mirror of
https://github.com/minescope/mineping.git
synced 2025-07-15 21:14:37 +03:00
Compare commits
29 Commits
72041aa3f9
...
v1.5.0
Author | SHA1 | Date | |
---|---|---|---|
838ffc497a
|
|||
502029869a
|
|||
e3e7e293ed
|
|||
88ad92e59d
|
|||
009f542c55
|
|||
0b0bed4e71
|
|||
fa4c34d896
|
|||
296294ca96
|
|||
9d25aaf4ea
|
|||
c735604c38
|
|||
afdaa9eb3e
|
|||
435899309f | |||
13e6b8c6ff | |||
d7256eabe7
|
|||
afa2c3025f
|
|||
6c297d0b8c
|
|||
283e9b32c6 | |||
354fa212a6 | |||
d9bf4cfb3f | |||
9dace3748b
|
|||
0aa73655b1
|
|||
78ca03b004
|
|||
910184bf5f
|
|||
915edbec9c
|
|||
0fe675385f
|
|||
c3158ac925 | |||
31c58ee637 | |||
7cd3444a4f | |||
af78a184db |
@ -1,6 +1,6 @@
|
||||
# mineping
|
||||
|
||||
`mineping` is a Javasript library thar provides Minecraft server ping protocol implementation. It can be used to collect information about the server, such as MODT, current online, server icon (java edition only) and etc.
|
||||
This JavaScript library provides an implementation of the Minecraft server ping protocol. **It allows you to gather information about a Minecraft server**, such as the MOTD, current online players, server icon (Java Edition only), and more.
|
||||
|
||||
Mirror on my [<img src="https://git.zeldon.ru/assets/img/logo.svg" align="center" width="20" height="20"/> Git](https://git.zeldon.ru/zeldon/mineping)
|
||||
|
||||
@ -10,6 +10,8 @@ Mirror on my [<img src="https://git.zeldon.ru/assets/img/logo.svg" align="center
|
||||
|
||||
## Install
|
||||
|
||||
To install `mineping`, simply run the following command:
|
||||
|
||||
```
|
||||
npm i @minescope/mineping
|
||||
```
|
||||
@ -17,6 +19,7 @@ npm i @minescope/mineping
|
||||
## Loading and configuration the module
|
||||
|
||||
### ES Modules (ESM)
|
||||
If you are using ES Modules, you can import the library like this:
|
||||
|
||||
```js
|
||||
import { pingJava, pingBedrock } from '@minescope/mineping';
|
||||
@ -59,5 +62,7 @@ console.log(data);
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Special thanks to the following projects:
|
||||
|
||||
- [mcping](https://github.com/Scetch/mcping) crate for Rust
|
||||
- [mcping-js](https://github.com/Cryptkeeper/mcping-js) library for quering Minecraft Java Edition servers
|
||||
|
@ -1,19 +1,15 @@
|
||||
/**
|
||||
* Usage examples:
|
||||
* - Java (with custom timeout): node cli.js -j --host="mc.hypixel.net" --timeout 1000
|
||||
* - Bedrock: node cli.js -b --host="play.timecrack.net"
|
||||
*/
|
||||
|
||||
import { pingBedrock, pingJava } from '../index.js';
|
||||
|
||||
const args = getArgs();
|
||||
|
||||
if (args.help || args.h || Object.keys(args).length === 0) {
|
||||
console.log(`node cli.js [..]
|
||||
A simple to use, efficient, and full-featured Minecraft server info parser!
|
||||
|
||||
USAGE:
|
||||
node cli.js [OPTIONS] --host <HOST> --port <PORT> --timeout <TIMEOUT>
|
||||
|
||||
OPTIONS:
|
||||
-j Use for Minecraft Java Edition
|
||||
-b Use for Minecraft Bedrock Edition
|
||||
P.S. Don't use them at the same time!`);
|
||||
|
||||
if (shouldShowHelp(args)) {
|
||||
printHelp();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@ -24,6 +20,42 @@ if (!args.host) {
|
||||
|
||||
// easter egg <3
|
||||
if (args.j && args.b) {
|
||||
printInterestingFacts();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const port = args.port || getDefaultPort(args);
|
||||
const timeout = args.timeout || 500;
|
||||
|
||||
if (args.j) {
|
||||
await pingJavaServer(args.host, port, timeout)
|
||||
.catch(err => console.error(`ERROR: ${err.message}`));
|
||||
} else if (args.b) {
|
||||
await pingBedrockServer(args.host, port, timeout)
|
||||
.catch(err => console.error(`ERROR: ${err.message}`));
|
||||
} else {
|
||||
console.error('ERROR: Unsupported flag passed. Use -h or --help.');
|
||||
}
|
||||
|
||||
function shouldShowHelp(args) {
|
||||
return args.help || args.h || Object.keys(args).length === 0;
|
||||
}
|
||||
|
||||
function printHelp() {
|
||||
console.log(`node cli.js [..]
|
||||
A simple to use, efficient, and full-featured Minecraft server info parser!
|
||||
|
||||
USAGE:
|
||||
node cli.js [OPTIONS] --host <HOST> --port <PORT> --timeout <TIMEOUT>
|
||||
|
||||
OPTIONS:
|
||||
-j Use for Minecraft Java Edition
|
||||
-b Use for Minecraft Bedrock Edition
|
||||
|
||||
P.S. Don't use them at the same time!`);
|
||||
}
|
||||
|
||||
function printInterestingFacts() {
|
||||
console.log(`Some interesting facts about MOTDs on bedrock:
|
||||
- so far they seem to exclusively use legacy color codes
|
||||
- the random style has a special impl for periods, they turn into animated
|
||||
@ -31,25 +63,20 @@ if (args.j && args.b) {
|
||||
- motd_2 is ignored? client displays "motd_1 - v{version}", where the
|
||||
appended version text is considered part of motd_1 for color code processing
|
||||
- motd_2 seems to mainly be used to return the server software in use (e.g. PocketMine-MP)`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (args.j) {
|
||||
const data = await pingJava(args.host, {
|
||||
port: args.port || 25565,
|
||||
timeout: args.timeout || 500
|
||||
});
|
||||
function getDefaultPort(args) {
|
||||
return args.j ? 25565 : 19132;
|
||||
}
|
||||
|
||||
console.log(`host: ${args.host}\nprotocol: ${data.version.protocol}\nonline: ${data.players.online}`);
|
||||
} else if (args.b) {
|
||||
const data = await pingBedrock(args.host, {
|
||||
port: args.port || 19132,
|
||||
timeout: args.timeout || 500
|
||||
});
|
||||
async function pingJavaServer(host, port, timeout) {
|
||||
const data = await pingJava(host, { port, timeout });
|
||||
console.log(`host: ${host}\nprotocol: ${data.version?.protocol}\nonline: ${data.players?.online}`);
|
||||
}
|
||||
|
||||
console.log(`host: ${args.host}\nprotocol: ${data.version.protocol}\nonline: ${data.players.online}`);
|
||||
} else {
|
||||
console.error('ERROR: Unsupported flag passed. Use -h or --help.');
|
||||
async function pingBedrockServer(host, port, timeout) {
|
||||
const data = await pingBedrock(host, { port, timeout });
|
||||
console.log(`host: ${host}\nprotocol: ${data.version.protocol}\nonline: ${data.players.online}`);
|
||||
}
|
||||
|
||||
// parsing command line arguments
|
||||
|
20
example/parallel.js
Normal file
20
example/parallel.js
Normal file
@ -0,0 +1,20 @@
|
||||
import { pingBedrock } from '../index.js';
|
||||
|
||||
const hosts = [
|
||||
'play.timecrack.net',
|
||||
'geo.hivebedrock.network',
|
||||
'oasys-pe.com',
|
||||
'play.galaxite.net',
|
||||
];
|
||||
|
||||
const pingPromises = hosts.map(host => pingBedrock(host));
|
||||
const results = await Promise.allSettled(pingPromises);
|
||||
|
||||
for (let result of results) {
|
||||
if (result.status === 'rejected') {
|
||||
console.error(result.reason);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(result.value);
|
||||
}
|
5
example/single.js
Normal file
5
example/single.js
Normal file
@ -0,0 +1,5 @@
|
||||
import { pingBedrock } from "../index.js";
|
||||
|
||||
const host = "mc.nevertime.su";
|
||||
const ping = await pingBedrock(host);
|
||||
console.log(ping);
|
155
lib/bedrock.js
155
lib/bedrock.js
@ -1,79 +1,71 @@
|
||||
/**
|
||||
* Implementation of the RakNet ping/pong protocol.
|
||||
* @see https://wiki.vg/Raknet_Protocol#Unconnected_Ping
|
||||
*
|
||||
* Data types:
|
||||
* @see https://wiki.vg/Raknet_Protocol#Data_types
|
||||
* @see https://wiki.vg/Raknet_Protocol
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import dgram from 'dgram';
|
||||
import ByteBuffer from 'bytebuffer';
|
||||
import dgram from 'node:dgram';
|
||||
import crypto from 'node:crypto'
|
||||
|
||||
const MAGIC = "00ffff00fefefefefdfdfdfd12345678";
|
||||
const START_TIME = new Date().getTime();
|
||||
|
||||
/**
|
||||
* Decode Unconnected Ping
|
||||
* Creates an Unconnected Ping packet.
|
||||
* @param {number} pingId
|
||||
* @returns {import('bytebuffer')}
|
||||
* @see https://wiki.vg/Raknet_Protocol#Unconnected_Ping
|
||||
* @returns {Buffer}
|
||||
* @see {@link https://wiki.vg/Raknet_Protocol#Unconnected_Ping}
|
||||
*/
|
||||
const UNCONNECTED_PING = (pingId) => {
|
||||
// 0x01
|
||||
const bb = new ByteBuffer();
|
||||
bb.buffer[0] = 0x01;
|
||||
bb.offset = 1;
|
||||
return bb.writeLong(pingId).append('00ffff00fefefefefdfdfdfd12345678', 'hex').writeLong(0).flip().compact();
|
||||
const createUnconnectedPingFrame = (timestamp) => {
|
||||
const buffer = Buffer.alloc(33);
|
||||
buffer.writeUInt8(0x01, 0); // Packet ID
|
||||
buffer.writeBigInt64LE(BigInt(timestamp), 1); // Timestamp
|
||||
Buffer.from(MAGIC, "hex").copy(buffer, 9); // OFFLINE_MESSAGE_DATA_ID (Magic)
|
||||
Buffer.from(crypto.randomBytes(8)).copy(buffer, 25); // Client GUID
|
||||
return buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode Unconnected Pong
|
||||
* @param {import('bytebuffer')} buffer
|
||||
* @see https://wiki.vg/Raknet_Protocol#Unconnected_Pong
|
||||
* Extract Modt from Unconnected Pong Packet and convert to an object
|
||||
* @param {Buffer} unconnectedPongPacket
|
||||
* @returns {Object}
|
||||
* @see {@link https://wiki.vg/Raknet_Protocol#Unconnected_Pong}
|
||||
*/
|
||||
const UNCONNECTED_PONG = (buffer) => {
|
||||
// 0x1c
|
||||
buffer.offset = 1;
|
||||
const pingId = buffer.readLong();
|
||||
const serverId = buffer.readLong();
|
||||
const offset = buffer.offset += 16;
|
||||
const nameLength = buffer.readShort();
|
||||
let advertiseStr;
|
||||
const extractModt = (unconnectedPongPacket) => {
|
||||
// Skip everything to Modt
|
||||
const offset = 33;
|
||||
const length = unconnectedPongPacket.readUInt16BE(offset);
|
||||
let modt = unconnectedPongPacket.toString("utf-8", offset + 2, offset + 2 + length);
|
||||
|
||||
try {
|
||||
advertiseStr = buffer.readUTF8String(nameLength);
|
||||
} catch (err) {
|
||||
advertiseStr = buffer.readUTF8String(parseInt(err.message.substr(err.message.indexOf(',') + 2, 3)));
|
||||
}
|
||||
|
||||
advertiseStr = advertiseStr.split(/;/g);
|
||||
const gameId = advertiseStr[0];
|
||||
const description = advertiseStr[1];
|
||||
const protocolVersion = advertiseStr[2];
|
||||
const gameVersion = advertiseStr[3];
|
||||
const currentPlayers = advertiseStr[4];
|
||||
const maxPlayers = advertiseStr[5];
|
||||
const name = advertiseStr[7];
|
||||
const mode = advertiseStr[8];
|
||||
|
||||
return {
|
||||
pingId,
|
||||
advertiseStr,
|
||||
serverId,
|
||||
offset,
|
||||
gameId,
|
||||
description,
|
||||
protocolVersion,
|
||||
gameVersion,
|
||||
currentPlayers,
|
||||
maxPlayers,
|
||||
name,
|
||||
mode
|
||||
const components = modt.split(';');
|
||||
const parsedComponents = {
|
||||
edition: components[0],
|
||||
name: components[1],
|
||||
version: {
|
||||
protocolVersion: Number(components[2]),
|
||||
minecraftVersion: components[3],
|
||||
},
|
||||
players: {
|
||||
online: Number(components[4]),
|
||||
max: Number(components[5])
|
||||
},
|
||||
serverId: components[6],
|
||||
mapName: components[7],
|
||||
gameMode: components[8]
|
||||
};
|
||||
|
||||
return parsedComponents;
|
||||
};
|
||||
|
||||
function ping(host, port = 19132, cb, timeout = 5000) {
|
||||
/**
|
||||
* Sends a ping request to the specified host and port.
|
||||
* @param {string} host - The IP address or hostname of the server.
|
||||
* @param {number} [port=19132] - The port number.
|
||||
* @param {function} cb - The callback function to handle the response.
|
||||
* @param {number} [timeout=5000] - The timeout duration in milliseconds.
|
||||
*/
|
||||
const ping = (host, port = 19132, cb, timeout = 5000) => {
|
||||
const socket = dgram.createSocket('udp4');
|
||||
|
||||
// Set manual timeout interval.
|
||||
@ -92,6 +84,10 @@ function ping(host, port = 19132, cb, timeout = 5000) {
|
||||
// This is mostly dangerous since it can swallow errors
|
||||
let didFireError = false;
|
||||
|
||||
/**
|
||||
* Handle any error that occurs during the ping process.
|
||||
* @param {Error} err The error that occurred.
|
||||
*/
|
||||
const handleError = (err) => {
|
||||
closeSocket();
|
||||
|
||||
@ -102,37 +98,20 @@ function ping(host, port = 19132, cb, timeout = 5000) {
|
||||
};
|
||||
|
||||
try {
|
||||
const ping = UNCONNECTED_PING(new Date().getTime() - START_TIME);
|
||||
socket.send(ping.buffer, 0, ping.buffer.length, port, host);
|
||||
const ping = createUnconnectedPingFrame(new Date().getTime() - START_TIME);
|
||||
socket.send(ping, 0, ping.length, port, host);
|
||||
} catch (err) {
|
||||
handleError(err);
|
||||
}
|
||||
|
||||
socket.on('message', (msg) => {
|
||||
const buffer = new ByteBuffer().append(msg, 'hex').flip();
|
||||
const id = buffer.buffer[0];
|
||||
socket.on('message', (pongPacket) => {
|
||||
const id = pongPacket[0];
|
||||
|
||||
switch (id) {
|
||||
// https://wiki.vg/Raknet_Protocol#Unconnected_Ping
|
||||
case 0x1c: {
|
||||
const pong = UNCONNECTED_PONG(buffer);
|
||||
const clientData = {
|
||||
version: {
|
||||
name: pong.name,
|
||||
protocol: pong.protocolVersion
|
||||
},
|
||||
players: {
|
||||
max: pong.maxPlayers,
|
||||
online: pong.currentPlayers
|
||||
},
|
||||
description: pong.description.replace(/\xA7[0-9A-FK-OR]/ig, ''),
|
||||
gamemode: pong.mode
|
||||
};
|
||||
|
||||
// Close the socket and clear the timeout task
|
||||
// This is a general cleanup for success conditions
|
||||
const modtObject = extractModt(pongPacket);
|
||||
closeSocket();
|
||||
cb(null, clientData);
|
||||
cb(modtObject, null);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -143,26 +122,24 @@ function ping(host, port = 19132, cb, timeout = 5000) {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('error', (err) => handleError(err));
|
||||
}
|
||||
socket.on('error', handleError);
|
||||
};
|
||||
|
||||
/**
|
||||
* Asynchronously ping Minecraft Bedrock server.
|
||||
*
|
||||
* The optional `options` argument can be an object with a `ping` (default is `19132`) or/and `timeout` (default is `5000`) property.
|
||||
*
|
||||
* @param {string} host The Bedrock server address.
|
||||
* @param {import('../types/index.js').PingOptions} options The configuration for pinging Minecraft Bedrock server.
|
||||
* @returns {Promise<import('../types/lib/bedrock.js').BedrockPingResponse>}
|
||||
* @returns {Promise<import('../types/index.js').BedrockPingResponse>}
|
||||
*/
|
||||
export function pingBedrock(host, options = {}) {
|
||||
export const pingBedrock = (host, options = {}) => {
|
||||
if (!host) throw new Error('Host argument is not provided');
|
||||
|
||||
const { port = 19132, timeout = 5000 } = options;
|
||||
|
||||
return new Promise((resilve, reject) => {
|
||||
ping(host, port, (err, res) => {
|
||||
err ? reject(err) : resilve(res);
|
||||
return new Promise((resolve, reject) => {
|
||||
ping(host, port, (res, err) => {
|
||||
err ? reject(err) : resolve(res);
|
||||
}, timeout);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
42
lib/java.js
42
lib/java.js
@ -5,12 +5,18 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import net from 'net';
|
||||
import net from 'node:net';
|
||||
import varint from './varint.js';
|
||||
|
||||
const PROTOCOL_VERSION = 0;
|
||||
|
||||
function ping(host, port = 25565, cb, timeout = 5000) {
|
||||
/**
|
||||
* Ping a Minecraft Java server.
|
||||
* @param {string} host The host of the Java server.
|
||||
* @param {number} [port=25565] The port of the Java server.
|
||||
* @param {function} cb The callback function to handle the ping response.
|
||||
* @param {number} [timeout=5000] The timeout duration in milliseconds.
|
||||
* @param {number} [protocolVersion=-1] The protocol version of the Java client.
|
||||
*/
|
||||
function ping(host, port = 25565, cb, timeout = 5000, protocolVersion = -1) {
|
||||
const socket = net.createConnection(({ host, port }));
|
||||
|
||||
// Set manual timeout interval.
|
||||
@ -29,6 +35,10 @@ function ping(host, port = 25565, cb, timeout = 5000) {
|
||||
// This is mostly dangerous since it can swallow errors
|
||||
let didFireError = false;
|
||||
|
||||
/**
|
||||
* Handle any error that occurs during the ping process.
|
||||
* @param {Error} err The error that occurred.
|
||||
*/
|
||||
const handleError = (err) => {
|
||||
closeSocket();
|
||||
|
||||
@ -45,7 +55,7 @@ function ping(host, port = 25565, cb, timeout = 5000) {
|
||||
socket.on('connect', () => {
|
||||
const handshake = varint.concat([
|
||||
varint.encodeInt(0),
|
||||
varint.encodeInt(PROTOCOL_VERSION),
|
||||
varint.encodeInt(protocolVersion),
|
||||
varint.encodeInt(host.length),
|
||||
varint.encodeString(host),
|
||||
varint.encodeUShort(port),
|
||||
@ -65,6 +75,7 @@ function ping(host, port = 25565, cb, timeout = 5000) {
|
||||
|
||||
socket.on('data', (data) => {
|
||||
incomingBuffer = Buffer.concat([incomingBuffer, data]);
|
||||
|
||||
// Wait until incomingBuffer is at least 5 bytes long to ensure it has captured the first VarInt value
|
||||
// This value is used to determine the full read length of the response
|
||||
// "VarInts are never longer than 5 bytes"
|
||||
@ -84,16 +95,15 @@ function ping(host, port = 25565, cb, timeout = 5000) {
|
||||
const packetId = varint.decodeInt(incomingBuffer, varint.decodeLength(packetLength));
|
||||
|
||||
if (packetId === 0) {
|
||||
const data = incomingBuffer.slice(varint.decodeLength(packetLength) + varint.decodeLength(packetId));
|
||||
const data = incomingBuffer.subarray(varint.decodeLength(packetLength) + varint.decodeLength(packetId));
|
||||
const responseLength = varint.decodeInt(data, 0);
|
||||
const response = data.slice(varint.decodeLength(responseLength), varint.decodeLength(responseLength) + responseLength);
|
||||
const response = data.subarray(varint.decodeLength(responseLength), varint.decodeLength(responseLength) + responseLength);
|
||||
|
||||
try {
|
||||
const message = JSON.parse(response);
|
||||
cb(null, message);
|
||||
|
||||
// Close the socket and clear the timeout task
|
||||
closeSocket();
|
||||
cb(message, null);
|
||||
} catch (err) {
|
||||
handleError(err);
|
||||
}
|
||||
@ -107,21 +117,19 @@ function ping(host, port = 25565, cb, timeout = 5000) {
|
||||
|
||||
/**
|
||||
* Asynchronously ping Minecraft Java server.
|
||||
*
|
||||
* The optional `options` argument can be an object with a `ping` (default is `25565`) or/and `timeout` (default is `5000`) property.
|
||||
*
|
||||
* The optional `options` argument can be an object with a `port` (default is `25565`) or/and `timeout` (default is `5000`) or/and `protocolVersion` (default is `-1`) property.
|
||||
* @param {string} host The Java server address.
|
||||
* @param {import('../types/index.js').PingOptions} options The configuration for pinging Minecraft Java server.
|
||||
* @returns {Promise<import('../types/lib/java.js').JavaPingResponse>}
|
||||
* @returns {Promise<import('../types/index.js').JavaPingResponse>}
|
||||
*/
|
||||
export function pingJava(host, options = {}) {
|
||||
if (!host) throw new Error('Host argument is not provided');
|
||||
|
||||
const { port = 25565, timeout = 5000 } = options;
|
||||
const { port = 25565, timeout = 5000, protocolVersion = -1 } = options;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
ping(host, port, (err, res) => {
|
||||
ping(host, port, (res, err) => {
|
||||
err ? reject(err) : resolve(res);
|
||||
}, timeout);
|
||||
}, timeout, protocolVersion);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,14 @@
|
||||
// https://wiki.vg/Data_types
|
||||
|
||||
/**
|
||||
* A utility object for encoding and decoding varints.
|
||||
*/
|
||||
const varint = {
|
||||
/**
|
||||
* Encodes an integer value into a varint byte buffer.
|
||||
* @param {number} val - The integer value to encode.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
encodeInt: (val) => {
|
||||
// "constInts are never longer than 5 bytes"
|
||||
// https://wiki.vg/Data_types#constInt_and_constLong
|
||||
@ -8,26 +16,43 @@ const varint = {
|
||||
let written = 0;
|
||||
|
||||
while (true) {
|
||||
if ((val & 0xFFFFFF80) === 0) {
|
||||
buf.writeUInt8(val, written++);
|
||||
const byte = val & 0x7F;
|
||||
val >>>= 7;
|
||||
|
||||
if (val === 0) {
|
||||
buf.writeUInt8(byte, written++);
|
||||
break;
|
||||
} else {
|
||||
buf.writeUInt8(val & 0x7F | 0x80, written++);
|
||||
val >>>= 7;
|
||||
}
|
||||
|
||||
buf.writeUInt8(byte | 0x80, written++);
|
||||
}
|
||||
|
||||
return buf.slice(0, written);
|
||||
},
|
||||
|
||||
/**
|
||||
* Encodes a string value into a UTF-8 byte buffer.
|
||||
* @param {string} val - The string value to encode.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
encodeString: (val) => {
|
||||
return Buffer.from(val, 'utf-8');
|
||||
},
|
||||
|
||||
/**
|
||||
* Encodes an unsigned short value into a byte buffer.
|
||||
* @param {number} val - The unsigned short value to encode.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
encodeUShort: (val) => {
|
||||
return Buffer.from([val >> 8, val & 0xFF]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Concatenates multiple byte buffers into a single byte buffer.
|
||||
* @param {Buffer[]} chunks - An array of byte buffers to concatenate.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
concat: (chunks) => {
|
||||
let length = 0;
|
||||
|
||||
@ -43,16 +68,22 @@ const varint = {
|
||||
return Buffer.concat(buffer);
|
||||
},
|
||||
|
||||
/**
|
||||
* Decodes a varint integer value from a byte buffer.
|
||||
* @param {Buffer} buffer - The byte buffer to decode from.
|
||||
* @param {number} offset - The offset in the buffer to start decoding from.
|
||||
* @returns {number}
|
||||
*/
|
||||
decodeInt: (buffer, offset) => {
|
||||
let val = 0;
|
||||
let count = 0;
|
||||
|
||||
while (true) {
|
||||
const b = buffer.readUInt8(offset++);
|
||||
const byte = buffer.readUInt8(offset++);
|
||||
|
||||
val |= (b & 0x7F) << count++ * 7;
|
||||
val |= (byte & 0x7F) << count++ * 7;
|
||||
|
||||
if ((b & 0x80) != 128) {
|
||||
if ((byte & 0x80) !== 0x80) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -60,8 +91,13 @@ const varint = {
|
||||
return val;
|
||||
},
|
||||
|
||||
// The number of bytes that the last .decodeInt() call had to use to decode.
|
||||
/**
|
||||
* Calculates the number of bytes required to decode a varint integer value.
|
||||
* @param {number} val - The varint integer value.
|
||||
* @returns {5 | 7 | 8 | 1 | 2 | 3 | 4 | 6 | 9 | 10}
|
||||
*/
|
||||
decodeLength: (val) => {
|
||||
// Constants representing the powers of 2 used for comparison
|
||||
const N1 = Math.pow(2, 7);
|
||||
const N2 = Math.pow(2, 14);
|
||||
const N3 = Math.pow(2, 21);
|
||||
@ -72,6 +108,7 @@ const varint = {
|
||||
const N8 = Math.pow(2, 56);
|
||||
const N9 = Math.pow(2, 63);
|
||||
|
||||
// Return the number of bytes required based on the value
|
||||
return (
|
||||
val < N1 ? 1
|
||||
: val < N2 ? 2
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@minescope/mineping",
|
||||
"version": "1.0.4",
|
||||
"version": "1.5.0",
|
||||
"description": "Ping both Minecraft Bedrock and Java servers.",
|
||||
"main": "index.js",
|
||||
"types": "types/index.d.ts",
|
||||
@ -18,8 +18,5 @@
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytebuffer": "^5.0.1"
|
||||
}
|
||||
"license": "MIT"
|
||||
}
|
4
types/index.d.ts
vendored
4
types/index.d.ts
vendored
@ -1,2 +1,2 @@
|
||||
export { pingJava } from "./lib/java.js";
|
||||
export { pingBedrock } from "./lib/bedrock.js";
|
||||
export * from "./lib/java.js";
|
||||
export * from "./lib/bedrock.js";
|
26
types/lib/bedrock.d.ts
vendored
26
types/lib/bedrock.d.ts
vendored
@ -2,22 +2,25 @@
|
||||
* @param port The server port.
|
||||
* @param timeout The read/write socket timeout.
|
||||
*/
|
||||
export type PingOptions = {
|
||||
port: number,
|
||||
timeout: number;
|
||||
export type BedrockPingOptions = {
|
||||
port?: number;
|
||||
timeout?: number;
|
||||
};
|
||||
|
||||
export type BedrockPingResponse = {
|
||||
edition: string;
|
||||
name: string;
|
||||
version: {
|
||||
name: string;
|
||||
protocol: string;
|
||||
protocolVersion: number;
|
||||
minecraftVersion: string;
|
||||
};
|
||||
players: {
|
||||
max: string;
|
||||
online: string;
|
||||
online: number;
|
||||
max: number;
|
||||
};
|
||||
description: string;
|
||||
gamemode: string;
|
||||
serverId: string;
|
||||
mapName: string;
|
||||
gameMode: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -26,6 +29,7 @@ export type BedrockPingResponse = {
|
||||
* The optional `options` argument can be an object with a `ping` (default is `19132`) or/and `timeout` (default is `5000`) property.
|
||||
*
|
||||
* @param host The Bedrock server address.
|
||||
* @param options The configuration for pinging Minecraft Bedrock server.
|
||||
*
|
||||
* ```js
|
||||
* import { pingBedrock } from '@minescope/mineping';
|
||||
@ -43,7 +47,7 @@ export type BedrockPingResponse = {
|
||||
* gamemode: 'Survival'
|
||||
* }
|
||||
* ```
|
||||
* @see [source](https://github.com/minescope/mineping/blob/24a48802300f988d3ae520edbeb4f3e12820dcc9/lib/java.js#L117)
|
||||
* @see [source](https://github.com/minescope/mineping/blob/915edbec9c9ad811459458600af3531ec0836911/lib/bedrock.js#L204)
|
||||
*/
|
||||
export function pingBedrock(host: string, options?: PingOptions): Promise<BedrockPingResponse>;
|
||||
export function pingBedrock(host: string, options?: BedrockPingOptions): Promise<BedrockPingResponse>;
|
||||
|
||||
|
38
types/lib/java.d.ts
vendored
38
types/lib/java.d.ts
vendored
@ -1,4 +1,28 @@
|
||||
import { PingOptions } from "./bedrock";
|
||||
/**
|
||||
* @param port The server port.
|
||||
* @param timeout The read/write socket timeout.
|
||||
* @param protocolVersion The protocol version.
|
||||
*/
|
||||
export type JavaPingOptions = {
|
||||
port?: number | undefined,
|
||||
timeout?: number | undefined,
|
||||
protocolVersion?: number | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* JSON format chat component used for description field.
|
||||
* @see https://wiki.vg/Chat
|
||||
*/
|
||||
export type ChatComponent = {
|
||||
text: string;
|
||||
bold?: boolean;
|
||||
italic?: boolean;
|
||||
underlined?: boolean;
|
||||
strikethrough?: boolean;
|
||||
obfuscated?: boolean;
|
||||
color?: string;
|
||||
extra?: ChatComponent[];
|
||||
};
|
||||
|
||||
export type SampleProp = {
|
||||
name: string,
|
||||
@ -17,10 +41,12 @@ export type JavaPingResponse = {
|
||||
players: {
|
||||
max: number;
|
||||
online: number;
|
||||
sample: SampleProp[];
|
||||
sample?: SampleProp[];
|
||||
};
|
||||
description: string;
|
||||
favicon: string;
|
||||
description: string | ChatComponent;
|
||||
favicon?: string;
|
||||
enforcesSecureChat?: boolean;
|
||||
previewsChat?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -48,7 +74,7 @@ export type JavaPingResponse = {
|
||||
* favicon: 'data:image/png;base64,iVBORw0KGg...
|
||||
}
|
||||
* ```
|
||||
* @see [source](https://github.com/minescope/mineping/blob/8c84925ef7f5c420a7ef52740cba027491e82934/lib/bedrock.js#L158)
|
||||
* @see [source](https://github.com/minescope/mineping/blob/915edbec9c9ad811459458600af3531ec0836911/lib/java.js#L117)
|
||||
*/
|
||||
export function pingJava(host: string, options?: PingOptions): Promise<JavaPingResponse>;
|
||||
export function pingJava(host: string, options?: JavaPingOptions): Promise<JavaPingResponse>;
|
||||
|
||||
|
15
yarn.lock
15
yarn.lock
@ -1,15 +0,0 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
bytebuffer@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-5.0.1.tgz#582eea4b1a873b6d020a48d58df85f0bba6cfddd"
|
||||
integrity sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=
|
||||
dependencies:
|
||||
long "~3"
|
||||
|
||||
long@~3:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b"
|
||||
integrity sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=
|
Reference in New Issue
Block a user