From 2ce6ee56890c6db63839eecdc473afbb2633e640 Mon Sep 17 00:00:00 2001 From: bonanoo Date: Wed, 25 Dec 2024 18:32:01 +0200 Subject: [PATCH] Fixed :D --- .gitignore | 4 ++- README.md | 15 ++++++-- package.json | 5 +-- src/Client.ts | 37 ++++++++++--------- src/Connection.ts | 39 +++++++++++++++----- src/client/ClientOptions.ts | 6 ++++ src/client/Listener.ts | 48 +++++-------------------- src/tools/connect.ts | 12 ------- src/vendor/PacketSorter.ts | 30 ++++++++-------- src/vendor/debug-tools.ts | 3 ++ src/vendor/packets/player-auth-input.ts | 1 + 11 files changed, 102 insertions(+), 98 deletions(-) diff --git a/.gitignore b/.gitignore index df1396a..df2fc1e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules/ dist/ package-lock.json +cache/ tokens/ .vscode/ dev/ @@ -12,4 +13,5 @@ src/tools/level src/history/ note.txt bun.lockb -src/tools/z.ts \ No newline at end of file +src/tools/z.ts +src/tools/rat.ts \ No newline at end of file diff --git a/README.md b/README.md index 817eff0..5185810 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ npm i @sanctumterra/client | 2.0.10 | 712 | 1.21.20 | | 2.1.5 | 729 | 1.21.30 | | 2.1.12 | 748 | 1.21.40 | -| 2.1.13 | 766 | 1.21.50 | +| 2.1.16 | 766 | 1.21.50 | ## 🚀 Usage Example @@ -44,7 +44,10 @@ const client = new Client({ username: "SanctumTerra", tokensFolder: "./cache/tokens", version: "1.21.50", - deviceOS: DeviceOS.Android + deviceOS: DeviceOS.Android, + sendAuthInput: true, + logPacketErrors: false, + tickRate: 50 // 50 is the default tick rate }); client.connect(); @@ -76,7 +79,8 @@ client.on("spawn", () => { ### 🎛️ Client Configuration - **Required Parameters**: `host`, `port` -- **Optional Parameters**: `offline`, `username`, `tokensFolder`, `version`, `deviceOS`, `viewDistance` +- **Optional Parameters**: +`offline`, `username`, `tokensFolder`, `version`, `deviceOS`, `viewDistance`, `sendAuthInput`, `logPacketErrors`, `tickRate` ### 📡 Event Handling - Events allow you to listen to any implemented packet if it is not implemented you will receive a warning and it should not crash if there is a crash then make an issue on github. @@ -88,6 +92,11 @@ client.on("spawn", () => { ## 📜 Changelog +### 2.1.16 +- Fixed bugs with BDS. +- Added more options. +- New Listener Events. + ### 2.1.14 - Use latest version of Raknet - Fixes diff --git a/package.json b/package.json index facce34..1760eee 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "@sanctumterra/client", - "version": "2.1.15", + "version": "2.1.16", "minecraft": "1.21.50", - "description": "We'll be singing Baraye.", + "description": "MCBE Client", "main": "./dist/index.js", "type": "commonjs", "scripts": { @@ -38,6 +38,7 @@ "@sanctumterra/raknet": "^1.3.67", "@serenityjs/binarystream": "^2.6.6", "@serenityjs/block": "^0.4.4", + "@serenityjs/emitter": "^0.6.4", "@serenityjs/network": "^0.4.4", "@serenityjs/protocol": "^0.6.4-beta-20241210051348", "@serenityjs/raknet": "^0.6.2-beta-20241128210118", diff --git a/src/Client.ts b/src/Client.ts index 3ca585b..6666bba 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -25,11 +25,7 @@ import { AnimateId, ComplexInventoryTransaction, BlockPosition, - ItemStackRequestPacket, - ItemStackRequestActionType, - ItemStackRequest, - ItemStackRequestAction, - ItemStackActionTakePlace, + type DisconnectPacket, } from "@serenityjs/protocol"; import { Priority } from "@serenityjs/raknet"; import type { ClientOptions } from "./client/ClientOptions"; @@ -58,6 +54,8 @@ class Client extends Connection { private isBreaking = false; private requestId = -2; + private _authInputInterval!: NodeJS.Timeout; + constructor(options: Partial = {}) { super(options); this.inventory = new Inventory(this); @@ -79,8 +77,19 @@ class Client extends Connection { } } + public disconnect( + clientSide?: boolean, + packet?: DisconnectPacket | null, + ): void { + clearInterval(this._authInputInterval); + super.disconnect(clientSide, packet); + } + private handleAuthInput(): void { - setInterval(() => { + this._authInputInterval = setInterval(() => { + // So people can switch it live. + if (!this.options.sendAuthInput) return; + const inputData = new PlayerAuthInputData(0n); inputData.setFlag(InputData.BlockBreakingDelayEnabled, true); if (this.sneaking) { @@ -110,12 +119,9 @@ class Client extends Connection { packet.analogueMotion = new Vector2f(0, 0); packet.cameraOrientation = new Vector3f(0, 0, 0); packet.rawMoveVector = new Vector2f(0, 0); - const cancel = false; - this.emit("PrePlayerAuthInputPacket", packet, cancel); - if (!cancel) { - this.sendPacket(packet, Priority.Immediate); - } - }, 50); + this.emit("PrePlayerAuthInputPacket", packet); + this.sendPacket(packet, Priority.Normal); + }, 100); } public sendMessage(text: string): void { @@ -243,12 +249,9 @@ class Client extends Connection { modifier: (packet: CustomPlayerAuthInputPacket) => void, ): Promise => { return new Promise((resolve) => { - const handler = ( - packet: ProtocolPlayerAuthInputPacket, - cancel: boolean, - ) => { + const handler = (packet: ProtocolPlayerAuthInputPacket) => { modifier(packet as unknown as CustomPlayerAuthInputPacket); - this.removeListener("PrePlayerAuthInputPacket", handler); + this.remove("PrePlayerAuthInputPacket", handler); resolve(); }; this.on("PrePlayerAuthInputPacket", handler); diff --git a/src/Connection.ts b/src/Connection.ts index 217ce54..9c26c8a 100644 --- a/src/Connection.ts +++ b/src/Connection.ts @@ -22,6 +22,8 @@ import { ResourcePackResponse, type ResourcePacksInfoPacket, ResourcePackStackPacket, + ServerboundLoadingScreenPacketPacket, + ServerboundLoadingScreenType, type ServerToClientHandshakePacket, SetLocalPlayerAsInitializedPacket, type StartGamePacket, @@ -96,6 +98,7 @@ class Connection extends Listener { public disconnect(clientSide = true, packet: DisconnectPacket | null = null) { const reason = packet?.message?.message ?? "Raknet Closed."; + Logger.info(`Disconnecting: ${reason}`); if (clientSide) { const disconnectPacket = new DisconnectPacket(); @@ -105,7 +108,7 @@ class Connection extends Listener { this.sendPacket(disconnectPacket, Priority.Immediate); } clearInterval(this.ticker); - this.removeAllListeners(); + this.removeAll(); // this.raknet.close(); } @@ -115,6 +118,7 @@ class Connection extends Listener { priority: Priority = Priority.Normal, ): void { const packetId = packet.getId(); + console.log(packetId); const hexId = packetId.toString(16).padStart(2, "0"); if (this.options.debug) { Logger.debug( @@ -133,7 +137,7 @@ class Connection extends Listener { this.raknet.once("connect", this.handleConnect.bind(this)); this.ticker = setInterval(() => { this.emit("tick", this.tick++); - }, 50); + }, this.options.tickRate); this.once("close", () => { this.disconnect(false); }); @@ -160,16 +164,29 @@ class Connection extends Listener { private async initializeSession(): Promise<[Advertisement, StartGamePacket]> { return new Promise((resolve, reject) => { let Advertisement_: Advertisement; + this.onceAfter("StartGamePacket", (packet: StartGamePacket) => { + startGamePacket = packet; + }); + this.once("session", async () => { Advertisement_ = await this.handleSessionStart(); console.timeEnd("RakConnect"); }); let startGamePacket: StartGamePacket; - this.once("StartGamePacket", (packet: StartGamePacket) => { - startGamePacket = packet; - this.once("spawn", () => { - resolve([Advertisement_, startGamePacket]); - }); + + this.once("spawn", () => { + try { + if (startGamePacket) { + resolve([Advertisement_, startGamePacket]); + } else { + this.once("StartGamePacket", (packet: StartGamePacket) => { + startGamePacket = packet; + resolve([Advertisement_, startGamePacket]); + }); + } + } catch (e) { + console.log(e); + } }); this.options.offline ? createOfflineSession(this) : authenticate(this); }); @@ -237,6 +254,12 @@ class Connection extends Listener { if (instance.status === PlayStatus.PlayerSpawn) { const init = new SetLocalPlayerAsInitializedPacket(); init.runtimeEntityId = this.runtimeEntityId; + const ServerBoundLoadingScreen = + new ServerboundLoadingScreenPacketPacket(); + ServerBoundLoadingScreen.type = + ServerboundLoadingScreenType.EndLoadingScreen; + ServerBoundLoadingScreen.hasScreenId = false; + // this.sendPacket(ServerBoundLoadingScreen, Priority.Immediate); this.sendPacket(init, Priority.Immediate); this.emit("spawn"); } @@ -313,7 +336,7 @@ class Connection extends Listener { return ecdh.computeSecret(publicKeyBuffer); } catch (error) { Logger.error("Error computing shared secret:", error as Error); - throw new Error("Failed to create shared secret."); // More general error message + throw new Error("Failed to create shared secret."); } } diff --git a/src/client/ClientOptions.ts b/src/client/ClientOptions.ts index d3b5a4a..023754e 100644 --- a/src/client/ClientOptions.ts +++ b/src/client/ClientOptions.ts @@ -41,6 +41,9 @@ type ClientOptions = { tokensFolder: string; viewDistance: number; deviceOS: DeviceOS; + sendAuthInput: boolean; + logPacketErrors: boolean; + tickRate: number; }; const defaultOptions: ClientOptions = { @@ -55,6 +58,9 @@ const defaultOptions: ClientOptions = { tokensFolder: `${process.cwd()}/tokens`, viewDistance: 4, deviceOS: DeviceOS.Win10, + sendAuthInput: true, + logPacketErrors: false, + tickRate: 50, }; export { diff --git a/src/client/Listener.ts b/src/client/Listener.ts index 9e22799..8d06071 100644 --- a/src/client/Listener.ts +++ b/src/client/Listener.ts @@ -1,35 +1,5 @@ -import { EventEmitter } from "node:events"; import type * as Protocol from "@serenityjs/protocol"; -import type { NetworkEvents } from "@serenityjs/network"; - -class Listener extends EventEmitter { - emit( - eventName: K, - ...args: Parameters - ): boolean; - emit(eventName: string, ...args: unknown[]): boolean; - emit(eventName: string, ...args: unknown[]): boolean { - return super.emit(eventName, ...args); - } - - on( - eventName: K, - listener: ListenerEvents[K], - ): this; - on(eventName: string, listener: (...args: unknown[]) => void): this; - on(eventName: string, listener: (...args: unknown[]) => void): this { - return super.on(eventName, listener); - } - - once( - eventName: K, - listener: ListenerEvents[K], - ): this; - once(eventName: string, listener: (...args: unknown[]) => void): this; - once(eventName: string, listener: (...args: unknown[]) => void): this { - return super.once(eventName, listener); - } -} +import Emitter from "@serenityjs/emitter"; type PacketNames = { [K in keyof typeof Protocol]: K extends `${string}Packet` ? K : never; @@ -37,15 +7,15 @@ type PacketNames = { type ListenerEvents = { // @ts-expect-error does not matter - [K in PacketNames]: (packet: InstanceType<(typeof Protocol)[K]>) => void; + [K in PacketNames]: [InstanceType<(typeof Protocol)[K]>]; } & { - session: () => void; - spawn: () => void; - tick: (tick: number) => void; - PrePlayerAuthInputPacket: ( - packet: Protocol.PlayerAuthInputPacket, - cancel: boolean, - ) => void; + session: []; + spawn: []; + tick: [number]; + PrePlayerAuthInputPacket: [Protocol.PlayerAuthInputPacket]; + close: []; }; +class Listener extends Emitter {} + export { Listener, type ListenerEvents }; diff --git a/src/tools/connect.ts b/src/tools/connect.ts index 36983e4..55cafa1 100644 --- a/src/tools/connect.ts +++ b/src/tools/connect.ts @@ -143,18 +143,6 @@ client.on("UpdateBlockPacket", (packet) => { } }); -// process.on("uncaughtException", (error) => { -// writeToLog( -// `[UNCAUGHT EXCEPTION] ${sanitizeToLatin(error.message)}\n${sanitizeToLatin(error.stack || "")}`, -// ); -// }); - -// process.on("unhandledRejection", (reason, promise) => { -// writeToLog( -// `[UNHANDLED REJECTION] at: ${sanitizeToLatin(String(promise))}\nReason: ${sanitizeToLatin(String(reason))}`, -// ); -// }); - client.on("TextPacket", handleTextPacket); async function handleTextPacket(packet: TextPacket): Promise { diff --git a/src/vendor/PacketSorter.ts b/src/vendor/PacketSorter.ts index c00c683..a1df243 100644 --- a/src/vendor/PacketSorter.ts +++ b/src/vendor/PacketSorter.ts @@ -1,4 +1,4 @@ -import { Priority } from "@serenityjs/raknet"; +import type { Priority } from "@serenityjs/raknet"; import { Logger } from "../vendor/Logger"; import { CompressionMethod, @@ -13,7 +13,6 @@ import type { Connection } from "../Connection"; import { Frame } from "@sanctumterra/raknet"; export class PacketSorter { - // private lastPacket: Buffer = Buffer.alloc(0); constructor(private readonly connection: Connection) { this.initializeListeners(); } @@ -24,14 +23,10 @@ export class PacketSorter { const framed = Framer.frame(serialized); const payload = this.preparePayload(framed); - // if ("sendFrame" in this.connection.raknet) { const frame = new Frame(); frame.orderChannel = 0; frame.payload = payload; - this.connection.raknet.sendFrame(frame, Priority.Immediate); - // } else if ("frameAndSend" in this.connection.raknet) { - // this.connection.raknet.frameAndSend(payload); - // } + this.connection.raknet.sendFrame(frame, priority); } catch (error) { Logger.error( `Error sending packet: ${(error as Error).message}`, @@ -168,22 +163,25 @@ export class PacketSorter { const PacketClass = Packets[id]; if (!PacketClass) { - Logger.warn(`Packet with ID ${id} not found`); + if (this.connection.options.logPacketErrors) { + Logger.warn(`Packet with ID ${id} not found`); + } continue; } if (this.connection.options.debug) { Logger.debug(`Received packet ${PacketClass.name}`); } try { - if (this.connection.listenerCount(PacketClass.name) > 0) { - const instance = new PacketClass(frame).deserialize(); - this.connection.emit(PacketClass.name, instance); - } + const instance = new PacketClass(frame).deserialize(); + // @ts-ignore + this.connection.emit(PacketClass.name, instance); } catch (error) { - Logger.warn( - `Error processing packet ${id}: ${error instanceof Error ? error.message : String(error)}\n`, - (error as Error).stack, - ); + if (this.connection.options.logPacketErrors) { + Logger.warn( + `Error processing packet ${id}: ${error instanceof Error ? error.message : String(error)}\n`, + (error as Error).stack, + ); + } } } } diff --git a/src/vendor/debug-tools.ts b/src/vendor/debug-tools.ts index 45e41b6..75a638e 100644 --- a/src/vendor/debug-tools.ts +++ b/src/vendor/debug-tools.ts @@ -11,6 +11,9 @@ export function measureExecutionTime( const result = originalMethod.apply(this, args); const end = performance.now(); const duration = end - start; + if (propertyKey === "decryptPacket") { + console.log(duration); + } if (globalThis.__DEBUG) Logger.debug(`${propertyKey} execution time: ${duration.toFixed(2)}ms`); return result; diff --git a/src/vendor/packets/player-auth-input.ts b/src/vendor/packets/player-auth-input.ts index 84767a5..52992c5 100644 --- a/src/vendor/packets/player-auth-input.ts +++ b/src/vendor/packets/player-auth-input.ts @@ -183,6 +183,7 @@ class PlayerAuthItemStackRequest extends DataType { } } +// @ts-ignore @Proto(Packet.PlayerAuthInput) export class PlayerAuthInputPacket extends DataPacket { @Serialize(Vector2f) public rotation!: Vector2f;