@deitylamb/mcping 1.4.2 → 1.5.1
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/dist/cli.cjs +5 -4
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +5 -4
- package/dist/index.d.cts +71 -0
- package/dist/index.d.mts +71 -0
- package/package.json +26 -16
- package/.prettierrc +0 -7
- package/src/ansi.ts +0 -50
- package/src/bedrock-ping.ts +0 -88
- package/src/cache.ts +0 -42
- package/src/chat.ts +0 -45
- package/src/cli.ts +0 -113
- package/src/index.ts +0 -143
- package/src/java-ping.ts +0 -114
- package/src/target.ts +0 -65
- package/src/varint.ts +0 -53
package/dist/cli.cjs
CHANGED
|
@@ -91,10 +91,11 @@ async function main() {
|
|
|
91
91
|
const resolvedStr = `${res.target.ip}:${res.target.port}`;
|
|
92
92
|
const targetDisplay = parsed.target === resolvedStr ? parsed.target : `${parsed.target} ${colors.gray}→${colors.reset} ${resolvedStr}`;
|
|
93
93
|
console.log(`\n ${colors.bright}${targetDisplay}${colors.reset}`);
|
|
94
|
-
const editionStr = `${colors.bright}${res.type.toUpperCase()}${colors.reset}`;
|
|
95
|
-
const versionStr = `${colors.
|
|
96
|
-
const
|
|
97
|
-
|
|
94
|
+
const editionStr = `${res.type === "java" ? colors.cyan : colors.green}${colors.bright}${res.type.toUpperCase()}${colors.reset}`;
|
|
95
|
+
const versionStr = `${colors.white}${res.version.name}${colors.reset}`;
|
|
96
|
+
const protocolStr = `${colors.gray}(${res.version.protocol})${colors.reset}`;
|
|
97
|
+
const latencyStr = ` ${colors.magenta}${res.latency}ms${colors.reset}`;
|
|
98
|
+
console.log(` ${editionStr} ${colors.gray}•${colors.reset} ${versionStr} ${protocolStr} ${colors.gray}•${colors.reset}${latencyStr}`);
|
|
98
99
|
console.log(` ${colors.bright}${res.players.online}${colors.reset} ${colors.gray}/ ${res.players.max} players${colors.reset}`);
|
|
99
100
|
const cleanMotd = mcToAnsi(res.motd).trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0).join(`\n `);
|
|
100
101
|
console.log(`\n ${cleanMotd}${colors.reset}\n`);
|
package/dist/cli.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.mjs
CHANGED
|
@@ -91,10 +91,11 @@ async function main() {
|
|
|
91
91
|
const resolvedStr = `${res.target.ip}:${res.target.port}`;
|
|
92
92
|
const targetDisplay = parsed.target === resolvedStr ? parsed.target : `${parsed.target} ${colors.gray}→${colors.reset} ${resolvedStr}`;
|
|
93
93
|
console.log(`\n ${colors.bright}${targetDisplay}${colors.reset}`);
|
|
94
|
-
const editionStr = `${colors.bright}${res.type.toUpperCase()}${colors.reset}`;
|
|
95
|
-
const versionStr = `${colors.
|
|
96
|
-
const
|
|
97
|
-
|
|
94
|
+
const editionStr = `${res.type === "java" ? colors.cyan : colors.green}${colors.bright}${res.type.toUpperCase()}${colors.reset}`;
|
|
95
|
+
const versionStr = `${colors.white}${res.version.name}${colors.reset}`;
|
|
96
|
+
const protocolStr = `${colors.gray}(${res.version.protocol})${colors.reset}`;
|
|
97
|
+
const latencyStr = ` ${colors.magenta}${res.latency}ms${colors.reset}`;
|
|
98
|
+
console.log(` ${editionStr} ${colors.gray}•${colors.reset} ${versionStr} ${protocolStr} ${colors.gray}•${colors.reset}${latencyStr}`);
|
|
98
99
|
console.log(` ${colors.bright}${res.players.online}${colors.reset} ${colors.gray}/ ${res.players.max} players${colors.reset}`);
|
|
99
100
|
const cleanMotd = mcToAnsi(res.motd).trim().split("\n").map((line) => line.trim()).filter((line) => line.length > 0).join(`\n `);
|
|
100
101
|
console.log(`\n ${cleanMotd}${colors.reset}\n`);
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
//#region src/java-ping.d.ts
|
|
2
|
+
interface JavaRawResponse {
|
|
3
|
+
version: {
|
|
4
|
+
name: string;
|
|
5
|
+
protocol: number;
|
|
6
|
+
};
|
|
7
|
+
players: {
|
|
8
|
+
max: number;
|
|
9
|
+
online: number;
|
|
10
|
+
sample?: {
|
|
11
|
+
name: string;
|
|
12
|
+
id: string;
|
|
13
|
+
}[];
|
|
14
|
+
};
|
|
15
|
+
description: any;
|
|
16
|
+
favicon?: string;
|
|
17
|
+
enforcesSecureChat?: boolean;
|
|
18
|
+
previewsChat?: boolean;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/bedrock-ping.d.ts
|
|
22
|
+
interface BedrockRawResponse {
|
|
23
|
+
edition: string;
|
|
24
|
+
motdLine1: string;
|
|
25
|
+
motdLine2: string;
|
|
26
|
+
protocolVersion: number;
|
|
27
|
+
versionName: string;
|
|
28
|
+
playerCount: number;
|
|
29
|
+
maxPlayerCount: number;
|
|
30
|
+
serverUniqueId: string;
|
|
31
|
+
gameMode: string;
|
|
32
|
+
nintendoLimited: number;
|
|
33
|
+
ipv4Port: number | null;
|
|
34
|
+
ipv6Port: number | null;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/cache.d.ts
|
|
38
|
+
interface CacheOptions {
|
|
39
|
+
ttl: number;
|
|
40
|
+
strategy: "lazy" | "swr";
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/index.d.ts
|
|
44
|
+
interface PingOptions {
|
|
45
|
+
timeout?: number;
|
|
46
|
+
type?: "java" | "bedrock" | null;
|
|
47
|
+
cache?: CacheOptions;
|
|
48
|
+
}
|
|
49
|
+
interface PingResponse {
|
|
50
|
+
type: "java" | "bedrock";
|
|
51
|
+
version: {
|
|
52
|
+
name: string;
|
|
53
|
+
protocol: number;
|
|
54
|
+
};
|
|
55
|
+
players: {
|
|
56
|
+
online: number;
|
|
57
|
+
max: number;
|
|
58
|
+
};
|
|
59
|
+
motd: string;
|
|
60
|
+
latency: number;
|
|
61
|
+
target: {
|
|
62
|
+
host: string;
|
|
63
|
+
port: number;
|
|
64
|
+
ip: string;
|
|
65
|
+
};
|
|
66
|
+
raw: JavaRawResponse | BedrockRawResponse;
|
|
67
|
+
cached?: boolean;
|
|
68
|
+
}
|
|
69
|
+
declare function ping(target: string, options?: PingOptions): Promise<PingResponse>;
|
|
70
|
+
//#endregion
|
|
71
|
+
export { PingOptions, PingResponse, ping };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
//#region src/java-ping.d.ts
|
|
2
|
+
interface JavaRawResponse {
|
|
3
|
+
version: {
|
|
4
|
+
name: string;
|
|
5
|
+
protocol: number;
|
|
6
|
+
};
|
|
7
|
+
players: {
|
|
8
|
+
max: number;
|
|
9
|
+
online: number;
|
|
10
|
+
sample?: {
|
|
11
|
+
name: string;
|
|
12
|
+
id: string;
|
|
13
|
+
}[];
|
|
14
|
+
};
|
|
15
|
+
description: any;
|
|
16
|
+
favicon?: string;
|
|
17
|
+
enforcesSecureChat?: boolean;
|
|
18
|
+
previewsChat?: boolean;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/bedrock-ping.d.ts
|
|
22
|
+
interface BedrockRawResponse {
|
|
23
|
+
edition: string;
|
|
24
|
+
motdLine1: string;
|
|
25
|
+
motdLine2: string;
|
|
26
|
+
protocolVersion: number;
|
|
27
|
+
versionName: string;
|
|
28
|
+
playerCount: number;
|
|
29
|
+
maxPlayerCount: number;
|
|
30
|
+
serverUniqueId: string;
|
|
31
|
+
gameMode: string;
|
|
32
|
+
nintendoLimited: number;
|
|
33
|
+
ipv4Port: number | null;
|
|
34
|
+
ipv6Port: number | null;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/cache.d.ts
|
|
38
|
+
interface CacheOptions {
|
|
39
|
+
ttl: number;
|
|
40
|
+
strategy: "lazy" | "swr";
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/index.d.ts
|
|
44
|
+
interface PingOptions {
|
|
45
|
+
timeout?: number;
|
|
46
|
+
type?: "java" | "bedrock" | null;
|
|
47
|
+
cache?: CacheOptions;
|
|
48
|
+
}
|
|
49
|
+
interface PingResponse {
|
|
50
|
+
type: "java" | "bedrock";
|
|
51
|
+
version: {
|
|
52
|
+
name: string;
|
|
53
|
+
protocol: number;
|
|
54
|
+
};
|
|
55
|
+
players: {
|
|
56
|
+
online: number;
|
|
57
|
+
max: number;
|
|
58
|
+
};
|
|
59
|
+
motd: string;
|
|
60
|
+
latency: number;
|
|
61
|
+
target: {
|
|
62
|
+
host: string;
|
|
63
|
+
port: number;
|
|
64
|
+
ip: string;
|
|
65
|
+
};
|
|
66
|
+
raw: JavaRawResponse | BedrockRawResponse;
|
|
67
|
+
cached?: boolean;
|
|
68
|
+
}
|
|
69
|
+
declare function ping(target: string, options?: PingOptions): Promise<PingResponse>;
|
|
70
|
+
//#endregion
|
|
71
|
+
export { PingOptions, PingResponse, ping };
|
package/package.json
CHANGED
|
@@ -1,25 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deitylamb/mcping",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Minecraft server ping library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.mjs",
|
|
8
|
-
"types": "./dist/index.d.
|
|
8
|
+
"types": "./dist/index.d.mts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"mcping": "./dist/cli.mjs"
|
|
11
|
+
},
|
|
9
12
|
"exports": {
|
|
10
13
|
".": {
|
|
11
14
|
"import": "./dist/index.mjs",
|
|
12
15
|
"require": "./dist/index.cjs",
|
|
13
|
-
"types": "./dist/index.d.
|
|
16
|
+
"types": "./dist/index.d.mts"
|
|
14
17
|
}
|
|
15
18
|
},
|
|
16
|
-
"
|
|
17
|
-
"
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=22"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/harmoniamc/mcping.git"
|
|
18
30
|
},
|
|
19
31
|
"scripts": {
|
|
20
32
|
"dev": "tsdown src/index.ts --watch",
|
|
21
|
-
"build": "tsdown src/index.ts src/cli.ts --format cjs
|
|
22
|
-
"test": "npm run test:unit && npm run test:e2e",
|
|
33
|
+
"build": "tsdown src/index.ts src/cli.ts --format esm,cjs --dts",
|
|
23
34
|
"test:unit": "vitest run test/unit",
|
|
24
35
|
"test:e2e": "vitest run test/e2e",
|
|
25
36
|
"format": "prettier --write .",
|
|
@@ -28,21 +39,20 @@
|
|
|
28
39
|
"keywords": [
|
|
29
40
|
"minecraft",
|
|
30
41
|
"ping",
|
|
42
|
+
"query",
|
|
31
43
|
"server",
|
|
32
44
|
"java",
|
|
33
45
|
"bedrock"
|
|
34
46
|
],
|
|
35
|
-
"author": "",
|
|
47
|
+
"author": "deitylamb",
|
|
36
48
|
"license": "MIT",
|
|
37
49
|
"devDependencies": {
|
|
38
|
-
"@
|
|
39
|
-
"
|
|
50
|
+
"@emnapi/core": "1.9.2",
|
|
51
|
+
"@emnapi/runtime": "1.9.2",
|
|
52
|
+
"@types/node": "^22.13.4",
|
|
53
|
+
"prettier": "^3.4.2",
|
|
40
54
|
"tsdown": "^0.21.7",
|
|
41
|
-
"typescript": "^
|
|
42
|
-
"vitest": "^
|
|
43
|
-
},
|
|
44
|
-
"dependencies": {
|
|
45
|
-
"@emnapi/core": "^1.9.2",
|
|
46
|
-
"@emnapi/runtime": "^1.9.2"
|
|
55
|
+
"typescript": "^5.7.3",
|
|
56
|
+
"vitest": "^3.0.5"
|
|
47
57
|
}
|
|
48
58
|
}
|
package/.prettierrc
DELETED
package/src/ansi.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
const mcColorMap: Record<string, string> = {
|
|
2
|
-
"0": "\x1b[30m", // black
|
|
3
|
-
"1": "\x1b[34m", // dark_blue
|
|
4
|
-
"2": "\x1b[32m", // dark_green
|
|
5
|
-
"3": "\x1b[36m", // dark_aqua
|
|
6
|
-
"4": "\x1b[31m", // dark_red
|
|
7
|
-
"5": "\x1b[35m", // dark_purple
|
|
8
|
-
"6": "\x1b[33m", // gold
|
|
9
|
-
"7": "\x1b[37m", // gray
|
|
10
|
-
"8": "\x1b[90m", // dark_gray
|
|
11
|
-
"9": "\x1b[94m", // blue
|
|
12
|
-
a: "\x1b[92m", // green
|
|
13
|
-
b: "\x1b[96m", // aqua
|
|
14
|
-
c: "\x1b[91m", // red
|
|
15
|
-
d: "\x1b[95m", // light_purple
|
|
16
|
-
e: "\x1b[93m", // yellow
|
|
17
|
-
f: "\x1b[97m", // white
|
|
18
|
-
l: "\x1b[1m", // bold
|
|
19
|
-
m: "\x1b[9m", // strikethrough
|
|
20
|
-
n: "\x1b[4m", // underline
|
|
21
|
-
o: "\x1b[3m", // italic
|
|
22
|
-
r: "\x1b[0m", // reset
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Converts Minecraft color codes (§) to ANSI terminal colors.
|
|
27
|
-
*/
|
|
28
|
-
export function mcToAnsi(text: string): string {
|
|
29
|
-
const reset = "\x1b[0m";
|
|
30
|
-
let result = "";
|
|
31
|
-
const parts = text.split("§");
|
|
32
|
-
|
|
33
|
-
result += parts[0];
|
|
34
|
-
|
|
35
|
-
for (let i = 1; i < parts.length; i++) {
|
|
36
|
-
const part = parts[i];
|
|
37
|
-
if (part.length === 0) continue;
|
|
38
|
-
|
|
39
|
-
const code = part[0].toLowerCase();
|
|
40
|
-
const ansi = mcColorMap[code];
|
|
41
|
-
|
|
42
|
-
if (ansi) {
|
|
43
|
-
result += ansi + part.substring(1);
|
|
44
|
-
} else {
|
|
45
|
-
result += "§" + part;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return result + reset;
|
|
50
|
-
}
|
package/src/bedrock-ping.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import * as dgram from "node:dgram";
|
|
2
|
-
import * as crypto from "node:crypto";
|
|
3
|
-
|
|
4
|
-
export interface BedrockRawResponse {
|
|
5
|
-
edition: string;
|
|
6
|
-
motdLine1: string;
|
|
7
|
-
motdLine2: string;
|
|
8
|
-
protocolVersion: number;
|
|
9
|
-
versionName: string;
|
|
10
|
-
playerCount: number;
|
|
11
|
-
maxPlayerCount: number;
|
|
12
|
-
serverUniqueId: string;
|
|
13
|
-
gameMode: string;
|
|
14
|
-
nintendoLimited: number;
|
|
15
|
-
ipv4Port: number | null;
|
|
16
|
-
ipv6Port: number | null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const RAKNET_MAGIC = Buffer.from("00ffff00fefefefefdfdfdfd12345678", "hex");
|
|
20
|
-
|
|
21
|
-
export async function pingBedrock(
|
|
22
|
-
host: string,
|
|
23
|
-
port: number,
|
|
24
|
-
timeout: number,
|
|
25
|
-
): Promise<BedrockRawResponse> {
|
|
26
|
-
return new Promise((resolve, reject) => {
|
|
27
|
-
const client = dgram.createSocket("udp4");
|
|
28
|
-
const timeoutHandler = setTimeout(() => {
|
|
29
|
-
client.close();
|
|
30
|
-
reject(new Error(`Bedrock ping timed out after ${timeout}ms`));
|
|
31
|
-
}, timeout);
|
|
32
|
-
|
|
33
|
-
const startTime = BigInt(Date.now());
|
|
34
|
-
const clientGUID = crypto.randomBytes(8);
|
|
35
|
-
|
|
36
|
-
// Unconnected Ping (0x01)
|
|
37
|
-
const packet = Buffer.alloc(1 + 8 + 16 + 8);
|
|
38
|
-
packet.writeUInt8(0x01, 0); // Packet ID
|
|
39
|
-
packet.writeBigInt64BE(startTime, 1); // Time
|
|
40
|
-
RAKNET_MAGIC.copy(packet, 9); // Magic
|
|
41
|
-
clientGUID.copy(packet, 25); // Client GUID
|
|
42
|
-
|
|
43
|
-
client.send(packet, port, host);
|
|
44
|
-
|
|
45
|
-
client.on("message", (msg) => {
|
|
46
|
-
if (msg.readUInt8(0) === 0x1c) {
|
|
47
|
-
// Unconnected Pong (0x1C)
|
|
48
|
-
clearTimeout(timeoutHandler);
|
|
49
|
-
client.close();
|
|
50
|
-
|
|
51
|
-
const time = msg.readBigInt64BE(1);
|
|
52
|
-
const serverGUID = msg.readBigInt64BE(9);
|
|
53
|
-
const magic = msg.slice(17, 33);
|
|
54
|
-
|
|
55
|
-
if (!magic.equals(RAKNET_MAGIC)) {
|
|
56
|
-
reject(new Error("Invalid RakNet magic"));
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const stringLength = msg.readUInt16BE(33);
|
|
61
|
-
const body = msg.toString("utf8", 35, 35 + stringLength);
|
|
62
|
-
|
|
63
|
-
const parts = body.split(";");
|
|
64
|
-
const response: BedrockRawResponse = {
|
|
65
|
-
edition: parts[0] || "MCPE",
|
|
66
|
-
motdLine1: parts[1] || "",
|
|
67
|
-
protocolVersion: parseInt(parts[2]) || 0,
|
|
68
|
-
versionName: parts[3] || "",
|
|
69
|
-
playerCount: parseInt(parts[4]) || 0,
|
|
70
|
-
maxPlayerCount: parseInt(parts[5]) || 0,
|
|
71
|
-
serverUniqueId: parts[6] || "",
|
|
72
|
-
motdLine2: parts[7] || "",
|
|
73
|
-
gameMode: parts[8] || "",
|
|
74
|
-
nintendoLimited: parseInt(parts[9]) || 0,
|
|
75
|
-
ipv4Port: parts[10] ? parseInt(parts[10]) : null,
|
|
76
|
-
ipv6Port: parts[11] ? parseInt(parts[11]) : null,
|
|
77
|
-
};
|
|
78
|
-
resolve(response);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
client.on("error", (err) => {
|
|
83
|
-
clearTimeout(timeoutHandler);
|
|
84
|
-
client.close();
|
|
85
|
-
reject(err);
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
}
|
package/src/cache.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { PingResponse } from "./index.js";
|
|
2
|
-
|
|
3
|
-
export interface CacheOptions {
|
|
4
|
-
ttl: number;
|
|
5
|
-
strategy: "lazy" | "swr";
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
interface CacheEntry {
|
|
9
|
-
response: PingResponse;
|
|
10
|
-
timestamp: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const cache = new Map<string, CacheEntry>();
|
|
14
|
-
|
|
15
|
-
export function getCache(
|
|
16
|
-
target: string,
|
|
17
|
-
options: CacheOptions,
|
|
18
|
-
): PingResponse | null {
|
|
19
|
-
const entry = cache.get(target);
|
|
20
|
-
if (!entry) return null;
|
|
21
|
-
|
|
22
|
-
const age = Date.now() - entry.timestamp;
|
|
23
|
-
const isExpired = age > options.ttl;
|
|
24
|
-
|
|
25
|
-
if (!isExpired || options.strategy === "swr") {
|
|
26
|
-
return { ...entry.response, cached: true };
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function setCache(target: string, response: PingResponse): void {
|
|
33
|
-
// Only cache successful, non-cached results
|
|
34
|
-
if (response.cached) return;
|
|
35
|
-
cache.set(target, { response, timestamp: Date.now() });
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function isExpired(target: string, options: CacheOptions): boolean {
|
|
39
|
-
const entry = cache.get(target);
|
|
40
|
-
if (!entry) return true;
|
|
41
|
-
return Date.now() - entry.timestamp > options.ttl;
|
|
42
|
-
}
|
package/src/chat.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
export function parseChat(chat: any): string {
|
|
2
|
-
if (typeof chat === "string") return chat;
|
|
3
|
-
if (!chat || typeof chat !== "object") return "";
|
|
4
|
-
|
|
5
|
-
let text = "";
|
|
6
|
-
|
|
7
|
-
// Minecraft legacy color code mapping in JSON
|
|
8
|
-
const colorMap: Record<string, string> = {
|
|
9
|
-
black: "0",
|
|
10
|
-
dark_blue: "1",
|
|
11
|
-
dark_green: "2",
|
|
12
|
-
dark_aqua: "3",
|
|
13
|
-
dark_red: "4",
|
|
14
|
-
dark_purple: "5",
|
|
15
|
-
gold: "6",
|
|
16
|
-
gray: "7",
|
|
17
|
-
dark_gray: "8",
|
|
18
|
-
blue: "9",
|
|
19
|
-
green: "a",
|
|
20
|
-
aqua: "b",
|
|
21
|
-
red: "c",
|
|
22
|
-
light_purple: "d",
|
|
23
|
-
yellow: "e",
|
|
24
|
-
white: "f",
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
if (chat.color && colorMap[chat.color]) {
|
|
28
|
-
text += `§${colorMap[chat.color]}`;
|
|
29
|
-
}
|
|
30
|
-
if (chat.bold) text += "§l";
|
|
31
|
-
if (chat.italic) text += "§o";
|
|
32
|
-
if (chat.underlined) text += "§n";
|
|
33
|
-
if (chat.strikethrough) text += "§m";
|
|
34
|
-
if (chat.obfuscated) text += "§k";
|
|
35
|
-
|
|
36
|
-
text += chat.text || "";
|
|
37
|
-
|
|
38
|
-
if (chat.extra && Array.isArray(chat.extra)) {
|
|
39
|
-
for (const part of chat.extra) {
|
|
40
|
-
text += parseChat(part);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return text;
|
|
45
|
-
}
|
package/src/cli.ts
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { ping } from "./index.js";
|
|
3
|
-
import { mcToAnsi } from "./ansi.js";
|
|
4
|
-
|
|
5
|
-
const colors = {
|
|
6
|
-
reset: "\x1b[0m",
|
|
7
|
-
bright: "\x1b[1m",
|
|
8
|
-
cyan: "\x1b[36m",
|
|
9
|
-
green: "\x1b[32m",
|
|
10
|
-
yellow: "\x1b[33m",
|
|
11
|
-
magenta: "\x1b[35m",
|
|
12
|
-
white: "\x1b[37m",
|
|
13
|
-
gray: "\x1b[90m",
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Poor man's argument parser
|
|
18
|
-
*/
|
|
19
|
-
function parseArgs(args: string[]) {
|
|
20
|
-
const result: {
|
|
21
|
-
target?: string;
|
|
22
|
-
type?: "java" | "bedrock";
|
|
23
|
-
timeout?: number;
|
|
24
|
-
} = {};
|
|
25
|
-
|
|
26
|
-
for (let i = 0; i < args.length; i++) {
|
|
27
|
-
const arg = args[i];
|
|
28
|
-
if (arg === "--type" || arg === "-t") {
|
|
29
|
-
const val = args[++i]?.toLowerCase();
|
|
30
|
-
if (val === "java" || val === "bedrock") {
|
|
31
|
-
result.type = val;
|
|
32
|
-
}
|
|
33
|
-
} else if (arg === "--timeout") {
|
|
34
|
-
const val = parseInt(args[++i]);
|
|
35
|
-
if (!isNaN(val)) {
|
|
36
|
-
result.timeout = val;
|
|
37
|
-
}
|
|
38
|
-
} else if (!result.target && !arg.startsWith("-")) {
|
|
39
|
-
result.target = arg;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return result;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async function main() {
|
|
46
|
-
const args = process.argv.slice(2);
|
|
47
|
-
const parsed = parseArgs(args);
|
|
48
|
-
|
|
49
|
-
if (!parsed.target) {
|
|
50
|
-
console.log(
|
|
51
|
-
`\n${colors.bright}Usage:${colors.reset} mcping <host[:port]> [options]`,
|
|
52
|
-
);
|
|
53
|
-
console.log(`\n${colors.bright}Options:${colors.reset}`);
|
|
54
|
-
console.log(` --type, -t <java|bedrock> Force protocol type`);
|
|
55
|
-
console.log(
|
|
56
|
-
` --timeout <ms> Connection timeout (default: 5000)`,
|
|
57
|
-
);
|
|
58
|
-
console.log(`\n${colors.bright}Examples:${colors.reset}`);
|
|
59
|
-
console.log(` mcping mc.hypixel.net`);
|
|
60
|
-
console.log(` mcping geo.hivebedrock.network --type bedrock`);
|
|
61
|
-
console.log(` mcping play.example.com --timeout 2000\n`);
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
const res = await ping(parsed.target, {
|
|
67
|
-
type: parsed.type,
|
|
68
|
-
timeout: parsed.timeout,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// Header Line: Input -> IP:Port
|
|
72
|
-
const resolvedStr = `${res.target.ip}:${res.target.port}`;
|
|
73
|
-
const targetDisplay =
|
|
74
|
-
parsed.target === resolvedStr
|
|
75
|
-
? parsed.target
|
|
76
|
-
: `${parsed.target} ${colors.gray}→${colors.reset} ${resolvedStr}`;
|
|
77
|
-
|
|
78
|
-
console.log(`\n ${colors.bright}${targetDisplay}${colors.reset}`);
|
|
79
|
-
|
|
80
|
-
// Edition line
|
|
81
|
-
const editionStr = `${colors.bright}${res.type.toUpperCase()}${colors.reset}`;
|
|
82
|
-
const versionStr = `${colors.gray}${res.version.name}${colors.reset}`;
|
|
83
|
-
const latencyStr =
|
|
84
|
-
res.type === "java"
|
|
85
|
-
? ` ${colors.magenta}${res.latency}ms${colors.reset}`
|
|
86
|
-
: "";
|
|
87
|
-
|
|
88
|
-
console.log(
|
|
89
|
-
` ${editionStr} ${colors.gray}•${colors.reset} ${versionStr}${latencyStr}`,
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
// Players line
|
|
93
|
-
console.log(
|
|
94
|
-
` ${colors.bright}${res.players.online}${colors.reset} ${colors.gray}/ ${res.players.max} players${colors.reset}`,
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
// MOTD with indent and colors
|
|
98
|
-
const coloredMotd = mcToAnsi(res.motd);
|
|
99
|
-
const cleanMotd = coloredMotd
|
|
100
|
-
.trim()
|
|
101
|
-
.split("\n")
|
|
102
|
-
.map((line) => line.trim())
|
|
103
|
-
.filter((line) => line.length > 0)
|
|
104
|
-
.join(`\n `);
|
|
105
|
-
|
|
106
|
-
console.log(`\n ${cleanMotd}${colors.reset}\n`);
|
|
107
|
-
} catch (err: any) {
|
|
108
|
-
console.error(`\n ${colors.yellow}Error:${colors.reset} ${err.message}\n`);
|
|
109
|
-
process.exit(1);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
main();
|
package/src/index.ts
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { resolveTarget } from "./target.js";
|
|
2
|
-
import { pingJava, JavaRawResponse } from "./java-ping.js";
|
|
3
|
-
import { pingBedrock, BedrockRawResponse } from "./bedrock-ping.js";
|
|
4
|
-
import { parseChat } from "./chat.js";
|
|
5
|
-
import * as cache from "./cache.js";
|
|
6
|
-
|
|
7
|
-
export interface PingOptions {
|
|
8
|
-
timeout?: number;
|
|
9
|
-
type?: "java" | "bedrock" | null;
|
|
10
|
-
cache?: cache.CacheOptions;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface PingResponse {
|
|
14
|
-
type: "java" | "bedrock";
|
|
15
|
-
version: {
|
|
16
|
-
name: string;
|
|
17
|
-
protocol: number;
|
|
18
|
-
};
|
|
19
|
-
players: {
|
|
20
|
-
online: number;
|
|
21
|
-
max: number;
|
|
22
|
-
};
|
|
23
|
-
motd: string;
|
|
24
|
-
latency: number;
|
|
25
|
-
target: {
|
|
26
|
-
host: string;
|
|
27
|
-
port: number;
|
|
28
|
-
ip: string;
|
|
29
|
-
};
|
|
30
|
-
raw: JavaRawResponse | BedrockRawResponse;
|
|
31
|
-
cached?: boolean;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export async function ping(
|
|
35
|
-
target: string,
|
|
36
|
-
options?: PingOptions,
|
|
37
|
-
): Promise<PingResponse> {
|
|
38
|
-
const timeout = options?.timeout || 5000;
|
|
39
|
-
const type = options?.type || null;
|
|
40
|
-
const cacheOptions = options?.cache;
|
|
41
|
-
|
|
42
|
-
if (cacheOptions) {
|
|
43
|
-
const cached = cache.getCache(target, cacheOptions);
|
|
44
|
-
if (cached) {
|
|
45
|
-
if (
|
|
46
|
-
cacheOptions.strategy === "swr" &&
|
|
47
|
-
cache.isExpired(target, cacheOptions)
|
|
48
|
-
) {
|
|
49
|
-
// Refresh in background
|
|
50
|
-
pingServer(target, timeout, type)
|
|
51
|
-
.then((refreshed) => cache.setCache(target, refreshed))
|
|
52
|
-
.catch(() => {});
|
|
53
|
-
}
|
|
54
|
-
return cached;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const result = await pingServer(target, timeout, type);
|
|
59
|
-
if (cacheOptions) {
|
|
60
|
-
cache.setCache(target, result);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return result;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async function pingServer(
|
|
67
|
-
target: string,
|
|
68
|
-
timeout: number,
|
|
69
|
-
type: "java" | "bedrock" | null,
|
|
70
|
-
): Promise<PingResponse> {
|
|
71
|
-
const resolved = await resolveTarget(target, type);
|
|
72
|
-
|
|
73
|
-
let javaError: any;
|
|
74
|
-
if (type === "java" || type === null) {
|
|
75
|
-
try {
|
|
76
|
-
const { response, latency } = await pingJava(
|
|
77
|
-
resolved.host,
|
|
78
|
-
resolved.port,
|
|
79
|
-
timeout,
|
|
80
|
-
);
|
|
81
|
-
return {
|
|
82
|
-
type: "java",
|
|
83
|
-
version: {
|
|
84
|
-
name: response.version.name,
|
|
85
|
-
protocol: response.version.protocol,
|
|
86
|
-
},
|
|
87
|
-
players: {
|
|
88
|
-
online: response.players.online,
|
|
89
|
-
max: response.players.max,
|
|
90
|
-
},
|
|
91
|
-
motd: parseChat(response.description),
|
|
92
|
-
latency,
|
|
93
|
-
target: {
|
|
94
|
-
host: resolved.host,
|
|
95
|
-
port: resolved.port,
|
|
96
|
-
ip: resolved.ip,
|
|
97
|
-
},
|
|
98
|
-
raw: response,
|
|
99
|
-
};
|
|
100
|
-
} catch (e) {
|
|
101
|
-
javaError = e;
|
|
102
|
-
if (type === "java") throw e;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
const bedrockResolved =
|
|
108
|
-
type === "bedrock" ? resolved : await resolveTarget(target, "bedrock");
|
|
109
|
-
const response = await pingBedrock(
|
|
110
|
-
bedrockResolved.host,
|
|
111
|
-
bedrockResolved.port,
|
|
112
|
-
timeout,
|
|
113
|
-
);
|
|
114
|
-
return {
|
|
115
|
-
type: "bedrock",
|
|
116
|
-
version: {
|
|
117
|
-
name: response.versionName,
|
|
118
|
-
protocol: response.protocolVersion,
|
|
119
|
-
},
|
|
120
|
-
players: {
|
|
121
|
-
online: response.playerCount,
|
|
122
|
-
max: response.maxPlayerCount,
|
|
123
|
-
},
|
|
124
|
-
motd: response.motdLine2
|
|
125
|
-
? `${response.motdLine1}\n${response.motdLine2}`
|
|
126
|
-
: response.motdLine1,
|
|
127
|
-
latency: 0,
|
|
128
|
-
target: {
|
|
129
|
-
host: bedrockResolved.host,
|
|
130
|
-
port: bedrockResolved.port,
|
|
131
|
-
ip: bedrockResolved.ip,
|
|
132
|
-
},
|
|
133
|
-
raw: response,
|
|
134
|
-
};
|
|
135
|
-
} catch (bedrockErr: any) {
|
|
136
|
-
if (type === null && javaError) {
|
|
137
|
-
throw new Error(
|
|
138
|
-
`Both Java and Bedrock pings failed. Java: ${javaError.message}. Bedrock: ${bedrockErr.message}`,
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
throw bedrockErr;
|
|
142
|
-
}
|
|
143
|
-
}
|
package/src/java-ping.ts
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import * as net from "node:net";
|
|
2
|
-
import {
|
|
3
|
-
encodeVarInt,
|
|
4
|
-
encodeString,
|
|
5
|
-
decodeVarInt,
|
|
6
|
-
decodeString,
|
|
7
|
-
} from "./varint.js";
|
|
8
|
-
|
|
9
|
-
export interface JavaRawResponse {
|
|
10
|
-
version: { name: string; protocol: number };
|
|
11
|
-
players: {
|
|
12
|
-
max: number;
|
|
13
|
-
online: number;
|
|
14
|
-
sample?: { name: string; id: string }[];
|
|
15
|
-
};
|
|
16
|
-
description: any;
|
|
17
|
-
favicon?: string;
|
|
18
|
-
enforcesSecureChat?: boolean;
|
|
19
|
-
previewsChat?: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export async function pingJava(
|
|
23
|
-
host: string,
|
|
24
|
-
port: number,
|
|
25
|
-
timeout: number,
|
|
26
|
-
): Promise<{ response: JavaRawResponse; latency: number }> {
|
|
27
|
-
return new Promise((resolve, reject) => {
|
|
28
|
-
const client = new net.Socket();
|
|
29
|
-
let startTime: number;
|
|
30
|
-
let response: JavaRawResponse;
|
|
31
|
-
|
|
32
|
-
const timeoutHandler = setTimeout(() => {
|
|
33
|
-
client.destroy();
|
|
34
|
-
reject(new Error(`Connection timed out after ${timeout}ms`));
|
|
35
|
-
}, timeout);
|
|
36
|
-
|
|
37
|
-
client.connect(port, host, () => {
|
|
38
|
-
// 1. Handshake
|
|
39
|
-
const protocolVersion = encodeVarInt(763); // 1.20.1
|
|
40
|
-
const serverAddress = encodeString(host);
|
|
41
|
-
const serverPort = Buffer.alloc(2);
|
|
42
|
-
serverPort.writeUInt16BE(port);
|
|
43
|
-
const nextState = encodeVarInt(1);
|
|
44
|
-
|
|
45
|
-
const handshakePayload = Buffer.concat([
|
|
46
|
-
protocolVersion,
|
|
47
|
-
serverAddress,
|
|
48
|
-
serverPort,
|
|
49
|
-
nextState,
|
|
50
|
-
]);
|
|
51
|
-
const packetIdBuffer = encodeVarInt(0);
|
|
52
|
-
const handshake = Buffer.concat([
|
|
53
|
-
encodeVarInt(handshakePayload.length + packetIdBuffer.length),
|
|
54
|
-
packetIdBuffer,
|
|
55
|
-
handshakePayload,
|
|
56
|
-
]);
|
|
57
|
-
|
|
58
|
-
client.write(handshake);
|
|
59
|
-
|
|
60
|
-
// 2. Status Request
|
|
61
|
-
const statusRequest = Buffer.concat([encodeVarInt(1), encodeVarInt(0)]);
|
|
62
|
-
client.write(statusRequest);
|
|
63
|
-
startTime = Date.now();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
let data = Buffer.alloc(0);
|
|
67
|
-
client.on("data", (chunk: Buffer) => {
|
|
68
|
-
data = Buffer.concat([data, chunk]);
|
|
69
|
-
|
|
70
|
-
while (data.length > 0) {
|
|
71
|
-
try {
|
|
72
|
-
// Read packet length
|
|
73
|
-
const { value: packetLen, length: varIntLen } = decodeVarInt(data, 0);
|
|
74
|
-
if (data.length < packetLen + varIntLen) return; // Wait for more data
|
|
75
|
-
|
|
76
|
-
const packet = data.subarray(varIntLen, varIntLen + packetLen);
|
|
77
|
-
data = data.subarray(varIntLen + packetLen); // Consume packet
|
|
78
|
-
|
|
79
|
-
// Read packet ID
|
|
80
|
-
const { value: packetId, length: idLen } = decodeVarInt(packet, 0);
|
|
81
|
-
|
|
82
|
-
if (packetId === 0) {
|
|
83
|
-
const { value: jsonStr } = decodeString(packet, idLen);
|
|
84
|
-
response = JSON.parse(jsonStr);
|
|
85
|
-
|
|
86
|
-
// 3. Ping
|
|
87
|
-
const pingPayload = Buffer.alloc(8);
|
|
88
|
-
pingPayload.writeBigInt64BE(BigInt(startTime));
|
|
89
|
-
const pingPacket = Buffer.concat([
|
|
90
|
-
encodeVarInt(9),
|
|
91
|
-
encodeVarInt(1),
|
|
92
|
-
pingPayload,
|
|
93
|
-
]);
|
|
94
|
-
client.write(pingPacket);
|
|
95
|
-
} else if (packetId === 1) {
|
|
96
|
-
const latency = Date.now() - startTime;
|
|
97
|
-
clearTimeout(timeoutHandler);
|
|
98
|
-
client.destroy();
|
|
99
|
-
resolve({ response, latency });
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
} catch (e) {
|
|
103
|
-
// Return if we can't decode yet
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
client.on("error", (err) => {
|
|
110
|
-
clearTimeout(timeoutHandler);
|
|
111
|
-
reject(err);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
}
|
package/src/target.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import * as dns from "node:dns/promises";
|
|
2
|
-
|
|
3
|
-
export interface Target {
|
|
4
|
-
host: string;
|
|
5
|
-
port: number;
|
|
6
|
-
protocol: "java" | "bedrock";
|
|
7
|
-
ip: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Resolves host and port, handling SRV records and lookups.
|
|
12
|
-
*/
|
|
13
|
-
export async function resolveTarget(
|
|
14
|
-
targetStr: string,
|
|
15
|
-
type: "java" | "bedrock" | null,
|
|
16
|
-
): Promise<Target> {
|
|
17
|
-
let host = targetStr;
|
|
18
|
-
let port = type === "bedrock" ? 19132 : 25565;
|
|
19
|
-
const parts = targetStr.split(":");
|
|
20
|
-
|
|
21
|
-
if (parts.length === 2 && !isNaN(parseInt(parts[1]))) {
|
|
22
|
-
host = parts[0];
|
|
23
|
-
port = parseInt(parts[1]);
|
|
24
|
-
const ip = await resolveIp(host);
|
|
25
|
-
return { host, port, protocol: type === null ? "java" : type, ip };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Attempt SRV resolution
|
|
29
|
-
if (type !== "bedrock") {
|
|
30
|
-
try {
|
|
31
|
-
const srv = await dns.resolveSrv(`_minecraft._tcp.${host}`);
|
|
32
|
-
if (srv && srv.length > 0) {
|
|
33
|
-
const srvHost = srv[0].name;
|
|
34
|
-
const srvPort = srv[0].port;
|
|
35
|
-
const ip = await resolveIp(srvHost);
|
|
36
|
-
return { host: srvHost, port: srvPort, protocol: "java", ip };
|
|
37
|
-
}
|
|
38
|
-
} catch (e) {}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (type === "bedrock" && parts.length === 1) {
|
|
42
|
-
try {
|
|
43
|
-
const srv = await dns.resolveSrv(`_minecraft._udp.${host}`);
|
|
44
|
-
if (srv && srv.length > 0) {
|
|
45
|
-
const srvHost = srv[0].name;
|
|
46
|
-
const srvPort = srv[0].port;
|
|
47
|
-
const ip = await resolveIp(srvHost);
|
|
48
|
-
return { host: srvHost, port: srvPort, protocol: "bedrock", ip };
|
|
49
|
-
}
|
|
50
|
-
} catch (e) {}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const ip = await resolveIp(host);
|
|
54
|
-
return { host, port, protocol: type || "java", ip };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async function resolveIp(host: string): Promise<string> {
|
|
58
|
-
try {
|
|
59
|
-
const addresses = await dns.lookup(host);
|
|
60
|
-
return addresses.address;
|
|
61
|
-
} catch (e) {
|
|
62
|
-
// If lookup fails, return the host itself as a fallback
|
|
63
|
-
return host;
|
|
64
|
-
}
|
|
65
|
-
}
|
package/src/varint.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* VarInt encoding and decoding for Minecraft protocol.
|
|
3
|
-
* Based on the specification at https://wiki.vg/Protocol#VarInt_and_VarLong
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export function encodeVarInt(value: number): Buffer {
|
|
7
|
-
const bytes: number[] = [];
|
|
8
|
-
let temp = value >>> 0;
|
|
9
|
-
|
|
10
|
-
while (temp >= 0x80) {
|
|
11
|
-
bytes.push((temp & 0x7f) | 0x80);
|
|
12
|
-
temp >>>= 7;
|
|
13
|
-
}
|
|
14
|
-
bytes.push(temp);
|
|
15
|
-
return Buffer.from(bytes);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function decodeVarInt(
|
|
19
|
-
buffer: Buffer,
|
|
20
|
-
offset = 0,
|
|
21
|
-
): { value: number; length: number } {
|
|
22
|
-
let value = 0;
|
|
23
|
-
let length = 0;
|
|
24
|
-
let currentByte: number;
|
|
25
|
-
|
|
26
|
-
while (true) {
|
|
27
|
-
currentByte = buffer.readUInt8(offset + length);
|
|
28
|
-
value |= (currentByte & 0x7f) << (length * 7);
|
|
29
|
-
length++;
|
|
30
|
-
if (length > 5) throw new Error("VarInt is too big");
|
|
31
|
-
if ((currentByte & 0x80) !== 0x80) break;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return { value: value | 0, length };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function encodeString(str: string): Buffer {
|
|
38
|
-
const content = Buffer.from(str, "utf8");
|
|
39
|
-
return Buffer.concat([encodeVarInt(content.length), content]);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function decodeString(
|
|
43
|
-
buffer: Buffer,
|
|
44
|
-
offset = 0,
|
|
45
|
-
): { value: string; length: number } {
|
|
46
|
-
const { value: strLen, length: varIntLen } = decodeVarInt(buffer, offset);
|
|
47
|
-
const value = buffer.toString(
|
|
48
|
-
"utf8",
|
|
49
|
-
offset + varIntLen,
|
|
50
|
-
offset + varIntLen + strLen,
|
|
51
|
-
);
|
|
52
|
-
return { value, length: varIntLen + strLen };
|
|
53
|
-
}
|