diff --git a/CHANGELOG.md b/CHANGELOG.md index 865534c6..faa2f95f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Added packet sending APIs: `Packet::sendTo`, `Packet::sendToClients` and `Packet::sendToServer` @zimuya4153 +- Added `BinaryStream` APIs: `getReadPointer`, `setReadPointer`, `setData`, `writeBytes`, `writeUuid` and `writeNormalizedFloat` @zimuya4153 +- Added server APIs: `mc.getMotd`, `mc.getOnlinePlayerNum`, `mc.getMaxNumPlayers`, `mc.getDimensionId` and `mc.getDimensionName` @zimuya4153 + +### Changed + +- `BinaryStream::getData([clear])` now supports the optional `clear` parameter and returns `ByteBuffer` instead of `String` @zimuya4153 +- `BinaryStream::createPacket(pktid[,raw])` now supports creating raw packets @zimuya4153 +- Allowed string arguments for several `BinaryStream::write*` numeric APIs to better support BigInt values @zimuya4153 + ## [0.18.2] - 2026-04-17 ### Fixed diff --git a/docs/apis/GameAPI/Packet.md b/docs/apis/GameAPI/Packet.md index fb9ab5a0..8ffbc4ec 100644 --- a/docs/apis/GameAPI/Packet.md +++ b/docs/apis/GameAPI/Packet.md @@ -1,18 +1,16 @@ -# 🎓 Packet API +# 🎓 Packet API -The following objects and APIs provide the basic BDS packet interface for scripts. +The following objects and APIs provide the basic BDS packet interface for scripts. -(Please refer to Nukkit, PokcetMine, BDS Reverse to know the packet structure) If the client crashes, it is a packet structure error, not a bug. +(Please refer to Nukkit, PokcetMine, BDS Reverse to know the packet structure) If the client crashes, it is a packet structure error, not a bug. The documentation does not list the packet ID and its structure, please check it yourself. - ## 目录 + - 🔉 [Packet Object API](#-packet-object-api) - 🔌 [Binary stream object API](#-binary-stream-object-api) - - ## 🔉 Packet Object API In LLSE, 「Packet Object」 is used to get information about packets. @@ -21,10 +19,8 @@ In LLSE, 「Packet Object」 is used to get information about packets. #### Get from API -Call some **return packet object** function to get to the packet object given by BDS -See [Binary Stream Objects](#-binary-stream-object-api) for details - - +Call some **return packet object** function to get to the packet object given by BDS +See [Binary Stream Objects](#-binary-stream-object-api) for details ### Packet Objects - Functions @@ -35,9 +31,7 @@ Every packet object contains some member functions (member methods) that can be `pkt.getName()` - Return value:packet name -- Return value type: `String` - - +- Return value type: `String` #### Get packet ID @@ -46,15 +40,55 @@ Every packet object contains some member functions (member methods) that can be - Return value:packet id - Return value type: `Integer` +#### Send packet to specified target + +!!! warning +This function is only available in 0.19.0 and later. + +`pkt.sendTo(pos)` +`pkt.sendTo(x,y,z,dimid)` +`pkt.sendTo(target)` + +- Parameters: + + - pos : `IntPos` / `FloatPos` + The coordinates of the packet send target (or use x, y, z, dimid to determine the target position) + - target : `Player` / `Entity` + Packet send target + +- Return value:success or not +- Return value type: `Boolean` + +If `target` is `Player`, the packet will be sent to the specified player. +If `target` is `Entity`, the packet will be sent to players around the specified entity. +#### Send packet to all clients + +!!! warning +This function is only available in 0.19.0 and later. + +`pkt.sendToClients()` + +- Return value:success or not +- Return value type: `Boolean` + +#### Send packet to server + +!!! warning +This function is only available in 0.19.0 and later. + +`pkt.sendToServer()` + +- Return value:success or not +- Return value type: `Boolean` ## 🔌 Binary Stream Object API ### Create a binary stream object -[JavaScript] ```new BinaryStream()``` +[JavaScript] `new BinaryStream()` -[Lua] ```BinaryStream()``` +[Lua] `BinaryStream()` - Return value: Binary stream object - Return value type: `BinaryStream` @@ -70,72 +104,141 @@ Every binary stream object contains some member functions (member methods) that - Return value: success or not - Return value type: `Boolean` +#### Get binary stream read pointer + +!!! warning +This function is only available in 0.19.0 and later. + +`bs.getReadPointer()` + +- Return value: current read pointer +- Return value type: `Integer` + +#### Set binary stream read pointer +!!! warning +This function is only available in 0.19.0 and later. + +`bs.setReadPointer(pos)` + +- Parameters: + + - pos : `Integer` + New read pointer + +- Return value: success or not +- Return value type: `Boolean` + +#### Get binary stream data + +!!! warning +The optional parameter and `ByteBuffer` return value of this function are only available in 0.19.0 and later. + +`bs.getData([clear])` + +- Parameters: + + - clear : `Boolean` (Optional parameter) + Whether to clear stream data after reading. The default value is `true` + +- Return value: binary stream data +- Return value type: `ByteBuffer` + +Before 0.19.0, this function can only be used as `bs.getData()`. +At that time, it always cleared the stream data after reading, and the return value type was `String`. + +Because the old return value was `String`, in JavaScript it may be forcibly encoded as UTF-8, causing binary data corruption and incorrect data content. + +#### Set binary stream data + +!!! warning +This function is only available in 0.19.0 and later. + +`bs.setData(data)` + +- Parameters: + + - data : `ByteBuffer` + Binary stream data + +- Return value: success or not +- Return value type: `Boolean` #### Write to binary stream -`bs.writexxxx(value)` +`bs.writexxxx(value)` - Parameters: + - value : `NULL` Refer to the table below + For some numeric write functions, `String` is also accepted - Return value:success or not - Return value type: `Boolean` -| Available functions | Parameter Type | -| ------------------------------ | -------------- | -| writeBool | `Boolean` | -| writeByte | `Integer` | -| writeDouble | `Number` | -| writeFloat | `Float` | -| writeSignedBigEndianInt | `Number` | -| writeSignedInt | `Number` | -| writeSignedInt64 | `Number` | -| writeSignedShort | `Integer` | -| writeString | `String` | -| writeUnsignedChar | `Integer` | -| writeUnsignedInt | `Number` | -| writeUnsignedInt64 | `Number` | -| writeUnsignedShort | `Integer` | -| writeUnsignedVarInt | `Number` | -| writeUnsignedVarInt64 | `Number` | -| writeVarInt | `Number` | -| writeVarInt64 | `Number` | -| writeVec3 | `FloatPos` | -| writeBlockPos (Added in 0.9.5) | `BlockPos` | -| writeCompoundTag | `NbtCompound` | -| writeItem (Added in 0.9.5) | `Item` | - - +| Available functions | Parameter Type | +| -------------------------------------- | -------------------- | +| writeBool | `Boolean` | +| writeByte | `Integer` | +| writeBytes (Added in 0.19.0) | `ByteBuffer` | +| writeDouble | `Number` / `String` | +| writeFloat | `Float` / `String` | +| writeNormalizedFloat (Added in 0.19.0) | `Float` / `String` | +| writeSignedBigEndianInt | `Number` / `String` | +| writeSignedInt | `Number` / `String` | +| writeSignedInt64 | `Number` / `String` | +| writeSignedShort | `Integer` / `String` | +| writeString | `String` | +| writeUnsignedChar | `Integer` | +| writeUnsignedInt | `Number` / `String` | +| writeUnsignedInt64 | `Number` / `String` | +| writeUnsignedShort | `Integer` / `String` | +| writeUnsignedVarInt | `Number` / `String` | +| writeUnsignedVarInt64 | `Number` / `String` | +| writeVarInt | `Number` / `String` | +| writeVarInt64 | `Number` / `String` | +| writeVec3 | `FloatPos` | +| writeBlockPos (Added in 0.9.5) | `BlockPos` | +| writeCompoundTag | `NbtCompound` | +| writeItem (Added in 0.9.5) | `Item` | +| writeUuid (Added in 0.19.0) | `String` | #### Building packet from binary stream -`bs.createPacket(pktid)` +!!! warning +The optional parameter of this function is only available in 0.19.0 and later. + +`bs.createPacket(pktid[,raw])` - Parameters: + - pktid : `Integer` Packet ID + - raw : `Boolean` (Optional parameter) + Create raw network packet from current binary stream data. The default value is `false` - Return value:Packet object - Return value type: `Packet` - +Before 0.19.0, this function can only be used as `bs.createPacket(pktid)`. ### Dome Code Send TextPacket packets to a player + ```js -mc.listen("onChat",function(pl,msg){ - const bs = new BinaryStream() - var text = "LLSE Packet Test" - bs.reserve(text.length + 8) - bs.writeUnsignedChar(0) - bs.writeBool(true) - bs.writeString(text) - bs.writeString("") - bs.writeString("") - var pkt = bs.createPacket(9) - pl.sendPacket(pkt) -}) +mc.listen("onChat", (player, message) => { + const text = "LLSE Packet Test"; + const bs = new BinaryStream(); + bs.reserve(text.length + 8); + bs.writeBool(false); + bs.writeByte(/* TextPacketPayload::mBody::MessageOnly (Variant Index) */0); + bs.writeByte(/* TextPacketType::Raw (Enum) */0); + bs.writeString(text); + bs.writeString(""); // xuid + bs.writeString(""); // platformId + bs.writeString(""); // filtered message + bs.createPacket(9).sendTo(player); +}); ``` diff --git a/docs/apis/GameAPI/Packet.zh.md b/docs/apis/GameAPI/Packet.zh.md index dac8b728..793b395d 100644 --- a/docs/apis/GameAPI/Packet.zh.md +++ b/docs/apis/GameAPI/Packet.zh.md @@ -1,30 +1,26 @@ -# 🎓 数据包 API +# 🎓 数据包 API -下面这些对象与API为脚本提供了基本的BDS数据包接口。 +下面这些对象与 API 为脚本提供了基本的 BDS 数据包接口。 -温馨提示:此类API需要部分逆向基础,了解数据包结构(可通过参考Nukkit,PokcetMine,BDS逆向得知数据包结构)如出现客户端崩溃,为数据包结构错误,并非BUG。 - -文档不列出数据包ID与其结构,请自行查询。 +温馨提示:此类 API 需要部分逆向基础,了解数据包结构(可通过参考 Nukkit,PokcetMine,BDS 逆向得知数据包结构)如出现客户端崩溃,为数据包结构错误,并非 BUG。 +文档不列出数据包 ID 与其结构,请自行查询。 ## 目录 + - 🔉 [数据包对象 API](#-数据包对象-api) - 🔌 [二进制流对象 API](#-二进制流对象-api) - - ## 🔉 数据包对象 API 在脚本引擎中,使用「数据包对象」来获取数据包的相关信息。 ### 获取一个数据包对象 -#### 从API获取 - -调用某些**返回数据包对象**的函数,来获取到BDS给出的数据包对象 -详见 [二进制流对象](#-二进制流对象-api) - +#### 从 API 获取 +调用某些**返回数据包对象**的函数,来获取到 BDS 给出的数据包对象 +详见 [二进制流对象](#-二进制流对象-api) ### 数据包对象 - 函数 @@ -37,24 +33,62 @@ - 返回值:数据包名称 - 返回值类型: `String` - - -#### 获取数据包ID +#### 获取数据包 ID `pkt.getId()` -- 返回值:数据包ID +- 返回值:数据包 ID - 返回值类型: `Integer` +#### 发送数据包到指定目标 + +!!! warning +此函数仅在 0.19.0 及以后版本可用 + +`pkt.sendTo(pos)` +`pkt.sendTo(x,y,z,dimid)` +`pkt.sendTo(target)` + +- 参数: + + - pos : `IntPos` / `FloatPos` + 数据包发送目标所在坐标(或者使用 x, y, z, dimid 来确定目标位置) + - target : `Player` / `Entity` + 数据包发送目标 + +- 返回值:是否成功 +- 返回值类型: `Boolean` + +如果 `target` 是 `Player`,则数据包会发送到指定玩家。 +如果 `target` 是 `Entity`,则数据包会发送到指定实体周围的玩家。 +#### 发送数据包到所有客户端 + +!!! warning +此函数仅在 0.19.0 及以后版本可用 + +`pkt.sendToClients()` + +- 返回值:是否成功 +- 返回值类型: `Boolean` + +#### 发送数据包到服务端 + +!!! warning +此函数仅在 0.19.0 及以后版本可用 + +`pkt.sendToServer()` + +- 返回值:是否成功 +- 返回值类型: `Boolean` ## 🔌 二进制流对象 API ### 创建一个二进制流对象 -[JavaScript] ```new BinaryStream()``` +[JavaScript] `new BinaryStream()` -[Lua] ```BinaryStream()``` +[Lua] `BinaryStream()` - 返回值:二进制流对象 - 返回值类型: `BinaryStream` @@ -70,72 +104,141 @@ - 返回值:是否成功 - 返回值类型: `Boolean` +#### 获取二进制流读指针 + +!!! warning +此函数仅在 0.19.0 及以后版本可用 + +`bs.getReadPointer()` + +- 返回值:当前读指针 +- 返回值类型: `Integer` + +#### 设置二进制流读指针 +!!! warning +此函数仅在 0.19.0 及以后版本可用 + +`bs.setReadPointer(pos)` + +- 参数: + + - pos : `Integer` + 新的读指针 + +- 返回值:是否成功 +- 返回值类型: `Boolean` + +#### 获取二进制流数据 + +!!! warning +此函数的可选参数和 `ByteBuffer` 返回值仅在 0.19.0 及以后版本可用 + +`bs.getData([clear])` + +- 参数: + + - clear : `Boolean`(可选参数) + 获取后是否清空流数据。默认值为 `true` + +- 返回值:二进制流数据 +- 返回值类型: `ByteBuffer` + +在 0.19.0 之前,此函数只能使用 `bs.getData()` 形式调用。 +当时它在获取后总是会清空流数据,且返回值类型为 `String`。 + +由于旧版返回的是 `String`,在 JavaScript 中可能会被强制按 UTF-8 编码处理,导致二进制数据损坏,拿到的数据不正确。 + +#### 设置二进制流数据 + +!!! warning +此函数仅在 0.19.0 及以后版本可用 + +`bs.setData(data)` + +- 参数: + + - data : `ByteBuffer` + 二进制流数据 + +- 返回值:是否成功 +- 返回值类型: `Boolean` #### 写入二进制流 -`bs.writexxxx(value)` +`bs.writexxxx(value)` - 参数: + - value : `NULL` 参考下面表格 + 部分数值写入函数也允许传入 `String` - 返回值:是否成功 - 返回值类型: `Boolean` -| 可用函数 | 参数类型 | -| ---------------------------- | ------------- | -| writeBool | `Boolean` | -| writeByte | `Integer` | -| writeDouble | `Number` | -| writeFloat | `Float` | -| writeSignedBigEndianInt | `Number` | -| writeSignedInt | `Number` | -| writeSignedInt64 | `Number` | -| writeSignedShort | `Integer` | -| writeString | `String` | -| writeUnsignedChar | `Integer` | -| writeUnsignedInt | `Number` | -| writeUnsignedInt64 | `Number` | -| writeUnsignedShort | `Integer` | -| writeUnsignedVarInt | `Number` | -| writeUnsignedVarInt64 | `Number` | -| writeVarInt | `Number` | -| writeVarInt64 | `Number` | -| writeVec3 | `FloatPos` | -| writeBlockPos (0.9.5 时加入) | `BlockPos` | -| writeCompoundTag | `NbtCompound` | -| writeItem (0.9.5 时加入) | `Item` | - - +| 可用函数 | 参数类型 | +| ------------------------------------ | -------------------- | +| writeBool | `Boolean` | +| writeByte | `Integer` | +| writeBytes (0.19.0 时加入) | `ByteBuffer` | +| writeDouble | `Number` / `String` | +| writeFloat | `Float` / `String` | +| writeNormalizedFloat (0.19.0 时加入) | `Float` / `String` | +| writeSignedBigEndianInt | `Number` / `String` | +| writeSignedInt | `Number` / `String` | +| writeSignedInt64 | `Number` / `String` | +| writeSignedShort | `Integer` / `String` | +| writeString | `String` | +| writeUnsignedChar | `Integer` | +| writeUnsignedInt | `Number` / `String` | +| writeUnsignedInt64 | `Number` / `String` | +| writeUnsignedShort | `Integer` / `String` | +| writeUnsignedVarInt | `Number` / `String` | +| writeUnsignedVarInt64 | `Number` / `String` | +| writeVarInt | `Number` / `String` | +| writeVarInt64 | `Number` / `String` | +| writeVec3 | `FloatPos` | +| writeBlockPos (0.9.5 时加入) | `BlockPos` | +| writeCompoundTag | `NbtCompound` | +| writeItem (0.9.5 时加入) | `Item` | +| writeUuid (0.19.0 时加入) | `String` | #### 通过二进制流构建数据包 -`bs.createPacket(pktid)` +!!! warning +此函数的可选参数仅在 0.19.0 及以后版本可用 + +`bs.createPacket(pktid[,raw])` - 参数: + - pktid : `Integer` - 数据包ID + 数据包 ID + - raw : `Boolean`(可选参数) + 是否从当前二进制流数据创建原始网络数据包。默认值为 `false` - 返回值:数据包对象 - 返回值类型: `Packet` - +在 0.19.0 之前,此函数只能使用 `bs.createPacket(pktid)` 形式调用。 ### 演示代码 -向一个玩家发送TextPacket数据包 +向一个玩家发送 TextPacket 数据包 + ```js -mc.listen("onChat",function(pl,msg){ - const bs = new BinaryStream() - var text = "LLSE Packet Test" - bs.reserve(text.length + 8) - bs.writeUnsignedChar(0) - bs.writeBool(true) - bs.writeString(text) - bs.writeString("") - bs.writeString("") - var pkt = bs.createPacket(9) - pl.sendPacket(pkt) +mc.listen("onChat", (player, message) => { + const text = "LLSE Packet Test"; + const bs = new BinaryStream(); + bs.reserve(text.length + 8); + bs.writeBool(false); + bs.writeByte(/* TextPacketPayload::mBody::MessageOnly (Variant Index) */0); + bs.writeByte(/* TextPacketType::Raw (Enum) */0); + bs.writeString(text); + bs.writeString(""); // xuid + bs.writeString(""); // platformId + bs.writeString(""); // filtered message + bs.createPacket(9).sendTo(player); }); ``` diff --git a/docs/apis/GameAPI/Server.md b/docs/apis/GameAPI/Server.md index aea886fe..92395cc4 100644 --- a/docs/apis/GameAPI/Server.md +++ b/docs/apis/GameAPI/Server.md @@ -20,6 +20,18 @@ The following APIs provide interfaces for customizing some server settings: +### Get Server Motd String + +!!! warning +This function is only available in 0.19.0 and later. + +`mc.getMotd()` + +- Return value: Current server Motd string +- Return value type: `String` + + + ### Set Server Motd String `mc.setMotd(motd)` @@ -44,6 +56,33 @@ The following APIs provide interfaces for customizing some server settings: +### Get Online Player Count + +!!! warning +This function is only available in 0.19.0 and later. + +`mc.getOnlinePlayerNum([ignoreSimulatedPlayer])` + +- Parameters: + - ignoreSimulatedPlayer : `Boolean` = `false` + Whether to ignore simulated players +- Return value: Current number of online players +- Return value type: `Number` + + + +### Get Server Maximum Player Count + +!!! warning +This function is only available in 0.19.0 and later. + +`mc.getMaxNumPlayers()` + +- Return value: Current maximum number of players on the server +- Return value type: `Number` + + + ### Get Sever time `mc.getTime(TimeID)` @@ -90,3 +129,33 @@ Among them, daytime is the number of game ticks since dawn, gametime is the age - Return value type: `Boolean` + +### Get Dimension ID + +!!! warning +This function is only available in 0.19.0 and later. + +`mc.getDimensionId(name)` + +- Parameters: + - name : `String` + Dimension name +- Return value: Dimension ID corresponding to the dimension name, or `null` if the dimension name is invalid +- Return value type: `Number` + + + +### Get Dimension Name + +!!! warning +This function is only available in 0.19.0 and later. + +`mc.getDimensionName(dimid)` + +- Parameters: + - dimid : `Integer` + Dimension ID +- Return value: Dimension name corresponding to the dimension ID, or `null` if the dimension ID is invalid +- Return value type: `String` + + diff --git a/docs/apis/GameAPI/Server.zh.md b/docs/apis/GameAPI/Server.zh.md index 4f0a1b49..52908743 100644 --- a/docs/apis/GameAPI/Server.zh.md +++ b/docs/apis/GameAPI/Server.zh.md @@ -20,6 +20,18 @@ +### 获取服务器MOTD字符串 + +!!! warning + 此函数仅在0.19.0及以后版本可用 + +`mc.getMotd()` + +- 返回值:当前服务器MOTD字符串 +- 返回值类型:`String` + + + ### 设置服务器MOTD字符串 `mc.setMotd(motd)` @@ -44,6 +56,33 @@ +### 获取在线玩家数量 + +!!! warning + 此函数仅在0.19.0及以后版本可用 + +`mc.getOnlinePlayerNum([ignoreSimulatedPlayer])` + +- 参数: + - ignoreSimulatedPlayer : `Boolean` = `false` + 是否忽略模拟玩家 +- 返回值:当前在线玩家数量 +- 返回值类型:`Number` + + + +### 获取服务器最大玩家数 + +!!! warning + 此函数仅在0.19.0及以后版本可用 + +`mc.getMaxNumPlayers()` + +- 返回值:当前服务器最大玩家数 +- 返回值类型:`Number` + + + ### 获取服务器游戏时间 `mc.getTime(TimeID)` @@ -90,3 +129,33 @@ - 返回值类型:`Boolean` + +### 获取维度ID + +!!! warning + 此函数仅在0.19.0及以后版本可用 + +`mc.getDimensionId(name)` + +- 参数: + - name : `String` + 维度名称 +- 返回值:对应维度名称的维度ID,若维度名称无效则返回`null` +- 返回值类型:`Number` + + + +### 获取维度名称 + +!!! warning + 此函数仅在0.19.0及以后版本可用 + +`mc.getDimensionName(dimid)` + +- 参数: + - dimid : `Integer` + 维度ID +- 返回值:对应维度ID的维度名称,若维度ID无效则返回`null` +- 返回值类型:`String` + + diff --git a/src/legacy/api/CommandAPI.cpp b/src/legacy/api/CommandAPI.cpp index 511b3850..05cd1453 100644 --- a/src/legacy/api/CommandAPI.cpp +++ b/src/legacy/api/CommandAPI.cpp @@ -170,6 +170,9 @@ Local convertResult(ParamStorageType const& result, CommandOrigin const& if (result.hold(ParamKind::Kind::String)) { return String::newString(std::get(result.value())); } + if (result.hold(ParamKind::Kind::Dimension)) { + return Number::newNumber(std::get(result.value()).id); + } return {}; } diff --git a/src/legacy/api/McAPI.cpp b/src/legacy/api/McAPI.cpp index edb03ce4..7f276b80 100644 --- a/src/legacy/api/McAPI.cpp +++ b/src/legacy/api/McAPI.cpp @@ -26,6 +26,7 @@ ClassDefine McClassBuilder = defineClass("mc") .function("newSimpleForm", &McClass::newSimpleForm) .function("newCustomForm", &McClass::newCustomForm) .function("regConsoleCmd", &McClass::regConsoleCmd) + .function("getMotd", &McClass::getMotd) .function("setMotd", &McClass::setMotd) .function("sendCmdOutput", &McClass::sendCmdOutput) .function("newIntPos", &McClass::newIntPos) @@ -52,6 +53,10 @@ ClassDefine McClassBuilder = defineClass("mc") .function("setTime", &McClass::setTime) .function("getWeather", &McClass::getWeather) .function("setWeather", &McClass::setWeather) + .function("getDimensionId", &McClass::getDimensionId) + .function("getDimensionName", &McClass::getDimensionName) + .function("getOnlinePlayerNum", &McClass::getOnlinePlayerNum) + .function("getMaxNumPlayers", &McClass::getMaxNumPlayers) // For Compatibility .function("getAllScoreObjective", &McClass::getAllScoreObjectives) .function("getDisplayObjectives", &McClass::getDisplayObjective) diff --git a/src/legacy/api/McAPI.h b/src/legacy/api/McAPI.h index db54356a..b506325d 100644 --- a/src/legacy/api/McAPI.h +++ b/src/legacy/api/McAPI.h @@ -35,10 +35,13 @@ class McClass { static Local newCustomForm(Arguments const& args); static Local regConsoleCmd(Arguments const& args); + static Local getMotd(Arguments const& args); static Local setMotd(Arguments const& args); static Local sendCmdOutput(Arguments const& args); static Local crashBDS(Arguments const& args); + static Local getOnlinePlayerNum(Arguments const& args); + static Local getMaxNumPlayers(Arguments const& args); static Local setMaxNumPlayers(Arguments const& args); static Local newIntPos(Arguments const& args); @@ -69,5 +72,8 @@ class McClass { static Local setTime(Arguments const& args); static Local getWeather(Arguments const& args); static Local setWeather(Arguments const& args); + + static Local getDimensionId(Arguments const& args); + static Local getDimensionName(Arguments const& args); }; extern ClassDefine<> McClassBuilder; diff --git a/src/legacy/api/PacketAPI.cpp b/src/legacy/api/PacketAPI.cpp index 9380143f..7fa76dea 100644 --- a/src/legacy/api/PacketAPI.cpp +++ b/src/legacy/api/PacketAPI.cpp @@ -2,8 +2,11 @@ #include "legacy/api/APIHelp.h" #include "legacy/api/BaseAPI.h" +#include "legacy/api/EntityAPI.h" #include "legacy/api/ItemAPI.h" #include "legacy/api/NbtAPI.h" +#include "legacy/api/PlayerAPI.h" +#include "lse/api/NetworkPacket.h" #include "lse/api/helper/ItemStackSerializerHelpers.h" #include "mc/deps/core/utility/BinaryStream.h" #include "mc/network/MinecraftPackets.h" @@ -16,25 +19,33 @@ ClassDefine PacketClassBuilder = defineClass("LLSE_Pac .constructor(nullptr) .instanceFunction("getName", &PacketClass::getName) .instanceFunction("getId", &PacketClass::getId) + .instanceFunction("sendTo", &PacketClass::sendTo) + .instanceFunction("sendToClients", &PacketClass::sendToClients) + .instanceFunction("sendToServer", &PacketClass::sendToServer) .build(); ClassDefine BinaryStreamClassBuilder = defineClass("BinaryStream") .constructor(&BinaryStreamClass::constructor) - .instanceFunction("getData", &BinaryStreamClass::getAndReleaseData) + .instanceFunction("getReadPointer", &BinaryStreamClass::getReadPointer) + .instanceFunction("setReadPointer", &BinaryStreamClass::setReadPointer) + .instanceFunction("getData", &BinaryStreamClass::getData) + .instanceFunction("setData", &BinaryStreamClass::setData) .instanceFunction("reset", &BinaryStreamClass::reset) .instanceFunction("reserve", &BinaryStreamClass::reserve) .instanceFunction("writeBool", &BinaryStreamClass::writeBool) .instanceFunction("writeByte", &BinaryStreamClass::writeByte) + .instanceFunction("writeBytes", &BinaryStreamClass::writeBytes) .instanceFunction("writeDouble", &BinaryStreamClass::writeDouble) .instanceFunction("writeFloat", &BinaryStreamClass::writeFloat) + .instanceFunction("writeNormalizedFloat", &BinaryStreamClass::writeNormalizedFloat) .instanceFunction("writeSignedBigEndianInt", &BinaryStreamClass::writeSignedBigEndianInt) .instanceFunction("writeSignedInt", &BinaryStreamClass::writeSignedInt) .instanceFunction("writeSignedInt64", &BinaryStreamClass::writeSignedInt64) .instanceFunction("writeSignedShort", &BinaryStreamClass::writeSignedShort) .instanceFunction("writeString", &BinaryStreamClass::writeString) - .instanceFunction("writeUnsignedChar", &BinaryStreamClass::writeUnsignedChar) + .instanceFunction("writeUnsignedChar", &BinaryStreamClass::writeByte) .instanceFunction("writeUnsignedInt", &BinaryStreamClass::writeUnsignedInt) .instanceFunction("writeUnsignedInt64", &BinaryStreamClass::writeUnsignedInt64) .instanceFunction("writeUnsignedShort", &BinaryStreamClass::writeUnsignedShort) @@ -46,6 +57,7 @@ ClassDefine BinaryStreamClassBuilder = .instanceFunction("writeBlockPos", &BinaryStreamClass::writeBlockPos) .instanceFunction("writeCompoundTag", &BinaryStreamClass::writeCompoundTag) .instanceFunction("writeItem", &BinaryStreamClass::writeItem) + .instanceFunction("writeUuid", &BinaryStreamClass::writeUuid) .instanceFunction("createPacket", &BinaryStreamClass::createPacket) .build(); @@ -89,189 +101,144 @@ Local PacketClass::getId() { CATCH_AND_THROW } -//////////////////// BinaryStream Classes //////////////////// - -BinaryStreamClass::BinaryStreamClass(std::shared_ptr const& bs) -: ScriptClass(ConstructFromCpp{}) { - set(bs); -} - -// generating function -Local BinaryStreamClass::newBinaryStream() { - auto out = new BinaryStreamClass(std::make_shared()); - return out->getScriptObject(); -} - -// member function - -Local BinaryStreamClass::getAndReleaseData() { +Local PacketClass::sendTo(Arguments const& args) { + CHECK_ARGS_COUNT(args, 1); try { - auto stream = get(); - if (!stream) { + std::shared_ptr pkt = get(); + if (!pkt) { return {}; } - std::string data; - stream->mBuffer.swap(data); - return String::newString(data); - } - CATCH_AND_THROW -} -BinaryStreamClass* BinaryStreamClass::constructor(Arguments const& args) { - try { - return new BinaryStreamClass(args.thiz()); - } - CATCH_AND_THROW -} - -Local BinaryStreamClass::reset() { - try { - auto stream = get(); - if (!stream) { - return {}; + if (IsInstanceOf(args[0])) { + auto* player = PlayerClass::extract(args[0]); + pkt->sendTo(*player); + } else if (IsInstanceOf(args[0])) { + auto* entity = EntityClass::extract(args[0]); + pkt->sendTo(*entity); + } else if (IsInstanceOf(args[0])) { + auto* pos = IntPos::extractPos(args[0]); + pkt->sendTo(pos->getBlockPos(), pos->getDimensionId()); + } else if (IsInstanceOf(args[0])) { + auto* pos = FloatPos::extractPos(args[0]); + pkt->sendTo(pos->getVec3(), pos->getDimensionId()); + } else if (args.size() >= 4 && std::ranges::all_of(std::views::iota(0ull, 4ull), [&](auto index) { + return args[index].getKind() == ValueKind::kNumber; + })) { + pkt->sendTo( + BlockPos{args[0].asNumber().toInt32(), args[1].asNumber().toInt32(), args[2].asNumber().toInt32()}, + args[3].asNumber().toInt32() + ); + } else { + throw WrongArgTypeException(__FUNCTION__); } - stream->mBuffer.clear(); return Boolean::newBoolean(true); } CATCH_AND_THROW } -Local BinaryStreamClass::reserve(Arguments const& args) { +Local PacketClass::sendToClients(Arguments const& args) { CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); try { - return Boolean::newBoolean(true); - } - CATCH_AND_THROW -} - -Local BinaryStreamClass::writeBool(Arguments const& args) { - CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kBoolean); - try { - auto stream = get(); - if (!stream) { + std::shared_ptr pkt = get(); + if (!pkt) { return {}; } - stream->writeBool(args[0].asBoolean().value(), nullptr, nullptr); + + pkt->sendToClients(); + return Boolean::newBoolean(true); } CATCH_AND_THROW } -Local BinaryStreamClass::writeByte(Arguments const& args) { +Local PacketClass::sendToServer(Arguments const& args) { CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); try { - auto stream = get(); - if (!stream) { + std::shared_ptr pkt = get(); + if (!pkt) { return {}; } - stream->writeByte(args[0].asNumber().toInt32(), nullptr, nullptr); + + pkt->sendToServer(); + return Boolean::newBoolean(true); } CATCH_AND_THROW } -Local BinaryStreamClass::writeDouble(Arguments const& args) { - CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); - try { - auto stream = get(); - if (!stream) { - return {}; - } - stream->writeDouble(args[0].asNumber().toDouble(), nullptr, nullptr); - return Boolean::newBoolean(true); - } - CATCH_AND_THROW +//////////////////// BinaryStream Classes //////////////////// + +BinaryStreamClass::BinaryStreamClass(std::shared_ptr const& bs) +: ScriptClass(ConstructFromCpp{}) { + set(bs); } -Local BinaryStreamClass::writeFloat(Arguments const& args) { - CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); - try { - auto stream = get(); - if (!stream) { - return {}; - } - stream->writeFloat(args[0].asNumber().toFloat(), nullptr, nullptr); - return Boolean::newBoolean(true); - } - CATCH_AND_THROW +// generating function +Local BinaryStreamClass::newBinaryStream() { + auto out = new BinaryStreamClass(std::make_shared()); + return out->getScriptObject(); } -Local BinaryStreamClass::writeSignedBigEndianInt(Arguments const& args) { - CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); +// member function + +Local BinaryStreamClass::getData(Arguments const& args) { + if (args.size() >= 1) CHECK_ARG_TYPE(args[0], ValueKind::kBoolean); try { + auto stream = get(); if (!stream) { return {}; } - stream->writeSignedBigEndianInt(args[0].asNumber().toInt32(), nullptr, nullptr); - return Boolean::newBoolean(true); - } - CATCH_AND_THROW -} -Local BinaryStreamClass::writeSignedInt(Arguments const& args) { - CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); - try { - auto stream = get(); - if (!stream) { - return {}; + auto result = ByteBuffer::newByteBuffer(stream->mBuffer.data(), stream->mBuffer.size()); + if (args.size() < 1 || args[0].asBoolean().value()) { + stream->mBuffer.clear(); + stream->mView = stream->mBuffer; + stream->mReadPointer = 0; } - stream->writeSignedInt(args[0].asNumber().toInt32(), nullptr, nullptr); - return Boolean::newBoolean(true); + return result; } CATCH_AND_THROW } -Local BinaryStreamClass::writeSignedInt64(Arguments const& args) { - CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); +Local BinaryStreamClass::setData(Arguments const& args) { + if (args.size() >= 1) CHECK_ARG_TYPE(args[0], ValueKind::kByteBuffer); try { + auto stream = get(); if (!stream) { return {}; } - stream->writeSignedInt64(args[0].asNumber().toInt64(), nullptr, nullptr); + + auto buffer = args[0].asByteBuffer(); + stream->mBuffer = std::string_view{reinterpret_cast(buffer.getRawBytes()), buffer.byteLength()}; + stream->mView = stream->mBuffer; + stream->mReadPointer = 0; + return Boolean::newBoolean(true); } CATCH_AND_THROW } -Local BinaryStreamClass::writeSignedShort(Arguments const& args) { - CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); +BinaryStreamClass* BinaryStreamClass::constructor(Arguments const& args) { try { - auto stream = get(); - if (!stream) { - return {}; - } - stream->writeSignedShort(args[0].asNumber().toInt32(), nullptr, nullptr); - return Boolean::newBoolean(true); + return new BinaryStreamClass(args.thiz()); } CATCH_AND_THROW } -Local BinaryStreamClass::writeString(Arguments const& args) { - CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kString); +Local BinaryStreamClass::getReadPointer(Arguments const& args) { try { auto stream = get(); if (!stream) { return {}; } - stream->writeString(args[0].asString().toString(), nullptr, nullptr); - return Boolean::newBoolean(true); + return Number::newNumber(static_cast(stream->mReadPointer)); } CATCH_AND_THROW } -Local BinaryStreamClass::writeUnsignedChar(Arguments const& args) { +Local BinaryStreamClass::setReadPointer(Arguments const& args) { CHECK_ARGS_COUNT(args, 1); CHECK_ARG_TYPE(args[0], ValueKind::kNumber); try { @@ -279,27 +246,27 @@ Local BinaryStreamClass::writeUnsignedChar(Arguments const& args) { if (!stream) { return {}; } - stream->writeByte(args[0].asNumber().toInt32(), nullptr, nullptr); + stream->mReadPointer = args[0].asNumber().toInt64(); return Boolean::newBoolean(true); } CATCH_AND_THROW } -Local BinaryStreamClass::writeUnsignedInt(Arguments const& args) { - CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); +Local BinaryStreamClass::reset() { try { auto stream = get(); if (!stream) { return {}; } - stream->writeUnsignedInt(static_cast(args[0].asNumber().toInt32()), nullptr, nullptr); + stream->mBuffer.clear(); + stream->mView = stream->mBuffer; + stream->mReadPointer = 0; return Boolean::newBoolean(true); } CATCH_AND_THROW } -Local BinaryStreamClass::writeUnsignedInt64(Arguments const& args) { +Local BinaryStreamClass::reserve(Arguments const& args) { CHECK_ARGS_COUNT(args, 1); CHECK_ARG_TYPE(args[0], ValueKind::kNumber); try { @@ -307,27 +274,27 @@ Local BinaryStreamClass::writeUnsignedInt64(Arguments const& args) { if (!stream) { return {}; } - stream->writeUnsignedInt64(static_cast(args[0].asNumber().toInt64()), nullptr, nullptr); + stream->mBuffer.reserve(args[0].asNumber().toInt32()); return Boolean::newBoolean(true); } CATCH_AND_THROW } -Local BinaryStreamClass::writeUnsignedShort(Arguments const& args) { +Local BinaryStreamClass::writeBool(Arguments const& args) { CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); + CHECK_ARG_TYPE(args[0], ValueKind::kBoolean); try { auto stream = get(); if (!stream) { return {}; } - stream->writeUnsignedShort(static_cast(args[0].asNumber().toInt32()), nullptr, nullptr); + stream->writeBool(args[0].asBoolean().value(), nullptr, nullptr); return Boolean::newBoolean(true); } CATCH_AND_THROW } -Local BinaryStreamClass::writeUnsignedVarInt(Arguments const& args) { +Local BinaryStreamClass::writeByte(Arguments const& args) { CHECK_ARGS_COUNT(args, 1); CHECK_ARG_TYPE(args[0], ValueKind::kNumber); try { @@ -335,53 +302,90 @@ Local BinaryStreamClass::writeUnsignedVarInt(Arguments const& args) { if (!stream) { return {}; } - stream->writeUnsignedVarInt(static_cast(args[0].asNumber().toInt32()), nullptr, nullptr); + stream->writeByte(static_cast(args[0].asNumber().toInt32()), nullptr, nullptr); return Boolean::newBoolean(true); } CATCH_AND_THROW } -Local BinaryStreamClass::writeUnsignedVarInt64(Arguments const& args) { +Local BinaryStreamClass::writeBytes(Arguments const& args) { CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); + CHECK_ARG_TYPE(args[0], ValueKind::kByteBuffer); try { auto stream = get(); if (!stream) { return {}; } - stream->writeUnsignedVarInt64(static_cast(args[0].asNumber().toInt64()), nullptr, nullptr); + auto buffer = args[0].asByteBuffer(); + stream->mBuffer.append(reinterpret_cast(buffer.getRawBytes()), buffer.byteLength()); + stream->mView = stream->mBuffer; return Boolean::newBoolean(true); } CATCH_AND_THROW } -Local BinaryStreamClass::writeVarInt(Arguments const& args) { +Local BinaryStreamClass::writeString(Arguments const& args) { CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); + CHECK_ARG_TYPE(args[0], ValueKind::kString); try { auto stream = get(); if (!stream) { return {}; } - stream->writeVarInt(args[0].asNumber().toInt32(), nullptr, nullptr); + stream->writeString(args[0].asString().toString(), nullptr, nullptr); return Boolean::newBoolean(true); } CATCH_AND_THROW } -Local BinaryStreamClass::writeVarInt64(Arguments const& args) { - CHECK_ARGS_COUNT(args, 1); - CHECK_ARG_TYPE(args[0], ValueKind::kNumber); - try { - auto stream = get(); - if (!stream) { - return {}; - } - stream->writeVarInt64(args[0].asNumber().toInt64(), nullptr, nullptr); - return Boolean::newBoolean(true); +#define WRITE_MACRO(FUNC_NAME, INDEX) \ + Local BinaryStreamClass::FUNC_NAME(Arguments const& args) { \ + CHECK_ARGS_COUNT(args, 1); \ + CHECK_ARG_TYPE(args[0], ValueKind::kNumber && args[0].getKind() != ValueKind::kString); \ + try { \ + auto stream = get(); \ + if (!stream) { \ + return {}; \ + } \ + using T = ll::traits::function_traits::arg<0>; \ + T value{}; \ + if (args[0].isNumber()) { \ + value = static_cast(args[0].asNumber().toInt64()); \ + } else if (args[0].isString()) { \ + if (auto res = ll::string_utils::svtonum(args[0].asString().toString(), nullptr, INDEX); res) { \ + value = res.value(); \ + } else { \ + throw WrongArgTypeException(__FUNCTION__); \ + } \ + } \ + stream->FUNC_NAME(value, nullptr, nullptr); \ + return Boolean::newBoolean(true); \ + } \ + CATCH_AND_THROW \ } - CATCH_AND_THROW -} + +#define WRITE_INTEGER_MACRO(FUNC_NAME) WRITE_MACRO(FUNC_NAME, 10) +#define WRITE_FLOAT_MACRO(FUNC_NAME) WRITE_MACRO(FUNC_NAME, std::chars_format::general) + +WRITE_INTEGER_MACRO(writeSignedBigEndianInt); +WRITE_INTEGER_MACRO(writeSignedInt); +WRITE_INTEGER_MACRO(writeSignedInt64); +WRITE_INTEGER_MACRO(writeSignedShort); +WRITE_INTEGER_MACRO(writeUnsignedInt); +WRITE_INTEGER_MACRO(writeUnsignedInt64); +WRITE_INTEGER_MACRO(writeUnsignedShort); +WRITE_INTEGER_MACRO(writeUnsignedVarInt); +WRITE_INTEGER_MACRO(writeUnsignedVarInt64); +WRITE_INTEGER_MACRO(writeVarInt); +WRITE_INTEGER_MACRO(writeVarInt64); + +WRITE_FLOAT_MACRO(writeFloat) +WRITE_FLOAT_MACRO(writeDouble) +WRITE_FLOAT_MACRO(writeNormalizedFloat) + +#undef WRITE_MACRO +#undef WRITE_INTEGER_MACRO +#undef WRITE_FLOAT_MACRO Local BinaryStreamClass::writeVec3(Arguments const& args) { CHECK_ARGS_COUNT(args, 1); @@ -414,7 +418,7 @@ Local BinaryStreamClass::writeBlockPos(Arguments const& args) { } IntPos* posObj = IntPos::extractPos(args[0]); stream->writeVarInt(posObj->getBlockPos().x, nullptr, nullptr); - stream->writeUnsignedVarInt(posObj->getBlockPos().y, nullptr, nullptr); + stream->writeVarInt(posObj->getBlockPos().y, nullptr, nullptr); stream->writeVarInt(posObj->getBlockPos().z, nullptr, nullptr); return Boolean::newBoolean(true); } @@ -455,15 +459,49 @@ Local BinaryStreamClass::writeItem(Arguments const& args) { CATCH_AND_THROW } +Local BinaryStreamClass::writeUuid(Arguments const& args) { + CHECK_ARGS_COUNT(args, 1); + CHECK_ARG_TYPE(args[0], ValueKind::kString); + auto uuidStr = args[0].asString().toString(); + if (!mce::UUID::canParse(uuidStr)) { + throw Exception(fmt ::format("Invalid UUID: {}", uuidStr)); + } + + try { + auto stream = get(); + if (!stream) { + return {}; + } + + auto uuid = mce::UUID::fromString(uuidStr); + stream->writeUnsignedInt64(uuid.a, nullptr, nullptr); + stream->writeUnsignedInt64(uuid.b, nullptr, nullptr); + return Boolean::newBoolean(true); + } + CATCH_AND_THROW +} + Local BinaryStreamClass::createPacket(Arguments const& args) { CHECK_ARGS_COUNT(args, 1); + if (args.size() >= 2) { + CHECK_ARG_TYPE(args[1], ValueKind::kBoolean); + } try { auto stream = get(); if (!stream) { return {}; } - auto pkt = MinecraftPackets::createPacket(static_cast(args[0].asNumber().toInt32())); - pkt->read(*stream); + std::shared_ptr pkt = + args.size() < 2 || !args[1].asBoolean().value() + ? MinecraftPackets::createPacket(static_cast(args[0].asNumber().toInt32())) + : std::make_shared( + static_cast(args[0].asNumber().toInt32()), + "" + ); + + if (auto res = pkt->read(*stream); !res) { + throw Exception(fmt ::format("{}\nfunction: {}", res.error().code().message(), __func__)); + } return PacketClass::newPacket(pkt); } CATCH_AND_THROW diff --git a/src/legacy/api/PacketAPI.h b/src/legacy/api/PacketAPI.h index 3b711cb7..a814aa51 100644 --- a/src/legacy/api/PacketAPI.h +++ b/src/legacy/api/PacketAPI.h @@ -22,6 +22,10 @@ class PacketClass : public ScriptClass { Local getId(); Local getName(); + + Local sendTo(Arguments const& args); + Local sendToClients(Arguments const& args); + Local sendToServer(Arguments const& args); }; extern ClassDefine PacketClassBuilder; @@ -42,20 +46,24 @@ class BinaryStreamClass : public ScriptClass { static Local newBinaryStream(); static BinaryStreamClass* constructor(Arguments const& args); - Local getAndReleaseData(); + Local getReadPointer(Arguments const& args); + Local setReadPointer(Arguments const& args); + Local getData(Arguments const& args); + Local setData(Arguments const& args); Local reset(); Local reserve(Arguments const& args); Local writeBool(Arguments const& args); Local writeByte(Arguments const& args); + Local writeBytes(Arguments const& args); Local writeDouble(Arguments const& args); Local writeFloat(Arguments const& args); + Local writeNormalizedFloat(Arguments const& args); Local writeSignedBigEndianInt(Arguments const& args); Local writeSignedInt(Arguments const& args); Local writeSignedInt64(Arguments const& args); Local writeSignedShort(Arguments const& args); Local writeString(Arguments const& args); - Local writeUnsignedChar(Arguments const& args); Local writeUnsignedInt(Arguments const& args); Local writeUnsignedInt64(Arguments const& args); Local writeUnsignedShort(Arguments const& args); @@ -67,6 +75,7 @@ class BinaryStreamClass : public ScriptClass { Local writeBlockPos(Arguments const& args); Local writeCompoundTag(Arguments const& args); Local writeItem(Arguments const& args); + Local writeUuid(Arguments const& args); Local createPacket(Arguments const& args); }; diff --git a/src/legacy/api/PlayerAPI.cpp b/src/legacy/api/PlayerAPI.cpp index f94eeb01..d9af6297 100644 --- a/src/legacy/api/PlayerAPI.cpp +++ b/src/legacy/api/PlayerAPI.cpp @@ -2404,7 +2404,7 @@ Local PlayerClass::setBossBar(Arguments const& args) const { bs.writeUnsignedVarInt(0, nullptr, nullptr); // Links bs.writeUnsignedVarInt(0, nullptr, nullptr); - auto addPkt = lse::api::NetworkPacket(std::move(bs.mBuffer)); + auto addPkt = lse::api::NetworkPacket(MinecraftPacketIds::AddActor, std::move(bs.mBuffer)); BossBarColor color = static_cast(args[3].asNumber().toInt32()); auto pkt = diff --git a/src/legacy/api/ServerAPI.cpp b/src/legacy/api/ServerAPI.cpp index 2c416e1d..221b31e1 100644 --- a/src/legacy/api/ServerAPI.cpp +++ b/src/legacy/api/ServerAPI.cpp @@ -8,10 +8,18 @@ #include "mc/common/SharedConstants.h" #include "mc/network/ServerNetworkHandler.h" #include "mc/network/packet/SetTimePacket.h" +#include "mc/world/level/dimension/VanillaDimensions.h" #include "mc/world/level/storage/LevelData.h" #include +Local McClass::getMotd(Arguments const& args) { + try { + return String::newString(ll::service::getServerNetworkHandler().and_then(&ServerNetworkHandler::mServerName)); + } + CATCH_AND_THROW +} + Local McClass::setMotd(Arguments const& args) { CHECK_ARGS_COUNT(args, 1) CHECK_ARG_TYPE(args[0], ValueKind::kString) @@ -24,6 +32,30 @@ Local McClass::setMotd(Arguments const& args) { Local McClass::crashBDS(Arguments const&) { return Boolean::newBoolean(false); } +Local McClass::getOnlinePlayerNum(Arguments const& args) { + if (args.size() >= 1) CHECK_ARG_TYPE(args[0], ValueKind::kBoolean); + + try { + if (args.size() >= 1 && args[0].asBoolean().value()) { + return Number::newNumber(ll::service::getServerNetworkHandler().and_then([](auto& handler) { + return static_cast(handler.mClients->size()); + })); + } else { + return Number::newNumber(ll::service::getLevel().and_then(&Level::getUserCount)); + } + } + CATCH_AND_THROW +} + +Local McClass::getMaxNumPlayers(Arguments const& args) { + try { + return Number::newNumber( + ll::service::getServerNetworkHandler().and_then(&ServerNetworkHandler::mMaxNumPlayers) + ); + } + CATCH_AND_THROW +} + Local McClass::setMaxNumPlayers(Arguments const& args) { CHECK_ARGS_COUNT(args, 1) CHECK_ARG_TYPE(args[0], ValueKind::kNumber) @@ -128,3 +160,35 @@ Local McClass::setWeather(Arguments const& args) { return Boolean::newBoolean(true); } + +Local McClass::getDimensionId(Arguments const& args) { + CHECK_ARGS_COUNT(args, 1) + CHECK_ARG_TYPE(args[0], ValueKind::kString) + + try { + if (auto dimid = VanillaDimensions::fromString(args[0].asString().toString()); + dimid != VanillaDimensions::Undefined()) { + return Number::newNumber(dimid); + } + return {}; + } + CATCH_AND_THROW + + return Boolean::newBoolean(true); +} + +Local McClass::getDimensionName(Arguments const& args) { + CHECK_ARGS_COUNT(args, 1) + CHECK_ARG_TYPE(args[0], ValueKind::kNumber) + + try { + auto& map = VanillaDimensions::DimensionMap().mLeft; + if (auto it = map.find(args[0].asNumber().toInt32()); it != map.end()) { + return String::newString(it->second); + } + return {}; + } + CATCH_AND_THROW + + return Boolean::newBoolean(true); +} diff --git a/src/lse/api/NetworkPacket.h b/src/lse/api/NetworkPacket.h index ed0e7bce..f1719671 100644 --- a/src/lse/api/NetworkPacket.h +++ b/src/lse/api/NetworkPacket.h @@ -10,10 +10,9 @@ namespace lse::api { -template class NetworkPacket final : public Packet { public: - NetworkPacket(std::string data) : mData(std::move(data)) {} + NetworkPacket(MinecraftPacketIds id, std::string data) : Packet(), mPacketId(id), mData(std::move(data)) {} NetworkPacket() = default; NetworkPacket(NetworkPacket&&) = default; @@ -23,16 +22,20 @@ class NetworkPacket final : public Packet { NetworkPacket(NetworkPacket const&) = delete; NetworkPacket& operator=(NetworkPacket const&) = delete; - [[nodiscard]] MinecraftPacketIds getId() const override { return packetId; } + [[nodiscard]] MinecraftPacketIds getId() const override { return mPacketId; } [[nodiscard]] std::string_view getName() const override { return "NetworkPacket"; } void write(BinaryStream& stream) const override { stream.mBuffer.append(mData); } - Bedrock::Result _read(class ReadOnlyBinaryStream& /*stream*/) override { return Bedrock::Result{}; } + Bedrock::Result _read(ReadOnlyBinaryStream& stream) override { + mData = stream.mView.substr(stream.mReadPointer); + return {}; + } private: - std::string mData; + MinecraftPacketIds mPacketId; + std::string mData; }; } // namespace lse::api