From b36c55e11237d025118b298a6c6062a1b92fecf3 Mon Sep 17 00:00:00 2001 From: b23r0 Date: Tue, 9 Aug 2022 15:39:27 +0800 Subject: [PATCH] Add new raknet library option (raknet-node) (#211) * add new raknet library option (raknet-node) * fix lint * fix lint & add new options * fix lint * fix user option & add rust-raknet test. * fix lint. * add raknet backend option. * remove useNativeRaknet option. * add not found log. * add test timeout size. * fix js raknet return error. * restore useNativeRaknet option. * update doc. * update options handling, back compat * fix server doc * Fix tests * fix tests. * fix lint. * delay timeout. * Update rak.js * update raknet-node version. * increase timeout. * Update vanilla.js * Update proxy.js * Update internal.js * update raknet-node version. * update rust-raknet version. * increase timeout test time * increase timeout test time * update backend version. * change timeout Co-authored-by: extremeheat --- docs/API.md | 7 ++++++- package.json | 5 +++-- src/client.js | 13 ++----------- src/createClient.js | 2 +- src/options.js | 21 ++++++++++++++++++--- src/rak.js | 21 +++++++++++---------- src/relay.js | 1 + src/server.js | 12 ++---------- test/proxy.js | 11 +++++++---- test/vanilla.js | 1 + 10 files changed, 52 insertions(+), 42 deletions(-) diff --git a/docs/API.md b/docs/API.md index 6955f91..8d0b545 100644 --- a/docs/API.md +++ b/docs/API.md @@ -19,7 +19,7 @@ Returns a `Client` instance and connects to the server. | autoInitPlayer | *optional* | default to true, If we should send SetPlayerInitialized to the server after getting play_status spawn. | | skipPing | *optional* | Whether pinging the server to check its version should be skipped. | | conLog | *optional* | Where to log connection information (server join, kick messages to). Defaults to console.log, set to `null` to not log anywhere. | -| useNativeRaknet | *optional* | Whether to use the C++ version of RakNet. Set to false to use JS. | +| raknetBackend | *optional* | Specifies the raknet implementation to use. Possible options are 'raknet-native' (default, original C++ implementation), 'jsp-raknet' (JS port), and 'raknet-node' (Rust port). Please note when using the non-JS implementation you may the need approporate build tools on your system (for example a C++ or Rust compiler). | | compressionLevel | *optional* | What zlib compression level to use, default to **7** | | batchingInterval | *optional* | How frequently, in milliseconds to flush and write the packet queue (default: 20ms) | | realms | *optional* | An object which should contain one of the following properties: `realmId`, `realmInvite`, `pickRealm`. When defined will attempt to join a Realm without needing to specify host/port. **The authenticated account must either own the Realm or have been invited to it** | @@ -27,6 +27,8 @@ Returns a `Client` instance and connects to the server. | realms.realmInvite | *optional* | The invite link/code of the Realm to join. | | realms.pickRealm | *optional* | A function which will have an array of the user Realms (joined/owned) passed to it. The function should return a Realm. | +*`useNativeRaknet` is deprecated. Setting to true will use 'raknet-native' for `raknetBackend` and setting it to false will use a JavaScript implemenation (jsp-raknet)* + The following special events are emitted by the client on top of protocol packets: * 'status' - When the client's login sequence status has changed * 'join' - When the client has joined the server after authenticating @@ -57,6 +59,9 @@ authenticated unless offline is set to true. | motd | *optional* | The "message of the day" for the server, the message shown to players in the server list. See usage below. | | advertisementFn | *optional* | optional. Custom function to call that should return a ServerAdvertisement, used for setting the RakNet server PONG data. Overrides `motd`. | | conLog | *optional* | Where to log connection information (server join, kick messages to). Default to log only in DEBUG mode. | +| raknetBackend | *optional* | Specifies the raknet implementation to use. Possible options are 'raknet-native' (default, original C++ implementation), 'jsp-raknet' (JS port), and 'raknet-node' (Rust port). Please note when using the non-JS implementation you may the need approporate build tools on your system (for example a C++ or Rust compiler). | + +*`useNativeRaknet` is deprecated. Setting to true will use 'raknet-native' for `raknetBackend` and setting it to false will use a JavaScript implemenation (jsp-raknet)* ## be.ping({ host, port }) : ServerAdvertisement diff --git a/package.json b/package.json index f4aaeb6..d29f497 100644 --- a/package.json +++ b/package.json @@ -29,10 +29,11 @@ "prismarine-nbt": "^2.0.0", "prismarine-realms": "^1.1.0", "protodef": "^1.14.0", - "uuid-1345": "^1.0.2", - "raknet-native": "^1.0.3" + "raknet-native": "^1.0.3", + "uuid-1345": "^1.0.2" }, "optionalDependencies": { + "raknet-node": "^0.4.6" }, "devDependencies": { "bedrock-protocol": "file:.", diff --git a/src/client.js b/src/client.js index 85f48df..7ec612b 100644 --- a/src/client.js +++ b/src/client.js @@ -43,7 +43,7 @@ class Client extends Connection { Login(this, null, this.options) LoginVerify(this, null, this.options) - const { RakClient } = initRaknet(this.options.useNativeRaknet) + const { RakClient } = initRaknet(this.options.raknetBackend) const host = this.options.host const port = this.options.port this.connection = new RakClient({ useWorkers: this.options.useRaknetWorkers, host, port }) @@ -67,16 +67,7 @@ class Client extends Connection { validateOptions () { if (!this.options.host || this.options.port == null) throw Error('Invalid host/port') - - if (!Options.Versions[this.options.version]) { - console.warn('Supported versions: ', Options.Versions) - throw Error(`Unsupported version ${this.options.version}`) - } - this.options.protocolVersion = Options.Versions[this.options.version] - if (this.options.protocolVersion < Options.MIN_VERSION) { - throw new Error(`Protocol version < ${Options.MIN_VERSION} : ${this.options.protocolVersion}, too old`) - } - this.compressionLevel = this.options.compressionLevel || 7 + Options.validateOptions(this.options) } get entityId () { diff --git a/src/createClient.js b/src/createClient.js index f48b1a3..a642c7c 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -1,5 +1,5 @@ const { Client } = require('./client') -const { RakClient } = require('./rak')(true) +const { RakClient } = require('./rak')('raknet-native') const { sleep } = require('./datatypes/util') const assert = require('assert') const Options = require('./options') diff --git a/src/options.js b/src/options.js index a4288fb..ae57abe 100644 --- a/src/options.js +++ b/src/options.js @@ -18,10 +18,25 @@ const defaultOptions = { offline: false, // Milliseconds to wait before aborting connection attempt connectTimeout: 9000, - // Whether or not to use C++ version of RakNet - useNativeRaknet: true, + // Specifies the raknet implementation to use + raknetBackend: 'raknet-native', // If using JS implementation of RakNet, should we use workers? (This only affects the client) useRaknetWorkers: true } -module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION, Versions } +function validateOptions (options) { + if (!Versions[options.version]) { + console.warn('Supported versions', Versions) + throw Error(`Unsupported version ${options.version}`) + } + + options.protocolVersion = Versions[options.version] + if (options.protocolVersion < MIN_VERSION) { + throw new Error(`Protocol version < ${MIN_VERSION} : ${options.protocolVersion}, too old`) + } + this.compressionLevel = options.compressionLevel || 7 + if (options.useNativeRaknet === true) options.raknetBackend = 'raknet-native' + if (options.useNativeRaknet === false) options.raknetBackend = 'jsp-raknet' +} + +module.exports = { defaultOptions, MIN_VERSION, CURRENT_VERSION, Versions, validateOptions } diff --git a/src/rak.js b/src/rak.js index 19f313c..7b1e2f1 100644 --- a/src/rak.js +++ b/src/rak.js @@ -3,21 +3,22 @@ const ConnWorker = require('./rakWorker') const { waitFor } = require('./datatypes/util') let Client, Server, PacketPriority, EncapsulatedPacket, PacketReliability, Reliability - class RakTimeout extends Error {}; -module.exports = nativeRaknet => { - if (nativeRaknet) { - try { - ({ Client, Server, PacketPriority, PacketReliability } = require('raknet-native')) - return { RakServer: RakNativeServer, RakClient: RakNativeClient, RakTimeout } - } catch (e) { +module.exports = (backend) => { + try { + if (backend === 'jsp-raknet') { ({ Client, Server, EncapsulatedPacket, Reliability } = require('jsp-raknet')) - console.debug('[raknet] native not found, using js', e) - console.debug('You can suppress the error above by disabling `useNativeRaknet` in your options') + return { RakServer: RakJsServer, RakClient: RakJsClient, RakTimeout } } - } else { + // We need to explicitly name the require()s for bundlers + if (backend === 'raknet-node') ({ Client, Server, PacketPriority, PacketReliability } = require('raknet-node')) + if (backend === 'raknet-native') ({ Client, Server, PacketPriority, PacketReliability } = require('raknet-native')) + else ({ Client, Server, PacketPriority, PacketReliability } = require(backend)) + return { RakServer: RakNativeServer, RakClient: RakNativeClient, RakTimeout } + } catch (e) { ({ Client, Server, EncapsulatedPacket, Reliability } = require('jsp-raknet')) + console.debug('[raknet] ' + backend + ' library not found, defaulting to jsp-raknet. Correct the "raknetBackend" option to avoid this error.', e) } return { RakServer: RakJsServer, RakClient: RakJsClient, RakTimeout } } diff --git a/src/relay.js b/src/relay.js index bcb1295..8f8ba1b 100644 --- a/src/relay.js +++ b/src/relay.js @@ -182,6 +182,7 @@ class Relay extends Server { port: this.options.destination.port, onMsaCode: this.options.onMsaCode, profilesFolder: this.options.profilesFolder, + backend: this.options.backend, autoInitPlayer: false } diff --git a/src/server.js b/src/server.js index 50f3ddf..ffa5d77 100644 --- a/src/server.js +++ b/src/server.js @@ -12,7 +12,7 @@ class Server extends EventEmitter { this.options = { ...Options.defaultOptions, ...options } this.validateOptions() - this.RakServer = require('./rak')(this.options.useNativeRaknet).RakServer + this.RakServer = require('./rak')(this.options.raknetBackend).RakServer this.serializer = createSerializer(this.options.version) this.deserializer = createDeserializer(this.options.version) @@ -25,15 +25,7 @@ class Server extends EventEmitter { } validateOptions () { - if (!Options.Versions[this.options.version]) { - console.warn('Supported versions', Options.Versions) - throw Error(`Unsupported version ${this.options.version}`) - } - this.options.protocolVersion = Options.Versions[this.options.version] - if (this.options.protocolVersion < Options.MIN_VERSION) { - throw new Error(`Protocol version < ${Options.MIN_VERSION} : ${this.options.protocolVersion}, too old`) - } - this.compressionLevel = this.options.compressionLevel || 7 + Options.validateOptions(this.options) } onOpenConnection = (conn) => { diff --git a/test/proxy.js b/test/proxy.js index 2d94e05..a69b93c 100644 --- a/test/proxy.js +++ b/test/proxy.js @@ -1,7 +1,8 @@ const { createClient, createServer, Relay } = require('bedrock-protocol') const { sleep, waitFor } = require('../src/datatypes/util') -function proxyTest (version, timeout = 1000 * 40) { +function proxyTest (version, raknetBackend = 'raknet-node', timeout = 1000 * 40) { + console.log('with raknet backend', raknetBackend) return waitFor(res => { const SERVER_PORT = 19000 + ((Math.random() * 100) | 0) const CLIENT_PORT = 19000 + ((Math.random() * 100) | 0) @@ -9,6 +10,7 @@ function proxyTest (version, timeout = 1000 * 40) { host: '0.0.0.0', // optional port: SERVER_PORT, // optional offline: true, + raknetBackend, version // The server version }) @@ -34,14 +36,15 @@ function proxyTest (version, timeout = 1000 * 40) { destination: { host: '127.0.0.1', port: SERVER_PORT - } + }, + raknetBackend }) relay.conLog = console.debug relay.listen() console.debug('Proxy started', server.options.version) - const client = createClient({ host: '127.0.0.1', port: CLIENT_PORT, version, username: 'Boat', offline: true }) + const client = createClient({ host: '127.0.0.1', port: CLIENT_PORT, version, username: 'Boat', offline: true, raknetBackend }) console.debug('Client started') @@ -59,7 +62,7 @@ function proxyTest (version, timeout = 1000 * 40) { } if (!module.parent) { - proxyTest('1.16.220') + proxyTest('1.16.220', 'raknet-native') } module.exports = { proxyTest } diff --git a/test/vanilla.js b/test/vanilla.js index ac1cdda..e67bdaa 100644 --- a/test/vanilla.js +++ b/test/vanilla.js @@ -15,6 +15,7 @@ async function test (version) { port: 19130, username: 'Notch', version, + raknetBackend: 'raknet-node', offline: true })