ddmaster 3.1.3 → 3.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -121
- package/lib/serverlist.js +1 -1
- package/package.json +2 -2
- package/index.js +0 -2
- package/src/bin.ts +0 -44
- package/src/index.ts +0 -19
- package/src/serverlist.ts +0 -132
- package/src/types.ts +0 -43
- package/tsconfig.json +0 -43
package/README.md
CHANGED
|
@@ -1,124 +1,77 @@
|
|
|
1
|
-
|
|
2
|
-
позже добавлю другие функции, сейчас пока что только получение сырой инфы и список серверов.
|
|
3
|
-
Пакет зделан чтобы проще работать с ДДНет серверами.
|
|
1
|
+
# ddmaster
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
Пакет для работы с ДДНет серверами.
|
|
4
|
+
Сделал я, 0374flop. MIT лицензия (./LICENSE)
|
|
6
5
|
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Установка
|
|
9
|
+
|
|
10
|
+
```
|
|
7
11
|
npm i ddmaster
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
"country": -1,
|
|
75
|
-
"score": -9999,
|
|
76
|
-
"is_player": true,
|
|
77
|
-
"skin": {
|
|
78
|
-
"name": "rongrongtu_pink"
|
|
79
|
-
},
|
|
80
|
-
"afk": false,
|
|
81
|
-
"team": 0
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
"name": "18687017299",
|
|
85
|
-
"clan": "糖糖教",
|
|
86
|
-
"country": -1,
|
|
87
|
-
"score": -9999,
|
|
88
|
-
"is_player": true,
|
|
89
|
-
"skin": {
|
|
90
|
-
"name": "Shadow Catsk"
|
|
91
|
-
},
|
|
92
|
-
"afk": true,
|
|
93
|
-
"team": 0
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
"name": "pbAdq",
|
|
97
|
-
"clan": "",
|
|
98
|
-
"country": -1,
|
|
99
|
-
"score": 2167,
|
|
100
|
-
"is_player": true,
|
|
101
|
-
"skin": {
|
|
102
|
-
"name": "maotouying"
|
|
103
|
-
},
|
|
104
|
-
"afk": false,
|
|
105
|
-
"team": 0
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
"name": "549120418",
|
|
109
|
-
"clan": "日月教",
|
|
110
|
-
"country": 156,
|
|
111
|
-
"score": -9999,
|
|
112
|
-
"is_player": true,
|
|
113
|
-
"skin": {
|
|
114
|
-
"name": "ghostjtj",
|
|
115
|
-
"color_body": 14810880,
|
|
116
|
-
"color_feet": 16776960
|
|
117
|
-
},
|
|
118
|
-
"afk": false,
|
|
119
|
-
"team": 0
|
|
120
|
-
}
|
|
121
|
-
]
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
]
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Импорт
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
const ddmaster = require('ddmaster'); // CommonJS
|
|
18
|
+
```
|
|
19
|
+
```ts
|
|
20
|
+
import * as ddmaster from 'ddmaster'; // ESM / TypeScript
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## API
|
|
26
|
+
|
|
27
|
+
**getrawDDNetServers()**
|
|
28
|
+
Возвращает сырую инфу с мастер сервера ДДНета. Структура ответа — `{ servers: DDNetServer[] }`.
|
|
29
|
+
|
|
30
|
+
**getDDNetServers(data?)**
|
|
31
|
+
Возвращает список серверов в виде `['ip:port']`.
|
|
32
|
+
`data` — опционально, сырая data от `getrawDDNetServers()`. Если не передана, сама получит.
|
|
33
|
+
|
|
34
|
+
**findDDNetPlayerByName(playerName, data?)**
|
|
35
|
+
Ищет игрока по имени (строгое сравнение через `===`) на всех серверах.
|
|
36
|
+
Возвращает массив серверов (та же структура что у `getrawDDNetServers`), но только те где есть этот игрок.
|
|
37
|
+
`data` — опционально, сырая data от `getrawDDNetServers()`.
|
|
38
|
+
|
|
39
|
+
**getinfoserver(address)**
|
|
40
|
+
Возвращает полную инфу об одном сервере по адресу `'ip:port'`. Или `undefined` если не найден.
|
|
41
|
+
|
|
42
|
+
**convertudptw(addr)**
|
|
43
|
+
Берёт адрес типа `"tw-0.6+udp://203.86.233.50:8352"` и возвращает просто `"203.86.233.50:8352"`.
|
|
44
|
+
Если адрес невалидный — возвращает `null`.
|
|
45
|
+
|
|
46
|
+
**filterbycommunity(servers, community)**
|
|
47
|
+
Фильтрует массив серверов по community (например `'ddnet'`).
|
|
48
|
+
|
|
49
|
+
**filterbylocation(servers, location)**
|
|
50
|
+
Фильтрует массив серверов по локации, точное совпадение (например `'eu:de'`).
|
|
51
|
+
|
|
52
|
+
**filterbylocationincludes(servers, location)**
|
|
53
|
+
То же самое но через includes (например `'eu'` найдёт `'eu:de'`, `'eu:pl'` и тд).
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Пример
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
const ddmaster = require('ddmaster');
|
|
61
|
+
|
|
62
|
+
// список всех серверов
|
|
63
|
+
const servers = await ddmaster.getDDNetServers();
|
|
64
|
+
console.log(servers); // ['ip:port', ...]
|
|
65
|
+
|
|
66
|
+
// найти игрока
|
|
67
|
+
const found = await ddmaster.findDDNetPlayerByName('имя игрока');
|
|
68
|
+
console.log(found); // массив серверов где есть игрок
|
|
69
|
+
|
|
70
|
+
// получить только европейские сервера
|
|
71
|
+
const raw = await ddmaster.getrawDDNetServers();
|
|
72
|
+
const eu = ddmaster.filterbylocationincludes(raw.servers, 'eu');
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
Позже добавлю ещё функции.
|
package/lib/serverlist.js
CHANGED
|
@@ -115,7 +115,7 @@ function filterbylocationincludes(servers, location) {
|
|
|
115
115
|
async function getinfoserver(address) {
|
|
116
116
|
const servers = await getrawDDNetServers();
|
|
117
117
|
const server = servers?.servers.find((server) => {
|
|
118
|
-
if (server.addresses)
|
|
118
|
+
if (!server.addresses || server.addresses.length === 0)
|
|
119
119
|
return false;
|
|
120
120
|
return convertudptw(server.addresses[0]) === address;
|
|
121
121
|
});
|
package/package.json
CHANGED
package/index.js
DELETED
package/src/bin.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const ddmaster = require('./index.js');
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const [command, ...args] = process.argv.slice(2);
|
|
7
|
-
|
|
8
|
-
if (command === "find") {
|
|
9
|
-
ddmaster.findDDNetPlayerByName(args.join(" ")).then(async (servers: import('./types').DDNetServer[]) => {
|
|
10
|
-
if (servers.length === 0) {
|
|
11
|
-
console.log("Player not found on any server.");
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
console.log(`Count of servers: ${servers.length}`);
|
|
16
|
-
console.log((await ddmaster.getDDNetServers(servers)).join("\n"));
|
|
17
|
-
}).catch((err: Error) => {
|
|
18
|
-
console.error('Error:', err);
|
|
19
|
-
});
|
|
20
|
-
} else if (command === "list") {
|
|
21
|
-
ddmaster.getDDNetServers().then((servers: string[]) => {
|
|
22
|
-
console.log(servers.join("\n"));
|
|
23
|
-
}).catch((err: Error) => {
|
|
24
|
-
console.error('Error:', err);
|
|
25
|
-
});
|
|
26
|
-
} else if (command === "raw") {
|
|
27
|
-
ddmaster.getrawDDNetServers().then((servers: import('./types').DDNetServer[]) => {
|
|
28
|
-
console.log(JSON.stringify(servers, null, 2));
|
|
29
|
-
}).catch((err: Error) => {
|
|
30
|
-
console.error('Error:', err);
|
|
31
|
-
});
|
|
32
|
-
} else if (command === "info") {
|
|
33
|
-
ddmaster.getinfoserver(args[0]).then((server: import('./types').DDNetServer) => {
|
|
34
|
-
console.log(JSON.stringify(server, null, 2));
|
|
35
|
-
}).catch((err: Error) => {
|
|
36
|
-
console.error('Error:', err);
|
|
37
|
-
});
|
|
38
|
-
} else {
|
|
39
|
-
console.log("Usage:");
|
|
40
|
-
console.log(" find <playerName> - Найти сервера с игроком");
|
|
41
|
-
console.log(" list - Получить список всех серверов");
|
|
42
|
-
console.log(" raw - Получить сырые данные серверов");
|
|
43
|
-
console.log(" info <address> - Получить информацию о сервере по адресу");
|
|
44
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ddmaster
|
|
3
|
-
*/
|
|
4
|
-
const lib = require('./serverlist.js');
|
|
5
|
-
|
|
6
|
-
module.exports = lib;
|
|
7
|
-
|
|
8
|
-
if (require.main === module) (async () =>{
|
|
9
|
-
console.log(
|
|
10
|
-
JSON.stringify(
|
|
11
|
-
await lib.getDDNetServers(
|
|
12
|
-
await lib.findDDNetPlayerByName('0374_bober')
|
|
13
|
-
),
|
|
14
|
-
null,
|
|
15
|
-
1
|
|
16
|
-
)
|
|
17
|
-
); // тестовый вызов
|
|
18
|
-
// console.log(await lib.getrawDDNetServers());
|
|
19
|
-
})();
|
package/src/serverlist.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
// 0374flop MIT
|
|
2
|
-
// npm i ddmaster
|
|
3
|
-
|
|
4
|
-
"use strict";
|
|
5
|
-
|
|
6
|
-
if (typeof fetch === 'undefined') {
|
|
7
|
-
try {
|
|
8
|
-
require.resolve('node-fetch');
|
|
9
|
-
} catch (e) {
|
|
10
|
-
throw new Error('Node.js <18, npm install node-fetch');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const nodeFetch = require('node-fetch');
|
|
14
|
-
global.fetch = nodeFetch.default || nodeFetch;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Делает запрос на мастер сервер ДДНета.
|
|
19
|
-
* @returns Сервера ДДНета но в сыром виде.
|
|
20
|
-
*/
|
|
21
|
-
async function getrawDDNetServers(): Promise<{ servers: import('./types').DDNetServer[] } | null> {
|
|
22
|
-
try {
|
|
23
|
-
const response = await fetch('https://master1.ddnet.org/ddnet/15/servers.json');
|
|
24
|
-
if (!response.ok) throw new Error(`Ошибка при запросе: ${response.status}`);
|
|
25
|
-
const data = await response.json();
|
|
26
|
-
return data;
|
|
27
|
-
} catch (error) {
|
|
28
|
-
console.error(error);
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
*
|
|
35
|
-
* @param {string} addr - берёт примерно такое "tw-0.7+udp://152.89.254.27:8310"
|
|
36
|
-
* @returns {string|null} 152.89.254.27:8310 возвращает чистый адрес (если addr не валидный то null)
|
|
37
|
-
*/
|
|
38
|
-
function convertudptw(addr: string) {
|
|
39
|
-
if (typeof addr !== 'string') return null;
|
|
40
|
-
const match = addr.match(/(\d{1,3}(\.\d{1,3}){3}:\d+)/);
|
|
41
|
-
return match ? match[1] : null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Делает запрос на мастер сервер ДДНета.
|
|
46
|
-
* @param {Object|null} data - опционально, сырая data от getrawDDNetServers(). Если не передана, функция сама её получит.
|
|
47
|
-
* @returns Сервера ДДНета если все пошло хорошо. ['ip:port']
|
|
48
|
-
*/
|
|
49
|
-
async function getDDNetServers(data = null) {
|
|
50
|
-
try {
|
|
51
|
-
const servers = data || (await getrawDDNetServers())?.servers;
|
|
52
|
-
if (!servers) {
|
|
53
|
-
return [];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const ipv4WithPorts: string[] = [];
|
|
57
|
-
|
|
58
|
-
for (const server of servers) {
|
|
59
|
-
server.addresses.forEach((addr: string) => {
|
|
60
|
-
const converted = convertudptw(addr);
|
|
61
|
-
if (converted == null) return;
|
|
62
|
-
ipv4WithPorts.push(converted);
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
return [...new Set(ipv4WithPorts)];
|
|
66
|
-
} catch (err) {
|
|
67
|
-
console.error(err);
|
|
68
|
-
return [];
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Ищет игрока по имени на всех серверах ДДНета.
|
|
74
|
-
* Возвращает ПОЛНУЮ инфу о серверах (как getrawDDNetServers),
|
|
75
|
-
* но только те сервера, где есть игрок с таким именем.
|
|
76
|
-
*
|
|
77
|
-
* @param {string} playerName - имя игрока, ищется строго через ===
|
|
78
|
-
* @param {Object|null} data - опционально, сырая data от getrawDDNetServers().
|
|
79
|
-
* @returns {Promise<Array>} Массив серверов (как в getrawDDNetServers().servers),
|
|
80
|
-
* на которых найден игрок.
|
|
81
|
-
*/
|
|
82
|
-
async function findDDNetPlayerByName(playerName: string, data = null) {
|
|
83
|
-
if (typeof playerName !== 'string') {
|
|
84
|
-
throw new TypeError('playerName должен быть строкой');
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
const raw = data || await getrawDDNetServers();
|
|
89
|
-
if (!raw || !Array.isArray(raw.servers)) {
|
|
90
|
-
return [];
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const resultServers = [];
|
|
94
|
-
|
|
95
|
-
for (const server of raw.servers) {
|
|
96
|
-
const info = server.info;
|
|
97
|
-
if (!info || !Array.isArray(info.clients)) continue;
|
|
98
|
-
|
|
99
|
-
const hasPlayer = info.clients.some((client: import('./types').ServerClient) => client.name === playerName);
|
|
100
|
-
if (hasPlayer) {
|
|
101
|
-
resultServers.push(server);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return resultServers;
|
|
105
|
-
} catch (err) {
|
|
106
|
-
console.error(err);
|
|
107
|
-
return [];
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function filterbycommunity(servers: import('./types').DDNetServer[], community: string) {
|
|
112
|
-
return servers.filter(server => server.community === community);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function filterbylocation(servers: import('./types').DDNetServer[], location: string) {
|
|
116
|
-
return servers.filter(server => server.location?.toLowerCase() === location?.toLowerCase());
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function filterbylocationincludes(servers: import('./types').DDNetServer[], location: string) {
|
|
120
|
-
return servers.filter(server => server.location?.toLowerCase().includes(location?.toLowerCase()));
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async function getinfoserver(address: string) {
|
|
124
|
-
const servers = await getrawDDNetServers();
|
|
125
|
-
const server = servers?.servers.find((server: import('./types').DDNetServer) => {
|
|
126
|
-
if (server.addresses) return false;
|
|
127
|
-
return convertudptw(server.addresses[0]) === address;
|
|
128
|
-
});
|
|
129
|
-
return server;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
module.exports = { getDDNetServers, getrawDDNetServers, convertudptw, findDDNetPlayerByName, filterbycommunity, filterbylocation, filterbylocationincludes, getinfoserver };
|
package/src/types.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export interface DDNetServer {
|
|
2
|
-
addresses: string[];
|
|
3
|
-
community: string;
|
|
4
|
-
location: string;
|
|
5
|
-
info: ServerInfo;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface ServerInfo {
|
|
9
|
-
max_clients: number;
|
|
10
|
-
max_players: number;
|
|
11
|
-
passworded: boolean;
|
|
12
|
-
game_type: string;
|
|
13
|
-
flag: number;
|
|
14
|
-
name: string;
|
|
15
|
-
map: ServerMap;
|
|
16
|
-
version: string;
|
|
17
|
-
client_score_kind: string;
|
|
18
|
-
requires_login: boolean;
|
|
19
|
-
clients: ServerClient[];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface ServerMap {
|
|
23
|
-
name: string;
|
|
24
|
-
sha256: string;
|
|
25
|
-
size: number;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface ServerClient {
|
|
29
|
-
name: string;
|
|
30
|
-
clan: string;
|
|
31
|
-
country: number;
|
|
32
|
-
score: number;
|
|
33
|
-
is_player: boolean;
|
|
34
|
-
skin: ClientSkin;
|
|
35
|
-
afk: boolean;
|
|
36
|
-
team: number;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface ClientSkin {
|
|
40
|
-
name: string;
|
|
41
|
-
color_body?: number;
|
|
42
|
-
color_feet?: number;
|
|
43
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
// Visit https://aka.ms/tsconfig to read more about this file
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
// File Layout
|
|
5
|
-
"rootDir": "./src",
|
|
6
|
-
"outDir": "./lib",
|
|
7
|
-
|
|
8
|
-
// Environment Settings
|
|
9
|
-
// See also https://aka.ms/tsconfig/module
|
|
10
|
-
"module": "nodenext",
|
|
11
|
-
"target": "esnext",
|
|
12
|
-
"types": ["node"],
|
|
13
|
-
// For nodejs:
|
|
14
|
-
// "lib": ["esnext"],
|
|
15
|
-
// "types": ["node"],
|
|
16
|
-
// and npm install -D @types/node
|
|
17
|
-
|
|
18
|
-
// Other Outputs
|
|
19
|
-
"sourceMap": false,
|
|
20
|
-
"declaration": true,
|
|
21
|
-
"declarationMap": false,
|
|
22
|
-
|
|
23
|
-
// Stricter Typechecking Options
|
|
24
|
-
"noUncheckedIndexedAccess": true,
|
|
25
|
-
"exactOptionalPropertyTypes": true,
|
|
26
|
-
|
|
27
|
-
// Style Options
|
|
28
|
-
// "noImplicitReturns": true,
|
|
29
|
-
// "noImplicitOverride": true,
|
|
30
|
-
// "noUnusedLocals": true,
|
|
31
|
-
// "noUnusedParameters": true,
|
|
32
|
-
// "noFallthroughCasesInSwitch": true,
|
|
33
|
-
// "noPropertyAccessFromIndexSignature": true,
|
|
34
|
-
|
|
35
|
-
// Recommended Options
|
|
36
|
-
"strict": true,
|
|
37
|
-
"verbatimModuleSyntax": true,
|
|
38
|
-
"isolatedModules": true,
|
|
39
|
-
"noUncheckedSideEffectImports": true,
|
|
40
|
-
"moduleDetection": "force",
|
|
41
|
-
"skipLibCheck": true,
|
|
42
|
-
}
|
|
43
|
-
}
|