From 8f855a828e61c4268ee5434909d3e45278623457 Mon Sep 17 00:00:00 2001 From: dockfries Date: Sun, 16 Apr 2023 16:39:34 +0800 Subject: [PATCH] feat: support omp component raknet by patch call public --- packages/raknet/package.json | 5 +- packages/raknet/src/callbacks/index.ts | 60 ++++++++----- packages/raknet/src/enums/index.ts | 24 +++++ packages/raknet/src/functions/index.ts | 3 + packages/raknet/src/functions/macros.ts | 3 +- packages/raknet/src/functions/natives.ts | 107 +++++++++++------------ packages/raknet/src/functions/patch.ts | 3 + packages/raknet/src/main.ts | 18 ++-- packages/raknet/src/types/index.ts | 10 +++ packages/raknet/src/utils/index.ts | 28 ++++-- packages/raknet/tsconfig.json | 2 +- pnpm-lock.yaml | 4 + 12 files changed, 164 insertions(+), 103 deletions(-) create mode 100644 packages/raknet/src/functions/index.ts create mode 100644 packages/raknet/src/functions/patch.ts diff --git a/packages/raknet/package.json b/packages/raknet/package.json index e3a9725..af1e6cf 100644 --- a/packages/raknet/package.json +++ b/packages/raknet/package.json @@ -1,6 +1,6 @@ { "name": "@infernus/raknet", - "version": "0.0.1", + "version": "0.0.2", "description": "A functional wrapper of the popular open.mp raknet plugin for samp-node.", "keywords": [ "samp", @@ -35,5 +35,8 @@ }, "peerDependencies": { "@infernus/core": "workspace:^" + }, + "dependencies": { + "iconv-lite": "^0.6.3" } } diff --git a/packages/raknet/src/callbacks/index.ts b/packages/raknet/src/callbacks/index.ts index 154d215..737f92f 100644 --- a/packages/raknet/src/callbacks/index.ts +++ b/packages/raknet/src/callbacks/index.ts @@ -1,31 +1,51 @@ -// - It's not clear if registering multiple callbacks at the same time and then having one false followed by the next true will still execute (whether it's the same eventId i.e. packetId or rpcId) - -// If they affect each other, a copy of the global array will be saved, and then the callback will be called in a loop. If one of them returns false, the return will be executed. -// Otherwise return true when the loop is complete, maybe? +import { packetCallback, rpcCallback } from "@/types"; // raw callback -export const OnIncomingPacket = ( - func: (playerId: number, packetId: number, bs: number) => boolean -) => { - return samp.addEventListener("OnIncomingPacket", func); +const incomingPackets: packetCallback[] = []; +const incomingRPCs: rpcCallback[] = []; +const outgoingPackets: packetCallback[] = []; +const outgoingRPCs: rpcCallback[] = []; + +samp.registerEvent("OnIncomingPacket", "iii"); +samp.addEventListener( + "OnIncomingPacket", + (...args: [number, number, number]) => { + return incomingPackets.every((func) => func(...args)); + } +); + +samp.registerEvent("OnIncomingRPC", "iii"); +samp.addEventListener("OnIncomingRPC", (...args: [number, number, number]) => { + return incomingRPCs.every((func) => func(...args)); +}); + +samp.registerEvent("OnOutgoingPacket", "iii"); +samp.addEventListener( + "OnOutgoingPacket", + (...args: [number, number, number]) => { + return outgoingPackets.every((func) => func(...args)); + } +); + +samp.registerEvent("OnOutgoingRPC", "iii"); +samp.addEventListener("OnOutgoingRPC", (...args: [number, number, number]) => { + return outgoingRPCs.every((func) => func(...args)); +}); + +export const OnIncomingPacket = (func: packetCallback) => { + incomingPackets.push(func); }; -export const OnIncomingRPC = ( - func: (playerId: number, rpcId: number, bs: number) => boolean -) => { - return samp.addEventListener("OnIncomingRPC", func); +export const OnIncomingRPC = (func: rpcCallback) => { + incomingRPCs.push(func); }; -export const OnOutgoingPacket = ( - func: (playerId: number, packetId: number, bs: number) => boolean -) => { - return samp.addEventListener("OnOutgoingPacket", func); +export const OnOutgoingPacket = (func: packetCallback) => { + outgoingPackets.push(func); }; -export const OnOutgoingRPC = ( - func: (playerId: number, rpcId: number, bs: number) => boolean -) => { - return samp.addEventListener("OnOutgoingRPC", func); +export const OnOutgoingRPC = (func: rpcCallback) => { + outgoingRPCs.push(func); }; // syntactic sugar callback diff --git a/packages/raknet/src/enums/index.ts b/packages/raknet/src/enums/index.ts index 01d9519..b051ed4 100644 --- a/packages/raknet/src/enums/index.ts +++ b/packages/raknet/src/enums/index.ts @@ -55,3 +55,27 @@ export enum PR_PacketReliability { RELIABLE_ORDERED, RELIABLE_SEQUENCED, } + +export enum RakNetNatives { + SEND_PACKET, + SEND_RPC, + EMULATE_INCOMING_PACKET, + EMULATE_INCOMING_RPC, + NEW, + NEW_COPY, + DELETE, + RESET, + RESET_READ_POINTER, + RESET_WRITE_POINTER, + IGNORE_BITS, + SET_WRITE_OFFSET, + GET_WRITE_OFFSET, + SET_READ_OFFSET, + GET_READ_OFFSET, + GET_NUMBER_OF_BITS_USED, + GET_NUMBER_OF_BYTES_USED, + GET_NUMBER_OF_UNREAD_BITS, + GET_NUMBER_OF_BITS_ALLOCATED, + WRITE_VALUE, + READ_VALUE, +} diff --git a/packages/raknet/src/functions/index.ts b/packages/raknet/src/functions/index.ts new file mode 100644 index 0000000..655bae2 --- /dev/null +++ b/packages/raknet/src/functions/index.ts @@ -0,0 +1,3 @@ +export * from "./macros"; +export * from "./natives"; +export * from "./stocks"; diff --git a/packages/raknet/src/functions/macros.ts b/packages/raknet/src/functions/macros.ts index 7bb8fa0..64f75fc 100644 --- a/packages/raknet/src/functions/macros.ts +++ b/packages/raknet/src/functions/macros.ts @@ -55,8 +55,7 @@ export const BS_ReadCompressedBool = (bs: BitStream) => BS_ReadValue(bs, PR_ValueType.CBOOL); export const BS_ReadCompressedString = (bs: BitStream, size: number) => { - const byteArr = BS_ReadValue(bs, [PR_ValueType.CSTRING, size]) as number[]; - return byteArr.slice(0, byteArr.indexOf(0)); + return BS_ReadStringX(bs, size, true); }; export const BS_ReadBits = (bs: BitStream, size: number) => diff --git a/packages/raknet/src/functions/natives.ts b/packages/raknet/src/functions/natives.ts index 869af0e..e54d316 100644 --- a/packages/raknet/src/functions/natives.ts +++ b/packages/raknet/src/functions/natives.ts @@ -1,9 +1,11 @@ -import { PR_PacketPriority, PR_PacketReliability, PR_ValueType } from "@/enums"; +import { + PR_PacketPriority, + PR_PacketReliability, + PR_ValueType, + RakNetNatives, +} from "@/enums"; import { BitStream } from "@/types"; - -export const PR_Init = () => { - samp.callNative("PR_Init", ""); -}; +import { patchRakNetNative } from "./patch"; export const PR_SendPacket = ( bs: BitStream, @@ -12,9 +14,8 @@ export const PR_SendPacket = ( reliability = PR_PacketReliability.RELIABLE_ORDERED, orderingChannel = 0 ) => { - samp.callNative( - "PR_SendPacket", - "iiiii", + patchRakNetNative( + RakNetNatives.SEND_PACKET, bs, playerId, priority, @@ -31,9 +32,8 @@ export const PR_SendRPC = ( reliability = PR_PacketReliability.RELIABLE_ORDERED, orderingChannel = 0 ) => { - samp.callNative( - "PR_SendRPC", - "iiiiii", + patchRakNetNative( + RakNetNatives.SEND_RPC, bs, playerId, rpcId, @@ -44,7 +44,7 @@ export const PR_SendRPC = ( }; export const PR_EmulateIncomingPacket = (bs: BitStream, playerId: number) => { - samp.callNative("PR_EmulateIncomingPacket", "ii", bs, playerId); + patchRakNetNative(RakNetNatives.EMULATE_INCOMING_PACKET, bs, playerId); }; export const PR_EmulateIncomingRPC = ( @@ -52,95 +52,89 @@ export const PR_EmulateIncomingRPC = ( playerId: number, rpcId: number ) => { - samp.callNative("PR_EmulateIncomingRPC", "iii", bs, playerId, rpcId); + patchRakNetNative(RakNetNatives.EMULATE_INCOMING_RPC, bs, playerId, rpcId); }; export const BS_New = (): BitStream => { - return samp.callNative("BS_New", ""); + return patchRakNetNative(RakNetNatives.NEW); }; export const BS_NewCopy = (bs: BitStream): BitStream => { - return samp.callNative("BS_NewCopy", "i", bs); + return patchRakNetNative(RakNetNatives.NEW_COPY, bs); }; export const BS_Delete = (bs: BitStream): BitStream => { - return samp.callNative("BS_Delete", "i", bs); + patchRakNetNative(RakNetNatives.DELETE, bs); + return bs; }; export const BS_Reset = (bs: BitStream) => { - samp.callNative("BS_Reset", "i", bs); + patchRakNetNative(RakNetNatives.RESET, bs); }; export const BS_ResetReadPointer = (bs: BitStream) => { - samp.callNative("BS_ResetReadPointer", "i", bs); + patchRakNetNative(RakNetNatives.RESET_READ_POINTER, bs); }; export const BS_ResetWritePointer = (bs: BitStream) => { - samp.callNative("BS_ResetWritePointer", "i", bs); + patchRakNetNative(RakNetNatives.RESET_WRITE_POINTER, bs); }; export const BS_IgnoreBits = (bs: BitStream, number_of_bits: number) => { - samp.callNative("BS_IgnoreBits", "ii", bs, number_of_bits); + patchRakNetNative(RakNetNatives.IGNORE_BITS, bs, number_of_bits); }; export const BS_SetWriteOffset = (bs: BitStream, offset: number) => { - samp.callNative("BS_SetWriteOffset", "ii", bs, offset); + patchRakNetNative(RakNetNatives.SET_WRITE_OFFSET, bs, offset); }; export const BS_GetWriteOffset = (bs: BitStream): number => { - return samp.callNative("BS_GetWriteOffset", "iI", bs); + return patchRakNetNative(RakNetNatives.GET_WRITE_OFFSET, bs); }; export const BS_SetReadOffset = (bs: BitStream, offset: number) => { - samp.callNative("BS_SetReadOffset", "ii", bs, offset); + patchRakNetNative(RakNetNatives.SET_READ_OFFSET, bs, offset); }; export const BS_GetReadOffset = (bs: BitStream): number => { - return samp.callNative("BS_GetReadOffset", "iI", bs); + return patchRakNetNative(RakNetNatives.GET_READ_OFFSET, bs); }; export const BS_GetNumberOfBitsUsed = (bs: BitStream): number => { - return samp.callNative("BS_GetNumberOfBitsUsed", "iI", bs); + return patchRakNetNative(RakNetNatives.GET_NUMBER_OF_BITS_USED, bs); }; export const BS_GetNumberOfBytesUsed = (bs: BitStream): number => { - return samp.callNative("BS_GetNumberOfBytesUsed", "iI", bs); + return patchRakNetNative(RakNetNatives.GET_NUMBER_OF_BYTES_USED, bs); }; export const BS_GetNumberOfUnreadBits = (bs: BitStream): number => { - return samp.callNative("BS_GetNumberOfUnreadBits", "iI", bs); + return patchRakNetNative(RakNetNatives.GET_NUMBER_OF_UNREAD_BITS, bs); }; export const BS_GetNumberOfBitsAllocated = (bs: BitStream): number => { - return samp.callNative("BS_GetNumberOfBitsAllocated", "iI", bs); -}; - -const isArrValueType = (type: PR_ValueType) => { - return [ - PR_ValueType.STRING, - PR_ValueType.CSTRING, - PR_ValueType.STRING8, - PR_ValueType.STRING32, - PR_ValueType.FLOAT3, - PR_ValueType.FLOAT4, - PR_ValueType.VECTOR, - PR_ValueType.NORM_QUAT, - ].includes(type); + return patchRakNetNative(RakNetNatives.GET_NUMBER_OF_BITS_ALLOCATED, bs); }; export function BS_ReadValue( bs: BitStream, ...types: (PR_ValueType | [PR_ValueType, number])[] ): number | number[] | (number | number[])[] { - let paramTypes = ""; + const ret: any[] = []; types.forEach((item) => { - const isReplaceItem = Array.isArray(item); - const type = isReplaceItem ? item[0] : item; - paramTypes += "i"; - paramTypes += isArrValueType(type) ? "A" : "F"; - isReplaceItem && (paramTypes += "i"); + const isPlaceholder = Array.isArray(item); + const type = isPlaceholder ? item[0] : item; + ret.push( + patchRakNetNative( + RakNetNatives.READ_VALUE, + bs, + type, + isPlaceholder ? item[1] : 0 + ) + ); }); - return samp.callNative("BS_ReadValue", `i${paramTypes}`, bs, ...types); + if (ret.length === 1) return ret[0]; + return ret; } export const BS_WriteValue = ( @@ -157,16 +151,13 @@ export const BS_WriteValue = ( ] )[] ) => { - let paramTypes = ""; types.forEach((item) => { - paramTypes += "i"; - paramTypes += isArrValueType(item[0]) ? "a" : "f"; - if (item.length === 3) paramTypes += "i"; + patchRakNetNative( + RakNetNatives.WRITE_VALUE, + bs, + item[0], + item[1], + item[2] || 0 + ); }); - samp.callNative( - "BS_WriteValue", - `i${paramTypes}`, - bs, - ...types.flat(Infinity) - ); }; diff --git a/packages/raknet/src/functions/patch.ts b/packages/raknet/src/functions/patch.ts new file mode 100644 index 0000000..2803f4d --- /dev/null +++ b/packages/raknet/src/functions/patch.ts @@ -0,0 +1,3 @@ +export const patchRakNetNative = (...args: any[]) => { + return samp.callPublic("RakNetNative", `a`, args); +}; diff --git a/packages/raknet/src/main.ts b/packages/raknet/src/main.ts index fa6115f..16292dc 100644 --- a/packages/raknet/src/main.ts +++ b/packages/raknet/src/main.ts @@ -1,12 +1,6 @@ -import { GameMode, IFilterScript } from "@infernus/core"; -import { PR_Init } from "./functions/natives"; - -export default { - name: "raknet", - load() { - new GameMode().onInit = PR_Init; - }, - unload() { - /* empty */ - }, -} as IFilterScript; +export * from "./callbacks"; +export * from "./defines"; +export * from "./enums"; +export * from "./functions"; +export * from "./interfaces"; +export * from "./types"; diff --git a/packages/raknet/src/types/index.ts b/packages/raknet/src/types/index.ts index 140f596..ff20b37 100644 --- a/packages/raknet/src/types/index.ts +++ b/packages/raknet/src/types/index.ts @@ -1,3 +1,13 @@ export type BitStream = number; export type Vector3 = [number, number, number]; export type Vector4 = [number, number, number, number]; +export type packetCallback = ( + playerId: number, + packetId: number, + bs: number +) => boolean; +export type rpcCallback = ( + playerId: number, + rpcId: number, + bs: number +) => boolean; diff --git a/packages/raknet/src/utils/index.ts b/packages/raknet/src/utils/index.ts index 86ec119..a1f8013 100644 --- a/packages/raknet/src/utils/index.ts +++ b/packages/raknet/src/utils/index.ts @@ -1,20 +1,30 @@ import { PR_ValueType } from "@/enums"; import { BS_ReadValue } from "@/functions/natives"; import { BitStream } from "@/types"; +import iconv from "iconv-lite"; export const BS_ConvertToByteString = ( value: string | number[], - length: number + length: number, + charset = "utf-8" ) => { - let finalValue: string | number[] = value; - if (typeof finalValue === "string") { - const encoder = new TextEncoder(); - finalValue = Array.from(encoder.encode(finalValue)); + let finalValue: Buffer | [] = []; + if (typeof value === "string") { + finalValue = iconv.encode(value, charset); } - return finalValue.slice(0, length); + return Array.from(finalValue).slice(0, length); }; -export const BS_ReadStringX = (bs: BitStream, size: number) => { - const byteArr = BS_ReadValue(bs, [PR_ValueType.STRING, size]) as number[]; - return byteArr.slice(0, byteArr.indexOf(0)); +export const BS_ReadStringX = ( + bs: BitStream, + size: number, + isCompressed = false, + charset = "utf-8" +) => { + const byteArr = BS_ReadValue(bs, [ + isCompressed ? PR_ValueType.CSTRING : PR_ValueType.STRING, + size, + ]) as number[]; + const validByteArr = byteArr.slice(0, byteArr.indexOf(0)); + return iconv.decode(Buffer.from(validByteArr), charset); }; diff --git a/packages/raknet/tsconfig.json b/packages/raknet/tsconfig.json index 71ff765..91592d7 100644 --- a/packages/raknet/tsconfig.json +++ b/packages/raknet/tsconfig.json @@ -1,7 +1,7 @@ { "include": ["src/**/*.ts"], "compilerOptions": { - "types": ["@sa-mp/node"], + "types": ["@sa-mp/node", "@types/node"], "baseUrl": "./", "paths": { "@/*": ["src/*"] }, "target": "ESNext", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f31b183..3a93772 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -88,6 +88,10 @@ importers: version: 6.0.0(rollup@3.15.0) packages/raknet: + dependencies: + iconv-lite: + specifier: ^0.6.3 + version: 0.6.3 devDependencies: '@infernus/core': specifier: workspace:^