diff --git a/lib/GMLIB_API-JS.d.ts b/lib/GMLIB_API-JS.d.ts index 4d6982e..d72233b 100644 --- a/lib/GMLIB_API-JS.d.ts +++ b/lib/GMLIB_API-JS.d.ts @@ -1054,6 +1054,202 @@ declare class UserCache { static getAllPlayerInfo(): { Xuid: String; Uuid: string; Name: string; }[] } +/** 二进制流数据包类 */ +declare class GMLIB_BinaryStream { + constructor(); + + /** 发送数据包 */ + sendTo( + /** 要发送数据包的玩家对象 */ + player: Player, + /** 数据包发送后是否销毁 */ + free: boolean = true + ): void; + + /** 发送数据包到玩家数组 */ + sendToPlayers( + /** 要发送数据包的玩家对象数组 */ + players: Player[], + /** 数据包发送后是否销毁 */ + free: boolean = true + ): void; + + /** 发送数据包到所有玩家 */ + sendToAll( + /** 数据包发送后是否销毁 */ + free: boolean = true + ): void; + + /** 发送数据包到维度 */ + sendToDimension( + /** 维度ID */ + dimid: number, + /** 数据包发送后是否销毁 */ + free: boolean = true + ): void; + + /** 销毁数据包 */ + destroy(): void; + + /** 重置数据包 */ + reset(): void; + + /** 写入数据包头部 */ + writePacketHeader( + /** 数据包ID */ + id: number + ): void; + + /** 写入UUID */ + writeUuid( + /** UUID */ + value: string + ): void; + + /** 写入物品 */ + writeItem( + /** 物品对象 */ + value: Item + ): void; + + /** 写入NBT */ + writeCompoundTag( + /** NBT */ + value: NbtCompound + ): void; + + /** */ + writeDataItem( + /** 数据项 */ + value: { "id": number, "type": number, "value": string | IntPos | FloatPos | number | NbtCompound }[] + ): void; + + writeActorLink( + /** 数据项 */ + value: {"mA":number,"mB":number,"mType":number,"mImmediate":boolean,"mPassengerInitiated":boolean} + ): void; + + /** 写入浮点数坐标对象 */ + writeVec3( + /** 浮点数坐标对象 */ + value: FloatPos + ) : void; + + /** 写入整数坐标对象 */ + writeBlockPos( + /** 整数坐标对象 */ + value: IntPos + ) : void; + + /** 写入方向角对象 */ + writeVec2( + /** 方向角对象 */ + value: DirectionAngle + ) : void; + + /** 写入字符串 */ + writeString( + /** 字符串 */ + value: string + ): void; + + /** 写入布尔值 */ + writeBool( + /** 布尔值 */ + value: boolean + ): void; + + /** 写入字节 */ + writeByte( + /** 字节 */ + value: number + ): void; + + /** 写入(双精度)浮点数 */ + writeDouble( + /** 浮点数 */ + value: number + ): void; + + /** 写入(单精度)浮点数 */ + writeFloat( + /** 浮点数 */ + value: number + ): void; + + /** */ + writeSignedBigEndianInt( + /** 数值 */ + value: number + ): void; + + /** */ + writeSignedInt( + /** 数值 */ + value: number + ): void; + + /** 写入 */ + writeSignedInt64( + /** 数值 */ + value: number + ): void; + + /** */ + writeSignedShort( + /** 数值 */ + value: number + ): void; + + /** */ + writeUnsignedChar( + /** 数值 */ + value: number + ): void; + + /** */ + writeUnsignedInt( + /** 数值 */ + value: number + ): void; + + /** */ + writeUnsignedInt64( + /** 数值 */ + value: number + ): void; + + /** */ + writeUnsignedShort( + /** 数值 */ + value: number + ): void; + + /** */ + writeUnsignedVarInt( + /** 数值 */ + value: number + ): void; + + /** */ + writeUnsignedVarInt64( + /** 数值 */ + value: number + ): void; + + /** */ + writeVarInt( + /** 数值 */ + value: number + ): void; + + /** */ + writeVarInt64( + /** 数值 */ + value: number + ): void; +} + interface Player { /** (GMLIB)转换成实体对象 */ toEntity(): Entity; diff --git a/lib/GMLIB_API-JS.js b/lib/GMLIB_API-JS.js index 23d32b1..b1b5e3e 100644 --- a/lib/GMLIB_API-JS.js +++ b/lib/GMLIB_API-JS.js @@ -374,7 +374,61 @@ const GMLIB_API = { getDefaultGameMode: ll.import("GMLIB_API", "getDefaultGameMode"), /** 设置默认游戏模式 @type {function(mode):void} */ setDefaultGameMode: ll.import("GMLIB_API", "setDefaultGameMode"), -} +}; + +/** LRCA的二进制流数据包导出接口 */ +const GMLIB_BinaryStream_API = { + /** 创建二进制流数据包 @type {function():number} */ + create: ll.import("GMLIB_BinaryStream_API", "create"), + /** 发送二进制流数据包 @type {function(number,player, boolean):void} */ + sendTo: ll.import("GMLIB_BinaryStream_API", "sendTo"), + /** 销毁二进制流数据包 @type {function(number):void} */ + destroy: ll.import("GMLIB_BinaryStream_API", "destroy"), + /** 重置二进制流数据包 @type {function(number):void} */ + reset: ll.import("GMLIB_BinaryStream_API", "reset"), + /** 写入二进制流数据包头部 @type {function(number, number):void} */ + writePacketHeader: ll.import("GMLIB_BinaryStream_API", "writePacketHeader"), + /** 写入UUID @type {function(number, string):void} */ + writeUuid: ll.import("GMLIB_BinaryStream_API", "writeUuid"), + /** 写入物品 @type {function(number, Item):void} */ + writeItem: ll.import("GMLIB_BinaryStream_API", "writeItem"), + /** 写入NBT @type {function(NbtCompound, Item):void} */ + writeCompoundTag: ll.import("GMLIB_BinaryStream_API", "writeCompoundTag"), + /** 写入字符串 @type {function(number, string):void} */ + writeString: ll.import("GMLIB_BinaryStream_API", "writeString"), + /** 写入布尔值 @type {function(number, boolean):void} */ + writeBool: ll.import("GMLIB_BinaryStream_API", "writeBool"), + /** 写入字节 @type {function(number, number):void} */ + writeByte: ll.import("GMLIB_BinaryStream_API", "writeByte"), + /** 写入双精度浮点数 @type {function(number, number):void} */ + writeDouble: ll.import("GMLIB_BinaryStream_API", "writeDouble"), + /** 写入浮点数 @type {function(number, number):void} */ + writeFloat: ll.import("GMLIB_BinaryStream_API", "writeFloat"), + /** @type {function(number, number):void} */ + writeSignedBigEndianInt: ll.import("GMLIB_BinaryStream_API", "writeSignedBigEndianInt"), + /** @type {function(number, number):void} */ + writeSignedInt: ll.import("GMLIB_BinaryStream_API", "writeSignedInt"), + /** @type {function(number, number):void} */ + writeSignedInt64: ll.import("GMLIB_BinaryStream_API", "writeSignedInt64"), + /** @type {function(number, number):void} */ + writeSignedShort: ll.import("GMLIB_BinaryStream_API", "writeSignedShort"), + /** @type {function(number, number):void} */ + writeUnsignedChar: ll.import("GMLIB_BinaryStream_API", "writeUnsignedChar"), + /** @type {function(number, number):void} */ + writeUnsignedInt: ll.import("GMLIB_BinaryStream_API", "writeUnsignedInt"), + /** @type {function(number, number):void} */ + writeUnsignedInt64: ll.import("GMLIB_BinaryStream_API", "writeUnsignedInt64"), + /** @type {function(number, number):void} */ + writeUnsignedShort: ll.import("GMLIB_BinaryStream_API", "writeUnsignedShort"), + /** @type {function(number, number):void} */ + writeUnsignedVarInt: ll.import("GMLIB_BinaryStream_API", "writeUnsignedVarInt"), + /** @type {function(number, number):void} */ + writeUnsignedVarInt64: ll.import("GMLIB_BinaryStream_API", "writeUnsignedVarInt64"), + /** @type {function(number, number):void} */ + writeVarInt: ll.import("GMLIB_BinaryStream_API", "writeVarInt"), + /** @type {function(number, number):void} */ + writeVarInt64: ll.import("GMLIB_BinaryStream_API", "writeVarInt64"), +}; /** 静态悬浮字类列表 @type {Map} */ const mStaticFloatingTextMap = new Map(); @@ -2052,6 +2106,334 @@ class UserCache { } }; +/** 二进制数据包API类 */ +class GMLIB_BinaryStream { + + /** 数据包ID @type {number} */ + #id = null; + /** 数据包是否被销毁 */ + #destroy = false; + + constructor() { + this.#id = GMLIB_BinaryStream_API.create(); + } + + /** + * 发送数据包 + * @param {Player} player 玩家 + * @param {boolean} [free=true] 发送后销毁数据包 + */ + sendTo(player, free = true) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.sendTo(this.#id, player, free); + if (free) { + this.destroy(); + this.#destroy = true; + } + } + + /** + * 发送数据包到玩家 + * @param {Player[]} players 玩家对象数组 + * @param {boolean} free 发送后销毁数据包 + */ + sendToPlayers(players, free = true) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + players.forEach(player => this.sendTo(player, false)); + if (free) { + this.destroy(); + this.#destroy = true; + } + } + + /** + * 发送数据包到所有玩家 + * @param {boolean} [free=true] 发送后销毁数据包 + */ + sendToAll(free = true) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + mc.getOnlinePlayers().forEach(player => this.sendTo(player, false)); + if (free) { + this.destroy(); + this.#destroy = true; + } + } + + /** + * 发送数据包到维度 + * @param {number} dimid 维度ID + * @param {boolean} [free=true] 发送后销毁数据包 + */ + sendToDimension(dimid, free = true) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + mc.getOnlinePlayers().filter(player => player.pos.dimid === dimid).forEach(player => this.sendTo(player, false)); + if (free) { + this.destroy(); + this.#destroy = true; + } + } + + /** + * 销毁数据包 + */ + destroy() { + GMLIB_BinaryStream_API.destroy(this.#id); + this.#destroy = true; + } + + /** + * 重置数据包 + */ + reset() { + GMLIB_BinaryStream_API.reset(this.#id); + this.#destroy = false; + } + + /** + * 写入数据包头部 + * @param {number} id 数据包ID + */ + writePacketHeader(id) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writePacketHeader(this.#id, id); + } + + /** + * 写入UUID + * @param {string} value UUID + */ + writeUuid(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeUuid(this.#id, value); + } + + /** + * 写入物品 + * @param {Item} value 物品 + */ + writeItem(value){ + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeItem(this.#id, value); + } + + /** + * 写入NBT + * @param {NbtCompound} value NBT + */ + writeCompoundTag(value){ + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeCompoundTag(this.#id, value); + } + + /** + * @param {{"id":number,"type":number,"value":string|IntPos|FloatPos|number|NbtCompound}[]} value 数据 + */ + writeDataItem(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + this.writeUnsignedVarInt(value.length); + for (const data of value) { + this.writeUnsignedVarInt(data.id); + this.writeUnsignedVarInt(data.type); + switch (data.type) { + case 0: this.writeByte(data.value); break; + case 1: this.writeSignedShort(data.value); break; + case 2: this.writeSignedInt(data.value); break; + case 3: this.writeFloat(data.value); break; + case 4: this.writeString(data.value); break; + case 5: this.writeCompoundTag(data.value); break; + case 6: this.writeBlockPos(data.value); break; + case 7: this.writeSignedInt64(data.value); break; + case 8: this.writeVec3(data.value); break; + default: throw new Error("Unknown data type"); + } + } + } + + /** + * @param {{"mA":number,"mB":number,"mType":number,"mImmediate":boolean,"mPassengerInitiated":boolean}} value 数据 + */ + writeActorLink(value) { + this.writeVarInt64(value.mA); + this.writeVarInt64(value.mB); + this.writeUnsignedChar(value.mType); + this.writeBool(value.mImmediate); + this.writeBool(value.mPassengerInitiated); + } + + /** + * 写入字符串 + * @param {string} value 字符串 + */ + writeString(value){ + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeString(this.#id, value); + } + + /** + * 写入布尔值 + * @param {boolean} value 布尔值 + */ + writeBool(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeBool(this.#id, value); + } + + /** + * 写入字节 + * @param {number} value 字节 + */ + writeByte(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeByte(this.#id, value); + } + + /** + * 写入(双精度)浮点数 + * @param {number} value 浮点数 + */ + writeDouble(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeDouble(this.#id, value); + } + + /** + * 写入(单精度)浮点数 + * @param {number} value 浮点数 + */ + writeFloat(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeFloat(this.#id, value); + } + + /** + * 写入浮点数坐标对象 + * @param {FloatPos} value 浮点数坐标对象 + */ + writeVec3({ x, y, z }) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + this.writeFloat(x); + this.writeFloat(y); + this.writeFloat(z); + } + + /** + * 写入整数坐标对象 + * @param {IntPos} value 整数坐标对象 + */ + writeBlockPos({ x, y, z }) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + this.writeVarInt(x); + this.writeUnsignedVarInt(y); + this.writeVarInt(z); + } + + /** + * 写入方向角对象 + * @param {DirectionAngle} value 方向角对象 + */ + writeVec2({ pitch, yaw }) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + this.writeFloat(pitch); + this.writeFloat(yaw); + } + + /** + * @param {number} value 数值 + */ + writeSignedBigEndianInt(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeSignedBigEndianInt(this.#id, value); + } + + /** + * @param {number} value 数值 + */ + writeSignedInt(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeSignedInt(this.#id, value); + } + + /** + * @param {number} value 数值 + */ + writeSignedInt64(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeSignedInt64(this.#id, value); + } + + /** + * @param {number} value 数值 + */ + writeSignedShort(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeSignedShort(this.#id, value); + } + + /** + * @param {number} value 数值 + */ + writeUnsignedChar(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeUnsignedChar(this.#id, value); + } + + /** + * @param {number} value 数值 + */ + writeUnsignedInt(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeUnsignedInt(this.#id, value); + } + + /** + * @param {number} value 数值 + */ + writeUnsignedInt64(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeUnsignedInt64(this.#id, value); + } + + /** + * @param {number} value 数值 + */ + writeUnsignedShort(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeUnsignedShort(this.#id, value); + } + + /** + * @param {number} value 数值 + */ + writeUnsignedVarInt(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeUnsignedVarInt(this.#id, value); + } + + /** + * @param {number} value 数值 + */ + writeUnsignedVarInt64(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeUnsignedVarInt64(this.#id, value); + } + + /** + * @param {number} value 数值 + */ + writeVarInt(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeVarInt(this.#id, value); + } + + /** + * @param {number} value 数值 + */ + writeVarInt64(value) { + if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); + GMLIB_BinaryStream_API.writeVarInt64(this.#id, value); + } +} + LLSE_Player.prototype.toEntity = /** * 获取实体对象 @@ -2661,5 +3043,6 @@ module.exports = { JsonI18n, Version, I18nAPI, - UserCache + UserCache, + GMLIB_BinaryStream }; \ No newline at end of file diff --git a/src/BinaryStreamApi.cpp b/src/BinaryStreamApi.cpp new file mode 100644 index 0000000..fb8a20f --- /dev/null +++ b/src/BinaryStreamApi.cpp @@ -0,0 +1,85 @@ +#include "Global.h" +using namespace ll::hash_utils; + +class LegacyScriptBinaryStreamManager { +private: + int64 mNextBinaryStreamId = 0; + std::unordered_map> mBinaryStream; + +public: + uint getNextId() { return mNextBinaryStreamId++; } + + void cretateBinaryStream(uint id) { mBinaryStream[id] = std::make_shared(); } + + void removeBinaryStream(uint64 id) { mBinaryStream.erase(id); } + + std::shared_ptr getBinaryStream(uint64 id) { + return mBinaryStream.contains(id) ? mBinaryStream.at(id) : nullptr; + } + +public: + static LegacyScriptBinaryStreamManager& getInstance() { + static std::unique_ptr instance; + if (!instance) instance = std::make_unique(); + return *instance; + } +}; + +#define EXPORTAPI(funcName, type, fuc) \ + RemoteCall::exportAs("GMLIB_BinaryStream_API", funcName, [](uint64 BinaryStreamId, type value) -> void { \ + auto binaryStream = LegacyScriptBinaryStreamManager::getInstance().getBinaryStream(BinaryStreamId); \ + if (binaryStream != nullptr) fuc; \ + }) + +template +struct Info; +template +struct Info { + using ArgT = A; +}; +#define EXPORTAPI2(T) EXPORTAPI(#T, Info::ArgT, binaryStream->T(value)) + +void Export_BinaryStream_API() { + RemoteCall::exportAs("GMLIB_BinaryStream_API", "create", []() -> uint64 { + auto id = LegacyScriptBinaryStreamManager::getInstance().getNextId(); + LegacyScriptBinaryStreamManager::getInstance().cretateBinaryStream(id); + return id; + }); + RemoteCall::exportAs("GMLIB_BinaryStream_API", "reset", [](uint64 BinaryStreamId) -> void { + if (LegacyScriptBinaryStreamManager::getInstance().getBinaryStream(BinaryStreamId) == nullptr) + LegacyScriptBinaryStreamManager::getInstance().cretateBinaryStream(BinaryStreamId); + LegacyScriptBinaryStreamManager::getInstance().getBinaryStream(BinaryStreamId)->reset(); + }); + RemoteCall::exportAs( + "GMLIB_BinaryStream_API", + "sendTo", + [](uint64 BinaryStreamId, Player* player) -> void { + auto binaryStream = LegacyScriptBinaryStreamManager::getInstance().getBinaryStream(BinaryStreamId); + if (binaryStream != nullptr) binaryStream->sendTo(*player); + } + ); + RemoteCall::exportAs("GMLIB_BinaryStream_API", "destroy", [](uint64 BinaryStreamId) -> void { + LegacyScriptBinaryStreamManager::getInstance().removeBinaryStream(BinaryStreamId); + }); + EXPORTAPI("writePacketHeader", int, binaryStream->writePacketHeader((MinecraftPacketIds)value)); + EXPORTAPI("writeUuid", std::string const&, binaryStream->writeUuid(mce::UUID::fromString(value))); + EXPORTAPI("writeItem", ItemStack*, NetworkItemStackDescriptor(*value).write(*binaryStream)); + EXPORTAPI("writeString", std::string const&, binaryStream->writeString(value)); + EXPORTAPI("writeCompoundTag", CompoundTag*, binaryStream->writeCompoundTag(*value)); + EXPORTAPI2(writeBool); + EXPORTAPI2(writeByte); + EXPORTAPI2(writeDouble); + EXPORTAPI2(writeFloat); + EXPORTAPI2(writeSignedBigEndianInt); + EXPORTAPI2(writeSignedInt); + EXPORTAPI2(writeSignedInt64); + EXPORTAPI2(writeSignedShort); + EXPORTAPI2(writeUnsignedChar); + EXPORTAPI2(writeUnsignedInt); + EXPORTAPI2(writeUnsignedInt64); + EXPORTAPI2(writeUnsignedShort); + EXPORTAPI2(writeUnsignedVarInt); + EXPORTAPI2(writeUnsignedVarInt64); + EXPORTAPI2(writeVarInt); + EXPORTAPI2(writeVarInt64); +} \ No newline at end of file diff --git a/src/CompatibilityApi.cpp b/src/CompatibilityApi.cpp index 7e213c1..39058cf 100644 --- a/src/CompatibilityApi.cpp +++ b/src/CompatibilityApi.cpp @@ -1,6 +1,5 @@ #include "Global.h" #include -#include bool isInteger(const std::string& str) { std::regex pattern("^[+-]?\\d+$"); diff --git a/src/Entry.cpp b/src/Entry.cpp index d761a55..4fc8301 100644 --- a/src/Entry.cpp +++ b/src/Entry.cpp @@ -16,6 +16,7 @@ bool LegacyRemoteCallApi::load() { Export_Compatibility_API(); ExportPAPI(); Export_Event_API(); + Export_BinaryStream_API(); logger.info("GMLIB-LegacyRemoteCallApi Loaded!"); logger.info( "Loaded Version: {} with {}", diff --git a/src/EventAPI.cpp b/src/EventAPI.cpp index 8793bbf..d30fab7 100644 --- a/src/EventAPI.cpp +++ b/src/EventAPI.cpp @@ -13,7 +13,7 @@ public: } void emplaceListener(std::string const& scriptEventId, ll::event::ListenerPtr listenerPtr) { - mEventListeners[doHash(scriptEventId)] = listenerPtr; + mEventListeners[doHash(scriptEventId)] = std::move(listenerPtr); } void removeListener(std::string const& scriptEventId) { diff --git a/src/Global.h b/src/Global.h index 851648d..5428fee 100644 --- a/src/Global.h +++ b/src/Global.h @@ -21,4 +21,5 @@ extern void Export_Legacy_GMLib_ModAPI(); extern void Export_Legacy_GMLib_ServerAPI(); extern void Export_Compatibility_API(); extern void ExportPAPI(); -extern void Export_Event_API(); \ No newline at end of file +extern void Export_Event_API(); +extern void Export_BinaryStream_API(); \ No newline at end of file