Skip to content

Commit

Permalink
add pingLegacyUniversal to JavaPingClient
Browse files Browse the repository at this point in the history
  • Loading branch information
KurtThiemann committed Nov 7, 2024
1 parent 70fe4d9 commit f39bccf
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 3 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,18 @@ let response = await client.pingLegacyPost14('localhost', 25565, {signal: AbortS
let response = await client.pingLegacyPre14('localhost', 25565, {signal: AbortSignal.timeout(5000)});
```

Both legacy ping versions will return a [`LegacyStatus`](src/JavaPing/Status/LegacyStatus.js) object.
#### Ping a server that supports either of the two legacy ping versions
Some custom server software seems to not respond to pre 1.4 pings, but will instead only respond to 1.4+ pings.
The only currently known instance of this is Better Than Adventure. If you are trying to ping a server that may or
may not support pre 1.4 pings, you can use the following code:
```js
let response = await client.pingLegacyUniversal('localhost', 25565, {signal: AbortSignal.timeout(5000)});
```

Note that this weird hack involves sending the first half of a packet, then waiting for up to 500ms if the servers
responds, and if it does not, sending the second half of the packet. It may therefore run into problems if the timing is off.

All legacy ping versions will return a [`LegacyStatus`](src/JavaPing/Status/LegacyStatus.js) object.
Note that for pre 1.4 pings, this object will not include the server version name and protocol version,
as this information was not included in the response packets before Minecraft 1.4.

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "craftping",
"type": "module",
"version": "1.0.3",
"version": "1.1.0",
"main": "index.js",
"repository": "github:aternosorg/craftping",
"scripts": {
Expand Down
35 changes: 35 additions & 0 deletions src/JavaPing/JavaPing.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,41 @@ export default class JavaPing extends TCPSocket {
return new LegacyStatus().fromPre14String(response.getMessage());
}

/**
* @param {PingOptions} options
* @return {Promise<LegacyStatus>}
*/
async pingLegacyUniversal(options = {}) {
await this.write(Buffer.from([0xfe]));
this.signal?.throwIfAborted();

let usePost14 = false;
try {
await this.waitForData(1, AbortSignal.timeout(500));
} catch (e) {
usePost14 = true;
}
this.signal?.throwIfAborted();

if (usePost14) {
await this.write(Buffer.from([0x01]));
this.signal?.throwIfAborted();
await this.write(new LegacyPingHostPluginMessage()
.setProtocolVersion(options.protocolVersion ?? null)
.setHostname(options.hostname ?? this.address)
.setPort(options.port ?? this.port).write());
this.signal?.throwIfAborted();
}

let response = await this.readPacket(LegacyKick);
let message = response.getMessage();
if (message.startsWith("§1")) {
return new LegacyStatus().fromPost14String(response.getMessage());
} else {
return new LegacyStatus().fromPre14String(response.getMessage());
}
}

/**
* Read the next packet from the socket
*
Expand Down
26 changes: 26 additions & 0 deletions src/JavaPing/JavaPingClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,30 @@ export default class JavaPingClient {
await ping.close();
return response;
}

/**
* Send a weird hybrid ping that can be understood by both pre 1.4 servers, and custom servers that
* somehow only support the 1.4 - 1.6 protocol
*
* Note that, in some cases, this may result in pre 1.4 servers logging error messages.
*
* @param {string} address
* @param {number} port
* @param {PingOptions} options
* @return {Promise<LegacyStatus>}
*/
async pingLegacyUniversal(address, port, options = {}) {
[address, port] = await this.resolveSrv(address, port, options);
let ping = new JavaPing(address, port, options.signal);
await ping.connect();
let response;
try {
response = await ping.pingLegacyUniversal(options);
} catch (e) {
await ping.destroy();
throw e;
}
await ping.close();
return response;
}
}
11 changes: 10 additions & 1 deletion src/TCPSocket/TCPSocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,10 @@ export default class TCPSocket extends EventEmitter {

/**
* @param {number} length
* @param {?AbortSignal} signal
* @return {Promise<Buffer>}
*/
waitForData(length) {
waitForData(length, signal = null) {
if (this.waitForDataPromise !== null) {
throw new NetworkError("Already waiting for data");
}
Expand All @@ -163,6 +164,14 @@ export default class TCPSocket extends EventEmitter {
this.resolveDataPromise();
return promise.getPromise();
}

signal?.addEventListener("abort", () => {
if (this.waitForDataPromise === promise) {
this.waitForDataPromise = null;
promise.reject(new NetworkError("Operation was aborted"));
}
});

this.socket.resume();
return promise.getPromise();
}
Expand Down

0 comments on commit f39bccf

Please sign in to comment.