diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6419abe..3c6d683 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,8 +11,6 @@ jobs: uses: actions/checkout@v2 - uses: xmake-io/github-action-setup-xmake@v1 - with: - xmake-version: "2.9.3" - run: | xmake repo -u @@ -23,14 +21,8 @@ jobs: - run: | xmake -w -y - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }} path: | - bin/DLL/ - - - uses: actions/upload-artifact@v3 - with: - name: PDB - path: | - bin/PDB/ + bin/ \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d069c1d..852fe38 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,8 +11,6 @@ jobs: uses: actions/checkout@v2 - uses: xmake-io/github-action-setup-xmake@v1 - with: - xmake-version: "2.9.3" - run: | xmake repo -u @@ -23,17 +21,11 @@ jobs: - run: | xmake -w -y - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }} path: | - bin/DLL/ - - - uses: actions/upload-artifact@v3 - with: - name: PDB - path: | - bin/PDB/ + bin/ upload-to-release: needs: @@ -45,32 +37,23 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Download Plugin - uses: actions/download-artifact@v3 + - name: Download Mod + uses: actions/download-artifact@v4 with: name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }} - path: release/Plugin/ - - - name: Download PDB - uses: actions/download-artifact@v3 - with: - name: PDB - path: release/PDB/ + path: artifact - name: Copy additional files run: | - cp LICENSE README.md release/Plugin/ + cp -v LICENSE README.md artifact/ - name: Archive release run: | - cd release/Plugin zip -r ../${{ github.event.repository.name }}-windows-x64.zip * - cd .. + working-directory: artifact - name: Create GitHub Release - id: create_release uses: softprops/action-gh-release@v1 with: files: | - release/${{ github.event.repository.name }}-windows-x64.zip - release/PDB/${{ github.event.repository.name }}.pdb + ${{ github.event.repository.name }}-windows-x64.zip \ No newline at end of file diff --git a/lib/BEPlaceholderAPI-JS.d.ts b/lib/BEPlaceholderAPI-JS.d.ts index e28b63e..8e5d94b 100644 --- a/lib/BEPlaceholderAPI-JS.d.ts +++ b/lib/BEPlaceholderAPI-JS.d.ts @@ -1,4 +1,4 @@ -declare class PAPI { +export class PAPI { /** 注册一个玩家PAPI变量 */ static registerPlayerPlaceholder( /** PAPI调用函数 */ diff --git a/lib/EventAPI-JS.d.ts b/lib/EventAPI-JS.d.ts index b8654bc..a8975bc 100644 --- a/lib/EventAPI-JS.d.ts +++ b/lib/EventAPI-JS.d.ts @@ -1,251 +1,894 @@ -/** 事件监听接口 */ -declare class Event { - /** 生物捡起物品 */ - static listen( +export namespace Event { + /** 事件优先级 */ + export enum EventPriority { + /** 最高 */ + Highest = 0, + /** 高 */ + High = 100, + /** 正常(推荐) */ + Normal = 200, + /** 低 */ + Low = 300, + /** 最低 */ + Lowest = 400 + } + + /** 获取所有事件订阅 */ + export function getListener(): Record; + + /** 获取事件订阅列表 */ + export function getListener( /** 事件名 */ - event: "onMobDie", - /** 监听函数 */ - listener: ( - /** 尝试捡起物品的实体对象 */ - entity: Entity, - /** 掉落物实体对象 */ - itemEntity: Entity - ) => boolean | void + eventName: + "ll::ServerStoppingEvent" + | "gmlib::ClientLoginAfterEvent" + | "gmlib::WeatherUpdateBeforeEvent" + | "gmlib::MobPickupItemBeforeEvent" + | "gmlib::ItemActorSpawnBeforeEvent" + | "gmlib::ItemActorSpawnAfterEvent" + | "gmlib::ActorChangeDimensionBeforeEvent" + | "gmlib::PlayerStopSleepBeforeEvent" + | "gmlib::DeathMessageAfterEvent" + | "gmlib::MobHurtAfterEvent" + | "gmlib::EndermanTakeBlockBeforeEvent" + | "gmlib::ActorChangeDimensionAfterEvent" + | "gmlib::DragonRespawnBeforeEvent" + | "gmlib::ProjectileCreateBeforeEvent" + | "gmlib::ProjectileCreateAfterEvent" + | "gmlib::SpawnWanderingTraderBeforeEvent" + | "gmlib::HandleRequestActionBeforeEvent" + | "gmlib::ContainerClosePacketSendAfterEvent" + ): number[]; + + /** 订阅事件是否存在 */ + export function hasListener( + /** 事件ID */ + eventId: number ): boolean; - /** 客户端登录后事件(不可以拦截) */ - static listen( - /** 事件名 */ - event: "onClientLogin", - /** 监听函数 */ - listener: ( - /** 玩家的游戏名字 */ - realName: string, - /** 玩家的uuid */ - uuid: string, - /** 玩家在服务端的xuid */ - serverXuid: string, - /** 玩家在客户端的xuid */ - clientXuid: string + /** 取消事件订阅 */ + export function removeListener( + /** 事件ID */ + eventId: number + ): boolean; + + /** 获取订阅事件优先级 */ + export function getListenerPriority( + /** 事件ID */ + eventId: number + ): EventPriority | undefined; + + /** 设置事件异常处理回调 */ + export function setErrorHanlerCallback( + /** 回调 */ + callback: ( + /** 错误 */ + error: Error, + /** 事件名 */ + eventName: string, + /** 事件ID */ + eventId: number, + /** 插件名 */ + pluginName: string ) => void ): boolean; - /** 天气改变事件事件 */ - static listen( + /** 监听事件(兼容旧版) */ + export function listen( /** 事件名 */ - event: "onWeatherChange", - /** 监听函数 */ - listener: ( - /** 雷暴天气等级 */ - lightningLevel: number, - /** 雨天天气等级 */ - rainLevel: number, - /** 雷暴持续时间(刻) */ - lightningLastTick: number, - /** 雨天持续时间(刻) */ - rainingLastTick: number - ) => boolean | void + eventName: "onServerStopping" + | "onClientLogin" + | "onWeatherChange" + | "onMobPick" + | "onItemTrySpawn" + | "onItemSpawned" + | "onEntityTryChangeDim" + | "onLeaveBed" + | "onDeathMessage" + | "onMobHurted" + | "onEndermanTake" + | "onEntityChangeDim" + | "onDragonRespawn" + | "onProjectileTryCreate" + | "onProjectileCreate" + | "onSpawnWanderingTrader" + | "onHandleRequestAction" + | "onSendContainerClosePacket", + /** 回调 */ + callback: Function ): boolean; - /** 掉落物尝试生成 */ - static listen( - event: "onItemTrySpawn", - listener: ( - /** 物品对象 */ - item: Item, - /** 尝试生成的坐标对象 */ - pos: FloatPos, - /** 创建掉落物的实体uniqueId */ - spawnerUniqueId: number - ) => boolean | void - ): boolean; - - /** 掉落物生成完毕(不可以拦截) */ - static listen( + /** 订阅事件 */ + export function emplaceListener( /** 事件名 */ - event: "onItemSpawned", - /** 回调函数 */ - listener: ( - /** 物品对象 */ - item: Item, - /** 掉落物实体对象 */ - entity: Entity, - /** 实体生成的坐标 */ - pos: FloatPos, - /** 创建掉落物的实体uniqueId */ - spawnerUniqueId: number - ) => void - ): boolean; + eventName: string, + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: any[], + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 实体切换维度 */ - static listen( + /** 订阅事件(服务器关闭事件) */ + export function emplaceListener( /** 事件名 */ - event: "onEntityTryChangeDim", - /** 回调函数 */ - listener: ( - /** 切换维度的实体对象 */ - entity: Entity, - /** 前往到的维度ID */ - dimid: number - ) => boolean | void - ): boolean; + eventName: "ll::ServerStoppingEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: {}, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 实体切换维度后(不可拦截) */ - static listen( + /** 订阅事件(客户端登录后事件) */ + export function emplaceListener( /** 事件名 */ - event: "onEntityChangeDim", - /** 回调函数 */ - listener: ( - /** 切换维度的实体对象 */ - entity: Entity, - /** 前往到的维度ID */ - fromDimid: number - ) => void - ): boolean; + eventName: "gmlib::ClientLoginAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 玩家名 */ + 0: string, + /** 玩家uuid */ + 1: string, + /** 玩家服务端xuid */ + 2: string, + /** 玩家客户端xuid */ + 3: string, + }, + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 玩家下床 */ - static listen( + /** 订阅事件(天气更新前事件) */ + export function emplaceListener( /** 事件名 */ - event: "onLeaveBed", - /** 回调函数 */ - listener: ( - /** 下床的玩家对象 */ - player: Player - ) => boolean | void - ): boolean; + eventName: "gmlib::WeatherUpdateBeforeEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 雨天等级 */ + 0: number, + /** 雨天时间(tick) */ + 1: number, + /** 暴雨等级 */ + 2: number, + /** 暴雨时间(tick) */ + 3: number, + }, + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 触发死亡信息(不可以拦截) */ - static listen( + /** 订阅事件(天气更新后事件) */ + export function emplaceListener( /** 事件名 */ - event: "onDeathMessage", - /** 回调函数 */ - listener: ( - /** 死亡信息键名 */ - deathMsgKey: string, - /** 死亡信息翻译参数 */ - deathMsgParams: string[], - /** 死亡实体的实体对象 */ - entity: Entity - ) => void - ): boolean; + eventName: "gmlib::WeatherUpdateAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 雨天等级 */ + 0: number, + /** 雨天时间(tick) */ + 1: number, + /** 暴雨等级 */ + 2: number, + /** 暴雨时间(tick) */ + 3: number, + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 实体受伤后事件 */ - static listen( + /** 订阅事件(实体捡起物品前事件) */ + export function emplaceListener( /** 事件名 */ - event: "onMobHurted", - /** 回调函数 */ - listener: ( - /** 受伤的实体对象 */ - entity: Entity, - /** 造成伤害的实体对象 */ - source: Entity, - /** 伤害值 */ - damage: number, - /** 伤害类型 */ - cause: number - ) => void - ): boolean; + eventName: "gmlib::MobPickupItemBeforeEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 捡起物品的实体 */ + 0: Entity, + /** 掉落物 */ + 1: Entity + }, + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 末影人搬起方块 */ - static listen( + /** 订阅事件(实体捡起物品后事件) */ + export function emplaceListener( /** 事件名 */ - event: "onEndermanTake", - /** 回调函数 */ - listener: ( - /** 末影人实体对象 */ - entity: Entity - ) => boolean | void - ): boolean; + eventName: "gmlib::MobPickupItemAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 捡起物品的实体 */ + 0: Entity, + /** 掉落物 */ + 1: Entity + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 末影龙重生事件 */ - static listen( + /** 订阅事件(掉落物生成前事件) */ + export function emplaceListener( /** 事件名 */ - event: "onDragonRespawn", - /** 回调函数 */ - listener: ( - /** 末影龙重生后的UniqueID */ - uniqueID: number - ) => boolean | void - ): boolean; + eventName: "gmlib::ItemActorSpawnBeforeEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 物品 */ + 0: Item, + /** 生成坐标坐标 */ + 1: FloatPos, + /** 生成此物品主人的uniqueId (-1为不存在) */ + 2: number + }, + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 弹射物实体尝试创建 */ - static listen( + /** 订阅事件(掉落物生成后事件) */ + export function emplaceListener( /** 事件名 */ - event: "onProjectileTryCreate", - /** 回调函数 */ - listener: ( - /** 弹射物实体对象 */ - entity: Entity, - /** 创建弹射的实体的uniqueID */ - uniqueId: number - ) => boolean | void - ): boolean; + eventName: "gmlib::ItemActorSpawnAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 物品实体对象 */ + 0: Entity, + /** 生成坐标坐标 */ + 1: FloatPos, + /** 生成此物品主人的uniqueId (-1为不存在) */ + 2: number + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 弹射物实体成功后(不可拦截) */ - static listen( + /** 订阅事件(实体切换维度前事件) */ + export function emplaceListener( /** 事件名 */ - event: "onProjectileCreate", - /** 回调函数 */ - listener: ( - /** 弹射物实体对象 */ - entity: Entity, - /** 创建弹射的实体的uniqueID */ - uniqueId: number - ) => void - ): boolean; + eventName: "gmlib::ActorChangeDimensionBeforeEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 切换维度的实体 */ + 0: Entity, + /** 前往的维度ID */ + 1: number + }, + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 生成流浪商人 */ - static listen( + /** 订阅事件(事件切换维度后事件) */ + export function emplaceListener( /** 事件名 */ - event: "onSpawnWanderingTrader", - /** 回调函数 */ - listener: ( - /** 生成的坐标 */ - pos: IntPos - ) => boolean | void - ): boolean; + eventName: "gmlib::ActorChangeDimensionAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 切换维度的实体 */ + 0: Entity, + /** 原来的维度ID */ + 1: number, + /** 前往的维度ID */ + 2: number + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 处理物品请求 */ - static listen( + /** 订阅事件(玩家开始睡觉前事件) */ + export function emplaceListener( /** 事件名 */ - event: "onHandleRequestAction", - /** 回调函数 */ - listener: ( - /** 请求玩家 */ - player: Player, - /** 请求类型 */ - actionType: string, - /** 请求数量 */ - count: number, - /** 第一个格子的容器类型 */ - sourceContainerNetId: string, - /** 第一个格子的槽位 */ - sourceSlot: number, - /** 第二个格子的容器类型 */ - destinationContainerNetId: string, - /** 第二个格子的槽位 */ - destinationSlot: number - ) => boolean | void - ): boolean; + eventName: "gmlib::PlayerStartSleepBeforeEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 睡觉的玩家 */ + 0: Player, + /** 床的坐标 */ + 1: IntPos + }, + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 发送容器关闭数据包后(不可拦截) */ - static listen( + /** 订阅事件(玩家开始睡觉后事件) */ + export function emplaceListener( /** 事件名 */ - event: "onSendContainerClosePacket", - /** 回调函数 */ - listener: ( - /** 要被关闭的玩家 */ - player: Player, - /** 容器ID */ - containerId: number - ) => void - ): boolean; + eventName: "gmlib::PlayerStartSleepAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 睡觉的玩家 */ + 0: Player, + /** 床的坐标 */ + 1: IntPos, + /** 睡觉的结果 */ + 2: number + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; - /** 关闭服务器(不可拦截) */ - static listen( + /** 订阅事件(玩家停止睡觉前事件) */ + export function emplaceListener( /** 事件名 */ - event: "onServerStopping", - /** 回调函数 */ - listener: () => void - ): boolean; + eventName: "gmlib::PlayerStopSleepBeforeEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 睡觉的玩家 */ + 0: Player, + /** forcefulWakeUp */ + 1: boolean, + /** updateLevelList */ + 2: boolean + }, + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(玩家停止睡觉后事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::PlayerStopSleepAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 睡觉的玩家 */ + 0: Player, + /** forcefulWakeUp */ + 1: boolean, + /** updateLevelList */ + 2: boolean + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(生成死亡消息后事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::DeathMessageAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 键名 */ + 0: string, + /** 翻译参数 */ + 1: string[], + /** 死亡的实体 */ + 2: Entity + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(实体受伤后事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::MobHurtAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 受伤的实体 */ + 0: Entity, + /** 伤害来源 */ + 1: Entity, + /** 伤害值 */ + 2: number, + /** 伤害类型 */ + 3: DamageCause + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(末影人搬运方块前事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::EndermanTakeBlockBeforeEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 末影人实体 */ + 0: Entity + }, + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(末影龙复活前事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::DragonRespawnBeforeEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: {}, + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(末影龙复活后事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::DragonRespawnAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 末影龙实体 */ + 0: Entity + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(投射物创建前事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::ProjectileCreateBeforeEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 投射物实体 */ + 0: Entity, + /** 创建投射物实体的uniqueId */ + 1: number + }, + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(投射物创建后事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::ProjectileCreateAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 投射物实体 */ + 0: Entity, + /** 创建投射物实体的uniqueId */ + 1: number + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(生成流浪商人前事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::SpawnWanderingTraderBeforeEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 出现的坐标 */ + 0: IntPos + }, + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(生成流浪商人后事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::SpawnWanderingTraderAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 出现的坐标 */ + 0: IntPos + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(处理物品请求前事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::HandleRequestActionBeforeEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 请求的玩家 */ + 0: Player, + /** 请求类型 */ + 1: string, + /** 请求数量 */ + 2: number, + /** 请求原容器类型 */ + 3: string, + /** 请求原容器槽位 */ + 4: number, + /** 请求前往的容器类型 */ + 5: string, + /** 请求前往的槽位 */ + 6: number + }, + /** 拦截事件 */ + cancel: () => void, + /** 设置拦截状态 */ + setCancelled: ( + /** 是否拦截 */ + value: boolean + ) => void, + /** 是否被拦截 */ + isCancelled: () => boolean, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(处理物品请求后事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::HandleRequestActionAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 请求的玩家 */ + 0: Player, + /** 请求类型 */ + 1: string, + /** 请求数量 */ + 2: number, + /** 请求原容器类型 */ + 3: string, + /** 请求原容器槽位 */ + 4: number, + /** 请求前往的容器类型 */ + 5: string, + /** 请求前往的槽位 */ + 6: number + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; + + /** 订阅事件(玩家关闭容器后事件) */ + export function emplaceListener( + /** 事件名 */ + eventName: "gmlib::ContainerClosePacketSendAfterEvent", + /** 回调 */ + callback: (event: { + /** 事件参数 */ + params: { + /** 关闭的玩家 */ + 0: Player, + /** 容器会话ID */ + 1: number, + /** 由服务器关闭 */ + 2: boolean + }, + /** 获取事件ID */ + getId: () => number, + /** 获取事件类型 */ + getEventType: () => string + }) => void, + /** 优先级 */ + priority?: Event.EventPriority, + /** 插件名 */ + pluginName?: string + ): number; } \ No newline at end of file diff --git a/lib/EventAPI-JS.js b/lib/EventAPI-JS.js index 61a9c72..f45fd02 100644 --- a/lib/EventAPI-JS.js +++ b/lib/EventAPI-JS.js @@ -1,28 +1,170 @@ -/** 事件创建函数 @type {function(string,string):boolean} */ -const CallEvent = ll.import("GMLIB_Event_API", "callCustomEvent"); -/** 获取事件ID函数 @type {function():string} */ -const getNextEventId = ll.import("GMLIB_Event_API", "getNextScriptEventId"); - -/** 事件类 */ -class Event { - constructor() { throw new Error("Static class cannot be instantiated"); } - - /** - * 监听事件 - * @param {string} event 事件名称 - * @param {function} callback 回调 - * @returns {boolean} 是否创建成功 - */ - static listen(event, callback) { - let eventId = getNextEventId(); - ll.export(callback, event, eventId); - let result = CallEvent(event, eventId); - if (!result) { - logger.error(`Cannot listen event "${event}" !`); - logger.error(`GMLIB Script Event "${event}" does not exist !`); - } - return result; +/** + * @returns {string} + */ +const getPluginName = () => { + try { + throw new Error("getPluginName"); + } catch (error) { + return error.stack.trim().match(/plugins\\(.*)\\.*\.js:[0-9]+\)$/i)?.[1] || "Unknown"; } -} +}; -module.exports = { Event }; \ No newline at end of file +module.exports = { + Event: { + /** + * 事件订阅记录 + * 例如: {事件名: [事件ID, ...], ...} + * @type {Object.} + */ + mEventData: {}, + /** + * 事件异常处理回调 + * @param {Error} error + * @param {string} eventName + * @param {number} eventID + * @param {string} pluginName + * @returns {void} + */ + mErrorHanlerCallback: (error, eventName, eventID, pluginName) => { + logger.error(`Info: ${pluginName}-${eventName}-${eventID} Exception: ${error.message}\n${error.stack}`); + }, + + /** + * 监听事件(兼容旧版) + * @param {string} eventName + * @param {function} callback + * @param {boolean} + */ + listen: function (eventName, callback) { + try { + if (typeof callback !== "function") return false; + const eventReflection = { + onServerStopping: "ll::ServerStoppingEvent", + onClientLogin: "gmlib::ClientLoginAfterEvent", + onWeatherChange: "gmlib::WeatherUpdateBeforeEvent", + onMobPick: "gmlib::MobPickupItemBeforeEvent", + onItemTrySpawn: "gmlib::ItemActorSpawnBeforeEvent", + onItemSpawned: "gmlib::ItemActorSpawnAfterEvent", + onEntityTryChangeDim: "gmlib::ActorChangeDimensionBeforeEvent", + onLeaveBed: "gmlib::PlayerStopSleepBeforeEvent", + onDeathMessage: "gmlib::DeathMessageAfterEvent", + onMobHurted: "gmlib::MobHurtAfterEvent", + onEndermanTake: "gmlib::EndermanTakeBlockBeforeEvent", + onEntityChangeDim: "gmlib::ActorChangeDimensionAfterEvent", + onDragonRespawn: "gmlib::DragonRespawnBeforeEvent", + onProjectileTryCreate: "gmlib::ProjectileCreateBeforeEvent", + onProjectileCreate: "gmlib::ProjectileCreateAfterEvent", + onSpawnWanderingTrader: "gmlib::SpawnWanderingTraderBeforeEvent", + onHandleRequestAction: "gmlib::HandleRequestActionBeforeEvent", + onSendContainerClosePacket: "gmlib::ContainerClosePacketSendAfterEvent" + }; + this.emplaceListener(eventReflection[eventName] ?? eventName, event => { + const result = callback(...event.params); + if (typeof (result) === "boolean" && !result) event.cancel(); + }); + return true; + } catch { } + return false; + }, + + /** + * 订阅事件 + * @param {string} eventName + * @param {function} callback + * @param {number?} priority + * @param {string?} pluginName + * @returns {number} + */ + emplaceListener: function (eventName, callback, priority = this.EventPriority.Normal, pluginName = getPluginName()) { + if (typeof callback !== "function") throw new Error("callback must be a function!"); + const /** @type {number} */ eventId = ll.imports("GMLIB_Event_API", "emplaceListener")(pluginName, eventName, priority); + if (eventId === -1) throw new Error(`Event ${eventName} creation failed!`); + ll.exports((...data) => { + let /** @type {boolean} */ result = typeof (data.slice(-1)[0]) === "boolean" ? data.pop() : false; + try { + callback({ + params: data, + cancel: () => result = true, + setCancelled: (/** @type {boolean} */value) => { result = value; }, + isCancelled: () => result, + getId: () => eventId, + getEventType: () => eventName + }); + } catch (error) { + try { + this.mErrorHanlerCallback(error, eventName, eventId, pluginName); + } catch { } + } + return result; + }, pluginName, eventName + "_" + eventId); + (this.mEventData[eventName] ??= []).push(eventId); + return eventId; + }, + + /** + * 取消事件订阅 + * @param {number} eventId + * @param {boolean} + */ + removeListener: function (eventId) { + const result = ll.imports("GMLIB_Event_API", "removeListener")(eventId); + if (result) { + for (let [eventName, eventIds] of Object.entries(this.mEventData)) { + this.mEventData[eventName] = eventIds.filter(id => id !== eventId); + if (this.mEventData[eventName].length === 0) delete this.mEventData[eventName]; + } + } + return result; + }, + + /** + * 判断事件订阅是否存在 + * @param {number} eventId + * @returns {boolean} + */ + hasListener: function (eventId) { + return ll.imports("GMLIB_Event_API", "hasListener")(eventId); + }, + + /** + * 获取订阅事件优先级 + * @param {number} eventId + * @returns {number?} + */ + getListenerPriority: function (eventId) { + const priority = ll.imports("GMLIB_Event_API", "getListenerPriority")(eventId); + return priority === -1 ? undefined : priority; + }, + + /** + * 获取订阅事件列表 + * @param {string | undefined} eventName + * @returns {number[] | Object.} + */ + getListener: function (eventName) { + return eventName === undefined ? this.mEventData : this.mEventData[eventName] ?? []; + }, + + /** + * 设置异常处理回调 + * @param {function(Error, string, number, string): void} callback + * @returns {boolean} + */ + setErrorHanlerCallback: function (callback) { + if (callback === undefined || typeof callback !== "function") return false; + this.mErrorHanlerCallback = callback; + return true; + }, + + /** + * 事件优先级 + */ + EventPriority: { + Highest: 0, + High: 100, + Normal: 200, + Low: 300, + Lowest: 400 + } + } +}; \ No newline at end of file diff --git a/lib/GMLIB_API-JS.d.ts b/lib/GMLIB_API-JS.d.ts index eece4f8..bb7ad7b 100644 --- a/lib/GMLIB_API-JS.d.ts +++ b/lib/GMLIB_API-JS.d.ts @@ -1,5 +1,5 @@ /** 静态悬浮字类 */ -declare class StaticFloatingText { +export class StaticFloatingText { constructor( /** 生成的坐标 */ pos: FloatPos, @@ -73,7 +73,7 @@ declare class StaticFloatingText { } /** 动态悬浮字类 */ -declare class DynamicFloatingText extends StaticFloatingText { +export class DynamicFloatingText extends StaticFloatingText { constructor( /** 生成的坐标 */ pos: FloatPos, @@ -113,7 +113,7 @@ declare class DynamicFloatingText extends StaticFloatingText { } /** 基础游戏API类 */ -declare class Minecraft { +export class Minecraft { private constructor(); /** 获取服务器平均tps */ @@ -393,7 +393,7 @@ declare class Minecraft { } /** 合成表类 */ -declare class Recipes { +export class Recipes { private constructor(); /** 注销合成表 */ @@ -534,7 +534,7 @@ declare class Recipes { } /** 实验性功能类 */ -declare class Experiments { +export class Experiments { private constructor(); /** 获取所有实验的id */ @@ -568,7 +568,7 @@ declare class Experiments { } /** 计分板类 */ -declare class Scoreboard { +export class Scoreboard { private constructor(); /** 获取所有跟踪实体 */ @@ -788,7 +788,7 @@ declare class Scoreboard { } /** 仿LSE的JsonConfigFile类 */ -declare class JsonConfig { +export class JsonConfig { constructor( /** 文件路径 */ path: string, @@ -832,7 +832,7 @@ declare class JsonConfig { } /** JSON语言文件 */ -declare class JsonLanguage extends JsonConfig { +export class JsonLanguage extends JsonConfig { /** 创建或打开一个 Json 语言文件 */ constructor( /** 文件路径 */ @@ -851,7 +851,7 @@ declare class JsonLanguage extends JsonConfig { } /** JSON版翻译类 */ -declare class JsonI18n { +export class JsonI18n { /** 加载翻译数据目录 */ constructor( /** 目录 */ @@ -895,7 +895,7 @@ declare class JsonI18n { } /** 版本类 */ -declare class Version { +export class Version { /** 创建版本对象 */ constructor( /** 主版本号 */ @@ -944,7 +944,7 @@ declare class Version { } /** 翻译API类 */ -declare class I18nAPI { +export class I18nAPI { private constructor(); /** 获取键翻译 */ @@ -1005,7 +1005,7 @@ declare class I18nAPI { } /** 玩家信息存储类 */ -declare class UserCache { +export class UserCache { private constructor(); /** 根据uuid查xuid */ @@ -1122,21 +1122,31 @@ type PacketData = ( ); /** 二进制流数据包类 */ -declare class GMLIB_BinaryStream { +export class GMLIB_BinaryStream { /** 数据包ID */ #id: number; /** 数据包是否被销毁 */ #destroy: boolean; + /** 构造二进流数据包 */ constructor( /** 数据包数据 */ data: PacketData[]? ); + /** 拷贝二进制流数据包 */ + constructor( + /** 要拷贝的二进制流数据包 */ + stream: GMLIB_BinaryStream + ); + + /** 获取数据包的ID */ + getId(): number; + /** 发送数据包 */ sendTo( /** 要发送数据包的玩家对象 */ - player: Player, + player: Player | Entity, /** 数据包发送后是否销毁 */ free: boolean = true ): GMLIB_BinaryStream; @@ -1144,7 +1154,7 @@ declare class GMLIB_BinaryStream { /** 发送数据包到玩家数组 */ sendToPlayers( /** 要发送数据包的玩家对象数组 */ - players: Player[], + players: Player[] | Entity[], /** 数据包发送后是否销毁 */ free: boolean = true ): GMLIB_BinaryStream; @@ -1337,6 +1347,165 @@ declare class GMLIB_BinaryStream { ): GMLIB_BinaryStream; } +export enum ActorType { + Undefined = 1, + TypeMask = 0b11111111, + None = 0, + Mob = 1 << 8, + PathfinderMob = 1 << 9 | Mob, + UnknownType = 1 << 10, + Monster = 1 << 11 | PathfinderMob, + Animal = 1 << 12 | PathfinderMob, + WaterAnimal = 1 << 13 | PathfinderMob, + TamableAnimal = 1 << 14 | Animal, + Ambient = 1 << 15 | Mob, + UndeadMob = 1 << 16 | Monster, + ZombieMonster = 1 << 17 | UndeadMob, + Arthropod = 1 << 18 | Monster, + Minecart = 1 << 19, + SkeletonMonster = 1 << 20 | UndeadMob, + EquineAnimal = 1 << 21 | TamableAnimal, + Projectile = 1 << 22, + AbstractArrow = 1 << 23, + VillagerBase = 1 << 24 | PathfinderMob, + + Chicken = 10 | Animal, + Cow = 11 | Animal, + Pig = 12 | Animal, + Sheep = 13 | Animal, + Wolf = 14 | TamableAnimal, + Villager = 15 | VillagerBase, + MushroomCow = 16 | Animal, + Squid = 17 | WaterAnimal, + Rabbit = 18 | Animal, + Bat = 19 | Ambient, + IronGolem = 20 | PathfinderMob, + SnowGolem = 21 | PathfinderMob, + Ocelot = 22 | TamableAnimal, + Horse = 23 | EquineAnimal, + Donkey = 24 | EquineAnimal, + Mule = 25 | EquineAnimal, + SkeletonHorse = 26 | EquineAnimal | UndeadMob, + ZombieHorse = 27 | EquineAnimal | UndeadMob, + PolarBear = 28 | Animal, + Llama = 29 | Animal, + Parrot = 30 | TamableAnimal, + Dolphin = 31 | WaterAnimal, + Zombie = 32 | ZombieMonster, + Creeper = 33 | Monster, + Skeleton = 34 | SkeletonMonster, + Spider = 35 | Arthropod, + PigZombie = 36 | UndeadMob, + Slime = 37 | Monster, + EnderMan = 38 | Monster, + Silverfish = 39 | Arthropod, + CaveSpider = 40 | Arthropod, + Ghast = 41 | Monster, + LavaSlime = 42 | Monster, + Blaze = 43 | Monster, + ZombieVillager = 44 | ZombieMonster, + Witch = 45 | Monster, + Stray = 46 | SkeletonMonster, + Husk = 47 | ZombieMonster, + WitherSkeleton = 48 | SkeletonMonster, + Guardian = 49 | Monster, + ElderGuardian = 50 | Monster, + Npc = 51 | Mob, + WitherBoss = 52 | UndeadMob, + Dragon = 53 | Monster, + Shulker = 54 | Monster, + Endermite = 55 | Arthropod, + Agent = 56 | Mob, + Vindicator = 57 | Monster, + Phantom = 58 | UndeadMob, + IllagerBeast = 59 | Monster, + UNUSED60 = 60, + ArmorStand = 61 | Mob, + TripodCamera = 62 | Mob, + Player = 63 | Mob, + ItemEntity = 64 | None, + PrimedTnt = 65 | None, + FallingBlock = 66 | None, + MovingBlock = 67 | None, + ExperiencePotion = 68 | Projectile, + Experience = 69 | None, + EyeOfEnder = 70 | None, + EnderCrystal = 71 | None, + FireworksRocket = 72 | None, + Trident = 73 | Projectile | AbstractArrow, + Turtle = 74 | Animal, + Cat = 75 | TamableAnimal, + ShulkerBullet = 76 | Projectile, + FishingHook = 77 | None, + Chalkboard = 78 | None, + DragonFireball = 79 | Projectile, + Arrow = 80 | Projectile | AbstractArrow, + Snowball = 81 | Projectile, + ThrownEgg = 82 | Projectile, + Painting = 83 | None, + MinecartRideable = 84 | Minecart, + LargeFireball = 85 | Projectile, + ThrownPotion = 86 | Projectile, + Enderpearl = 87 | Projectile, + LeashKnot = 88 | None, + WitherSkull = 89 | Projectile, + BoatRideable = 90 | None, + WitherSkullDangerous = 91 | Projectile, + UNUSED92 = 92, + LightningBolt = 93 | None, + SmallFireball = 94 | Projectile, + AreaEffectCloud = 95 | None, + MinecartHopper = 96 | Minecart, + MinecartTNT = 97 | Minecart, + MinecartChest = 98 | Minecart, + MinecartFurnace = 99 | Minecart, + MinecartCommandBlock = 100 | Minecart, + LingeringPotion = 101 | Projectile, + LlamaSpit = 102 | Projectile, + EvocationFang = 103 | Projectile, + EvocationIllager = 104 | Monster, + Vex = 105 | Monster, + IceBomb = 106 | Projectile, + Balloon = 107 | None, + Pufferfish = 108 | WaterAnimal, + Salmon = 109 | WaterAnimal, + Drowned = 110 | ZombieMonster, + Tropicalfish = 111 | WaterAnimal, + Fish = 112 | WaterAnimal, + Panda = 113 | Animal, + Pillager = 114 | Monster, + VillagerV2 = 115 | VillagerBase, + ZombieVillagerV2 = 116 | ZombieMonster, + Shield = 117 | None, + WanderingTrader = 118 | PathfinderMob, + Lectern = 119 | None, + ElderGuardianGhost = 120 | Monster, + Fox = 121 | Animal, + Bee = 122 | Mob, + Piglin = 123 | Mob, + Hoglin = 124 | Animal, + Strider = 125 | Animal, + Zoglin = 126 | UndeadMob, + PiglinBrute = 127 | Mob, + Goat = 128 | Animal, + GlowSquid = 129 | WaterAnimal, + Axolotl = 130 | Animal, + Warden = 131 | Monster, + Frog = 132 | Animal, + Tadpole = 133 | WaterAnimal, + Allay = 134 | Mob, + ChestBoatRideable = 136 | BoatRideable, + TraderLlama = 137 | Llama, + Camel = 138 | Animal, + Sniffer = 139 | Animal, + Breeze = 140 | Monster, + BreezeWindChargeProjectile = 141 | Projectile, + Armadillo = 142 | Animal, + WindChargeProjectile = 143 | Projectile, + Bogged = 144 | SkeletonMonster, + OminousItemSpawner = 145 +} + interface Player { /** (GMLIB)转换成实体对象 */ toEntity(): Entity; @@ -1509,6 +1678,21 @@ interface Entity { /** 是否显示粒子效果 */ ShowParticles: boolean }[]; + + /** 实体是否为某类型 */ + isType( + /** 实体类型 */ + type: ActorType + ): boolean; + + /** 实体是否包含某类型 */ + hasType( + /** 实体类型 */ + type: ActorType + ): boolean; + + /** 获取实体类型ID */ + getEntityTypeId(): ActorType; } interface Block { @@ -1533,9 +1717,6 @@ interface Block { /** (GMLIB) */ canDropWithAnyTool(): boolean; - /** (GMLIB)方块是否不需要工具采集 */ - isAlwaysDestroyable(): boolean; - /** (GMLIB)检测方块是否能被玩家挖掘(比如插件拦截) */ playerWillDestroy( /** 挖掘的玩家对象 */ @@ -1574,9 +1755,6 @@ interface Item { block: Block ): boolean; - /** (GMLIB)获取物品可以拥有的附魔 */ - getLegalEnchants(): string[] - /** (GMLIB)添加附魔 */ applyEnchant( /** 附魔的命名空间ID */ diff --git a/lib/GMLIB_API-JS.js b/lib/GMLIB_API-JS.js index 1a34e4c..e3cce3d 100644 --- a/lib/GMLIB_API-JS.js +++ b/lib/GMLIB_API-JS.js @@ -252,8 +252,6 @@ const GMLIB_API = { itemCanDestroySpecial: ll.import("GMLIB_API", "itemCanDestroySpecial"), /** @type {function(Block):boolean} */ blockCanDropWithAnyTool: ll.import("GMLIB_API", "blockCanDropWithAnyTool"), - /** 方块是否不需要工具采集 @type {function(Block):boolean} */ - blockIsAlwaysDestroyable: ll.import("GMLIB_API", "blockIsAlwaysDestroyable"), /** @type {function(Block,Player,IntPos):boolean} */ blockPlayerWillDestroy: ll.import("GMLIB_API", "blockPlayerWillDestroy"), /** 使玩家攻击实体 @type {function(Entity,Player):boolean} */ @@ -268,8 +266,6 @@ const GMLIB_API = { getBlockLightEmission: ll.import("GMLIB_API", "getBlockLightEmission"), /** 获取游戏规则列表 @type {function():Array.<{Name:string,Value:string,Type:"Bool"|"Float"|"Int"}>} */ getGameRules: ll.import("GMLIB_API", "getGameRules"), - /** 获取物品可以拥有的附魔 @type {function(Item):Array.} */ - getLegalEnchants: ll.import("GMLIB_API", "getLegalEnchants"), /** 给物品添加附魔 @type {function(Item,string,number,boolean):boolean} */ applyEnchant: ll.import("GMLIB_API", "applyEnchant"), /** 删除物品所有附魔 @type {function(Item):void} */ @@ -374,12 +370,20 @@ const GMLIB_API = { getDefaultGameMode: ll.import("GMLIB_API", "getDefaultGameMode"), /** 设置默认游戏模式 @type {function(mode):void} */ setDefaultGameMode: ll.import("GMLIB_API", "setDefaultGameMode"), + /** 实体是否为某类型 @type {function(Entity, number):boolean} */ + entityIsType: ll.import("GMLIB_API", "entityIsType"), + /** 实体是包含某类型 @type {function(Entity, number):boolean} */ + entityHasType: ll.import("GMLIB_API", "entityHasType"), + /** 获取实体类型ID @type {function(Entity):number} */ + getEntityTypeId: ll.import("GMLIB_API", "getEntityTypeId"), }; /** LRCA的二进制流数据包导出接口 */ const GMLIB_BinaryStream_API = { /** 创建二进制流数据包 @type {function():number} */ create: ll.import("GMLIB_BinaryStream_API", "create"), + /** 拷贝二进制流数据包 @type {function(number):number} */ + copy: ll.import("GMLIB_BinaryStream_API", "copy"), /** 发送二进制流数据包 @type {function(number,player):void} */ sendTo: ll.import("GMLIB_BinaryStream_API", "sendTo"), /** 销毁二进制流数据包 @type {function(number):void} */ @@ -1053,7 +1057,7 @@ class Minecraft { * @returns {number} 方块的亮度(-1为不存在) */ static getBlockLightEmission(block, legacyData = 0) { - return GMLIB_API.getBlockLightEmission(block, legacyData) + return GMLIB_API.getBlockLightEmission(block, legacyData); } /** @@ -2116,30 +2120,39 @@ class GMLIB_BinaryStream { /** * 创建二进制流数据包 - * @param {{"type":string,"value":any}[]?} value 写入数据 + * @param {({"type":string,"value":any}[]|GMLIB_BinaryStream)?} value 写入数据 * @returns {GMLIB_BinaryStream} */ constructor(value) { - this.#id = GMLIB_BinaryStream_API.create(); + this.#id = value instanceof GMLIB_BinaryStream ? GMLIB_BinaryStream_API.copy(value.getId()) : GMLIB_BinaryStream_API.create(); if (Array.isArray(value)) this.write(value); } + /** + * 获取数据包的ID + * @returns {number} + */ + getId() { + return this.#id; + } + /** * 发送数据包 - * @param {Player} player 玩家 + * @param {Player|Entity} player 玩家 * @param {boolean} [free=true] 发送后销毁数据包 * @returns {GMLIB_BinaryStream} */ sendTo(player, free = true) { if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); - GMLIB_BinaryStream_API.sendTo(this.#id, player); + if (player instanceof LLSE_Entity && player.isPlayer()) player = player.toPlayer(); + if (player instanceof LLSE_Player && !player.isSimulatedPlayer()) GMLIB_BinaryStream_API.sendTo(this.#id, player); if (free) this.destroy(); return this; } /** * 发送数据包到玩家 - * @param {Player[]} players 玩家对象数组 + * @param {Player[]|Entity[]} players 玩家对象数组 * @param {boolean} free 发送后销毁数据包 * @returns {GMLIB_BinaryStream} */ @@ -2207,8 +2220,8 @@ class GMLIB_BinaryStream { * 转换成字符串 * @returns {string} 字符串 */ - toString(){ - return `` + toString() { + return ``; } /** @@ -2324,7 +2337,7 @@ class GMLIB_BinaryStream { */ writeBool(value) { if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); - GMLIB_BinaryStream_API.writeBool(this.#id, value); + GMLIB_BinaryStream_API.writeBool(this.#id, Boolean(value)); return this; } @@ -2335,7 +2348,7 @@ class GMLIB_BinaryStream { */ writeByte(value) { if (this.#destroy) throw new Error("The BinaryStream has been destroyed"); - GMLIB_BinaryStream_API.writeByte(this.#id, value); + GMLIB_BinaryStream_API.writeByte(this.#id, Number(value)); return this; } @@ -2518,7 +2531,7 @@ class GMLIB_BinaryStream { GMLIB_BinaryStream_API.writeVarInt64(this.#id, value); return this; } -} +} LLSE_Player.prototype.toEntity = /** @@ -2527,7 +2540,7 @@ LLSE_Player.prototype.toEntity = */ function () { return GMLIB_API.PlayerToEntity(this); - } + }; LLSE_Player.prototype.getSpawnPoint = /** @@ -2536,7 +2549,7 @@ LLSE_Player.prototype.getSpawnPoint = */ function () { return GMLIB_API.getPlayerSpawnPoint(this); - } + }; LLSE_Player.prototype.setSpawnPoint = /** @@ -2545,7 +2558,7 @@ LLSE_Player.prototype.setSpawnPoint = */ function (pos) { GMLIB_API.setPlayerSpawnPoint(this, pos); - } + }; LLSE_Player.prototype.clearSpawnPoint = /** @@ -2553,7 +2566,7 @@ LLSE_Player.prototype.clearSpawnPoint = */ function () { GMLIB_API.clearPlayerSpawnPoint(this); - } + }; LLSE_Entity.prototype.shootProjectile = /** @@ -2565,7 +2578,7 @@ LLSE_Entity.prototype.shootProjectile = */ function (proj, speed = 2, offset = 3) { return GMLIB_API.shootProjectile(this, proj, speed, offset); - } + }; LLSE_Entity.prototype.throwEntity = /** @@ -2577,7 +2590,7 @@ LLSE_Entity.prototype.throwEntity = */ function (proj, speed = 2, offset = 3) { return GMLIB_API.throwEntity(this, proj, speed, offset); - } + }; LLSE_Entity.prototype.getTranslateKey = /** @@ -2586,7 +2599,7 @@ LLSE_Entity.prototype.getTranslateKey = */ function () { return GMLIB_API.getEntityTranslateKey(this); - } + }; LLSE_Entity.prototype.getTranslateName = /** @@ -2596,7 +2609,7 @@ LLSE_Entity.prototype.getTranslateName = */ function (language) { return I18nAPI.get(this.getTranslateKey(), [], language); - } + }; LLSE_Block.prototype.getTranslateKey = /** @@ -2605,7 +2618,7 @@ LLSE_Block.prototype.getTranslateKey = */ function () { return GMLIB_API.getBlockTranslateKey(this); - } + }; LLSE_Block.prototype.getTranslateName = /** @@ -2615,7 +2628,7 @@ LLSE_Block.prototype.getTranslateName = */ function (language) { return I18nAPI.get(this.getTranslateKey(), [], language); - } + }; LLSE_Item.prototype.getTranslateKey = /** @@ -2624,7 +2637,7 @@ LLSE_Item.prototype.getTranslateKey = */ function () { return GMLIB_API.getItemTranslateKey(this); - } + }; LLSE_Item.prototype.getTranslateName = /** @@ -2634,7 +2647,7 @@ LLSE_Item.prototype.getTranslateName = */ function (language) { return I18nAPI.get(this.getTranslateKey(), [], language); - } + }; LLSE_Block.prototype.getBlockDestroySpeed = /** @@ -2643,7 +2656,7 @@ LLSE_Block.prototype.getBlockDestroySpeed = */ function () { return GMLIB_API.getBlockDestroySpeed(this); - } + }; LLSE_Item.prototype.getDestroyBlockSpeed = /** @@ -2653,7 +2666,7 @@ LLSE_Item.prototype.getDestroyBlockSpeed = */ function (block) { return GMLIB_API.getDestroyBlockSpeed(this, block); - } + }; LLSE_Block.prototype.playerDestroy = /** @@ -2662,7 +2675,7 @@ LLSE_Block.prototype.playerDestroy = */ function (player) { GMLIB_API.playerDestroyBlock(this, this.pos, player); - } + }; LLSE_Item.prototype.canDestroy = /** @@ -2672,7 +2685,7 @@ LLSE_Item.prototype.canDestroy = */ function (block) { return GMLIB_API.itemCanDestroyBlock(this, block); - } + }; LLSE_Item.prototype.canDestroyInCreative = /** @@ -2681,7 +2694,7 @@ LLSE_Item.prototype.canDestroyInCreative = */ function () { return GMLIB_API.itemCanDestroyInCreative(this); - } + }; LLSE_Item.prototype.canDestroySpecial = /** @@ -2691,7 +2704,7 @@ LLSE_Item.prototype.canDestroySpecial = */ function (block) { return GMLIB_API.itemCanDestroySpecial(this, block); - } + }; LLSE_Block.prototype.canDropWithAnyTool = /** @@ -2700,16 +2713,7 @@ LLSE_Block.prototype.canDropWithAnyTool = */ function () { return GMLIB_API.blockCanDropWithAnyTool(this); - } - -LLSE_Block.prototype.isAlwaysDestroyable = - /** - * 方块是否不需要工具采集 - * @returns {boolean} 方块是否不需要工具采集 - */ - function () { - return GMLIB_API.blockIsAlwaysDestroyable(this); - } + }; LLSE_Block.prototype.playerWillDestroy = /** @@ -2719,7 +2723,7 @@ LLSE_Block.prototype.playerWillDestroy = */ function (player) { return GMLIB_API.blockPlayerWillDestroy(this, player, this.pos); - } + }; LLSE_Player.prototype.attack = /** @@ -2729,7 +2733,7 @@ LLSE_Player.prototype.attack = */ function (entity) { return GMLIB_API.playerAttack(this, entity); - } + }; LLSE_Player.prototype.pullInEntity = /** @@ -2739,16 +2743,7 @@ LLSE_Player.prototype.pullInEntity = */ function (entity) { return GMLIB_API.playerPullInEntity(this, entity); - } - -LLSE_Item.prototype.getLegalEnchants = - /** - * 获取物品可以拥有的合法附魔 - * @returns {Array.} 附魔ID列表 - */ - function () { - return GMLIB_API.getLegalEnchants(this); - } + }; LLSE_Item.prototype.applyEnchant = /** @@ -2760,7 +2755,7 @@ LLSE_Item.prototype.applyEnchant = */ function (typeName, level, allowNonVanilla = true) { return GMLIB_API.applyEnchant(this, typeName, level, allowNonVanilla); - } + }; LLSE_Item.prototype.removeEnchants = /** @@ -2768,7 +2763,7 @@ LLSE_Item.prototype.removeEnchants = */ function () { GMLIB_API.removeEnchants(this); - } + }; LLSE_Item.prototype.hasEnchant = /** @@ -2778,7 +2773,7 @@ LLSE_Item.prototype.hasEnchant = */ function (typeName) { return GMLIB_API.hasEnchant(this, typeName); - } + }; LLSE_Item.prototype.getEnchantLevel = /** @@ -2788,7 +2783,7 @@ LLSE_Item.prototype.getEnchantLevel = */ function (typeName) { return GMLIB_API.getEnchantLevel(this, typeName); - } + }; LLSE_Player.prototype.dropItem = /** @@ -2799,7 +2794,7 @@ LLSE_Player.prototype.dropItem = */ function (item, randomly = false) { return GMLIB_API.dropPlayerItem(this, item, randomly); - } + }; LLSE_Player.prototype.getRuntimeId = /** @@ -2808,7 +2803,7 @@ LLSE_Player.prototype.getRuntimeId = */ function () { return GMLIB_API.getPlayerRuntimeId(this); - } + }; LLSE_Entity.prototype.getRuntimeId = /** @@ -2817,7 +2812,7 @@ LLSE_Entity.prototype.getRuntimeId = */ function () { return GMLIB_API.getEntityRuntimeId(this); - } + }; LLSE_Entity.prototype.getNameTag = /** @@ -2826,7 +2821,7 @@ LLSE_Entity.prototype.getNameTag = */ function () { return GMLIB_API.getEntityNameTag(this); - } + }; LLSE_Item.prototype.isUnbreakable = /** @@ -2835,7 +2830,7 @@ LLSE_Item.prototype.isUnbreakable = */ function () { return GMLIB_API.ItemisUnbreakable(this); - } + }; LLSE_Item.prototype.setUnbreakable = /** @@ -2844,7 +2839,7 @@ LLSE_Item.prototype.setUnbreakable = */ function (value) { GMLIB_API.setItemUnbreakable(this, value); - } + }; LLSE_Item.prototype.getShouldKeepOnDeath = /** @@ -2853,7 +2848,7 @@ LLSE_Item.prototype.getShouldKeepOnDeath = */ function () { return GMLIB_API.getItemShouldKeepOnDeath(this); - } + }; LLSE_Item.prototype.setShouldKeepOnDeath = /** @@ -2862,7 +2857,7 @@ LLSE_Item.prototype.setShouldKeepOnDeath = */ function (value) { GMLIB_API.setItemShouldKeepOnDeath(this, value); - } + }; LLSE_Item.prototype.getItemLockMode = /** @@ -2870,8 +2865,8 @@ LLSE_Item.prototype.getItemLockMode = * @returns {0|1|2} 锁定的模式 0:无 1:锁定在格子里 2:锁定在背包里 */ function () { - return GMLIB_API.getItemLockMode(this) - } + return GMLIB_API.getItemLockMode(this); + }; LLSE_Item.prototype.setItemLockMode = /** @@ -2880,7 +2875,7 @@ LLSE_Item.prototype.setItemLockMode = */ function (mode) { GMLIB_API.setItemLockMode(this, mode); - } + }; LLSE_Item.prototype.getRepairCost = /** @@ -2889,7 +2884,7 @@ LLSE_Item.prototype.getRepairCost = */ function () { return GMLIB_API.getItemRepairCost(this); - } + }; LLSE_Item.prototype.setRepairCost = /** @@ -2898,7 +2893,7 @@ LLSE_Item.prototype.setRepairCost = */ function (cost) { return GMLIB_API.setItemRepairCost(this, cost); - } + }; LLSE_Item.prototype.getCanDestroy = /** @@ -2907,7 +2902,7 @@ LLSE_Item.prototype.getCanDestroy = */ function () { return GMLIB_API.getItemCanDestroy(this); - } + }; LLSE_Item.prototype.setCanDestroy = /** @@ -2916,7 +2911,7 @@ LLSE_Item.prototype.setCanDestroy = */ function (blocks) { GMLIB_API.setItemCanDestroy(this, blocks); - } + }; LLSE_Item.prototype.getCanPlaceOn = /** @@ -2925,7 +2920,7 @@ LLSE_Item.prototype.getCanPlaceOn = */ function () { return GMLIB_API.getItemCanPlaceOn(this); - } + }; LLSE_Item.prototype.setCanPlaceOn = /** @@ -2934,7 +2929,7 @@ LLSE_Item.prototype.setCanPlaceOn = */ function (blocks) { GMLIB_API.setItemCanPlaceOn(this, blocks); - } + }; LLSE_Player.prototype.getHungry = /** @@ -2943,7 +2938,7 @@ LLSE_Player.prototype.getHungry = */ function () { return GMLIB_API.getPlayerHungry(this); - } + }; LLSE_Player.prototype.getArmorCoverPercentage = /** @@ -2952,7 +2947,7 @@ LLSE_Player.prototype.getArmorCoverPercentage = */ function () { return GMLIB_API.getPlayerArmorCoverPercentage(this); - } + }; LLSE_Player.prototype.getArmorValue = /** @@ -2961,7 +2956,7 @@ LLSE_Player.prototype.getArmorValue = */ function () { return GMLIB_API.getPlayerArmorValue(this); - } + }; LLSE_Entity.prototype.getEntityOwner = /** @@ -2971,7 +2966,7 @@ LLSE_Entity.prototype.getEntityOwner = function () { const uniqueId = GMLIB_API.getEntityOwnerUniqueId(this); return uniqueId === -1 ? null : Minecraft.getEntityFromUniqueId(uniqueId); - } + }; LLSE_Item.prototype.getCategoryName = /** @@ -2980,7 +2975,7 @@ LLSE_Item.prototype.getCategoryName = */ function () { return GMLIB_API.getItemCategoryName(this); - } + }; LLSE_Item.prototype.getCustomName = /** @@ -2989,7 +2984,7 @@ LLSE_Item.prototype.getCustomName = */ function () { return GMLIB_API.getItemCustomName(this); - } + }; LLSE_Item.prototype.getEffecName = /** @@ -2998,7 +2993,7 @@ LLSE_Item.prototype.getEffecName = */ function () { return GMLIB_API.getItemEffecName(this); - } + }; LLSE_Item.prototype.isFood = /** @@ -3007,7 +3002,7 @@ LLSE_Item.prototype.isFood = */ function () { return GMLIB_API.itemIsFood(this); - } + }; LLSE_Player.prototype.setPlayerUIItem = /** @@ -3017,7 +3012,7 @@ LLSE_Player.prototype.setPlayerUIItem = */ function (slot, item) { GMLIB_API.setPlayerUIItem(this, slot, item); - } + }; LLSE_Player.prototype.getPlayerUIItem = /** @@ -3027,7 +3022,7 @@ LLSE_Player.prototype.getPlayerUIItem = */ function (slot) { return GMLIB_API.getPlayerUIItem(this, slot); - } + }; LLSE_Player.prototype.sendInventorySlotPacket = /** @@ -3038,7 +3033,7 @@ LLSE_Player.prototype.sendInventorySlotPacket = */ function (containerId, slot, item) { GMLIB_API.sendInventorySlotPacket(this, containerId, slot, item); - } + }; LLSE_Container.prototype.getContainerType = /** @@ -3047,7 +3042,7 @@ LLSE_Container.prototype.getContainerType = */ function () { return GMLIB_API.getContainerType(this); - } + }; LLSE_Item.prototype.getMaxCount = /** @@ -3056,7 +3051,7 @@ LLSE_Item.prototype.getMaxCount = */ function () { return GMLIB_API.getItemMaxCount(this); - } + }; LLSE_Entity.prototype.hasFamily = /** @@ -3066,7 +3061,7 @@ LLSE_Entity.prototype.hasFamily = */ function (family) { return GMLIB_API.entityHasFamily(this, family); - } + }; LLSE_Player.prototype.getDestroyProgress = /** @@ -3076,7 +3071,7 @@ LLSE_Player.prototype.getDestroyProgress = */ function (block) { return GMLIB_API.getPlayerDestroyBlockProgress(this, block); - } + }; LLSE_Entity.prototype.hasEffect = /** @@ -3086,7 +3081,7 @@ LLSE_Entity.prototype.hasEffect = */ function (effectId) { return GMLIB_API.entityHasEffect(this, effectId); - } + }; LLSE_Entity.prototype.getEffectInfo = /** @@ -3105,8 +3100,8 @@ LLSE_Entity.prototype.getEffectInfo = DurationHard: GMLIB_API.getEntityEffectDurationHard(this, effectId), Ambient: GMLIB_API.getEntityEffectAmbient(this, effectId), ShowParticles: GMLIB_API.getEntityEffectVisible(this, effectId), - } - } + }; + }; LLSE_Entity.prototype.getAllEffectsInfo = /** @@ -3115,7 +3110,195 @@ LLSE_Entity.prototype.getAllEffectsInfo = */ function () { return this.getAllEffects().map(effectId => this.getEffectInfo(effectId)); - } + }; + +LLSE_Entity.prototype.isType = + /** + * 是否为某类型 + * @param {number} type 类型 + * @returns {boolean} + */ + function (type) { + return GMLIB_API.entityIsType(this, type); + }; + +LLSE_Entity.prototype.hasType = + /** + * 是否包含某类型 + * @param {number} type 类型 + * @returns {boolean} + */ + function (type) { + return GMLIB_API.entityHasType(this, type); + }; + +LLSE_Entity.prototype.getEntityTypeId = + /** + * 获取实体类型ID + * @returns {number} + */ + function () { + return GMLIB_API.getEntityTypeId(this); + }; + +const ActorType = Object.freeze({ + Undefined: 1, + TypeMask: 0b11111111, + None: 0, + Mob: 1 << 8, + PathfinderMob: 1 << 9 | this.Mob, + UnknownType: 1 << 10, + Monster: 1 << 11 | this.PathfinderMob, + Animal: 1 << 12 | this.PathfinderMob, + WaterAnimal: 1 << 13 | this.PathfinderMob, + TamableAnimal: 1 << 14 | this.Animal, + Ambient: 1 << 15 | this.Mob, + UndeadMob: 1 << 16 | this.Monster, + ZombieMonster: 1 << 17 | this.UndeadMob, + Arthropod: 1 << 18 | this.Monster, + Minecart: 1 << 19, + SkeletonMonster: 1 << 20 | this.UndeadMob, + EquineAnimal: 1 << 21 | this.TamableAnimal, + Projectile: 1 << 22, + AbstractArrow: 1 << 23, + VillagerBase: 1 << 24 | this.PathfinderMob, + + Chicken: 10 | this.Animal, + Cow: 11 | this.Animal, + Pig: 12 | this.Animal, + Sheep: 13 | this.Animal, + Wolf: 14 | this.TamableAnimal, + Villager: 15 | this.VillagerBase, + MushroomCow: 16 | this.Animal, + Squid: 17 | this.WaterAnimal, + Rabbit: 18 | this.Animal, + Bat: 19 | this.Ambient, + IronGolem: 20 | this.PathfinderMob, + SnowGolem: 21 | this.PathfinderMob, + Ocelot: 22 | this.TamableAnimal, + Horse: 23 | this.EquineAnimal, + Donkey: 24 | this.EquineAnimal, + Mule: 25 | this.EquineAnimal, + SkeletonHorse: 26 | this.EquineAnimal | this.UndeadMob, + ZombieHorse: 27 | this.EquineAnimal | this.UndeadMob, + PolarBear: 28 | this.Animal, + Llama: 29 | this.Animal, + Parrot: 30 | this.TamableAnimal, + Dolphin: 31 | this.WaterAnimal, + Zombie: 32 | this.ZombieMonster, + Creeper: 33 | this.Monster, + Skeleton: 34 | this.SkeletonMonster, + Spider: 35 | this.Arthropod, + PigZombie: 36 | this.UndeadMob, + Slime: 37 | this.Monster, + EnderMan: 38 | this.Monster, + Silverfish: 39 | this.Arthropod, + CaveSpider: 40 | this.Arthropod, + Ghast: 41 | this.Monster, + LavaSlime: 42 | this.Monster, + Blaze: 43 | this.Monster, + ZombieVillager: 44 | this.ZombieMonster, + Witch: 45 | this.Monster, + Stray: 46 | this.SkeletonMonster, + Husk: 47 | this.ZombieMonster, + WitherSkeleton: 48 | this.SkeletonMonster, + Guardian: 49 | this.Monster, + ElderGuardian: 50 | this.Monster, + Npc: 51 | this.Mob, + WitherBoss: 52 | this.UndeadMob, + Dragon: 53 | this.Monster, + Shulker: 54 | this.Monster, + Endermite: 55 | this.Arthropod, + Agent: 56 | this.Mob, + Vindicator: 57 | this.Monster, + Phantom: 58 | this.UndeadMob, + IllagerBeast: 59 | this.Monster, + UNUSED60: 60, + ArmorStand: 61 | this.Mob, + TripodCamera: 62 | this.Mob, + Player: 63 | this.Mob, + ItemEntity: 64 | this.None, + PrimedTnt: 65 | this.None, + FallingBlock: 66 | this.None, + MovingBlock: 67 | this.None, + ExperiencePotion: 68 | this.Projectile, + Experience: 69 | this.None, + EyeOfEnder: 70 | this.None, + EnderCrystal: 71 | this.None, + FireworksRocket: 72 | this.None, + Trident: 73 | this.Projectile | this.AbstractArrow, + Turtle: 74 | this.Animal, + Cat: 75 | this.TamableAnimal, + ShulkerBullet: 76 | this.Projectile, + FishingHook: 77 | this.None, + Chalkboard: 78 | this.None, + DragonFireball: 79 | this.Projectile, + Arrow: 80 | this.Projectile | this.AbstractArrow, + Snowball: 81 | this.Projectile, + ThrownEgg: 82 | this.Projectile, + Painting: 83 | this.None, + MinecartRideable: 84 | this.Minecart, + LargeFireball: 85 | this.Projectile, + ThrownPotion: 86 | this.Projectile, + Enderpearl: 87 | this.Projectile, + LeashKnot: 88 | this.None, + WitherSkull: 89 | this.Projectile, + BoatRideable: 90 | this.None, + WitherSkullDangerous: 91 | this.Projectile, + UNUSED92: 92, + LightningBolt: 93 | this.None, + SmallFireball: 94 | this.Projectile, + AreaEffectCloud: 95 | this.None, + MinecartHopper: 96 | this.Minecart, + MinecartTNT: 97 | this.Minecart, + MinecartChest: 98 | this.Minecart, + MinecartFurnace: 99 | this.Minecart, + MinecartCommandBlock: 100 | this.Minecart, + LingeringPotion: 101 | this.Projectile, + LlamaSpit: 102 | this.Projectile, + EvocationFang: 103 | this.Projectile, + EvocationIllager: 104 | this.Monster, + Vex: 105 | this.Monster, + IceBomb: 106 | this.Projectile, + Balloon: 107 | this.None, + Pufferfish: 108 | this.WaterAnimal, + Salmon: 109 | this.WaterAnimal, + Drowned: 110 | this.ZombieMonster, + Tropicalfish: 111 | this.WaterAnimal, + Fish: 112 | this.WaterAnimal, + Panda: 113 | this.Animal, + Pillager: 114 | this.Monster, + VillagerV2: 115 | this.VillagerBase, + ZombieVillagerV2: 116 | this.ZombieMonster, + Shield: 117 | this.None, + WanderingTrader: 118 | this.PathfinderMob, + Lectern: 119 | this.None, + ElderGuardianGhost: 120 | this.Monster, + Fox: 121 | this.Animal, + Bee: 122 | this.Mob, + Piglin: 123 | this.Mob, + Hoglin: 124 | this.Animal, + Strider: 125 | this.Animal, + Zoglin: 126 | this.UndeadMob, + PiglinBrute: 127 | this.Mob, + Goat: 128 | this.Animal, + GlowSquid: 129 | this.WaterAnimal, + Axolotl: 130 | this.Animal, + Warden: 131 | this.Monster, + Frog: 132 | this.Animal, + Tadpole: 133 | this.WaterAnimal, + Allay: 134 | this.Mob, + ChestBoatRideable: 136 | this.BoatRideable, + TraderLlama: 137 | this.Llama, + Camel: 138 | this.Animal, + Sniffer: 139 | this.Animal, + Breeze: 140 | this.Monster, + BreezeWindChargeProjectile: 141 | this.Projectile, + Armadillo: 142 | this.Animal, + WindChargeProjectile: 143 | this.Projectile, + Bogged: 144 | this.SkeletonMonster, + OminousItemSpawner: 145, +}); module.exports = { StaticFloatingText, @@ -3130,5 +3313,6 @@ module.exports = { Version, I18nAPI, UserCache, - GMLIB_BinaryStream + GMLIB_BinaryStream, + ActorType }; \ No newline at end of file diff --git a/manifest.json b/manifest.json index a83331b..51f93d3 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "${pluginName}", "entry": "${pluginFile}", - "version": "0.13.4", + "version": "0.13.6", "author": "GroupMountain", "type": "native", "passive": true, diff --git a/src/BinaryStreamApi.cpp b/src/BinaryStreamApi.cpp index 7eb6e95..be6c5ec 100644 --- a/src/BinaryStreamApi.cpp +++ b/src/BinaryStreamApi.cpp @@ -11,6 +11,15 @@ public: void cretateBinaryStream(uint id) { mBinaryStream[id] = std::make_shared(); } + uint64 copyBinaryStream(uint id) { + auto nextId = getNextId(); + cretateBinaryStream(nextId); + if(auto bs = getBinaryStream(nextId); bs !=nullptr){ + getBinaryStream(nextId)->mBuffer = getBinaryStream(id)->mBuffer; + } + return nextId; + } + void removeBinaryStream(uint64 id) { mBinaryStream.erase(id); } std::shared_ptr getBinaryStream(uint64 id) { @@ -46,6 +55,9 @@ void Export_BinaryStream_API() { BinaryStreamManager.cretateBinaryStream(id); return id; }); + RemoteCall::exportAs("GMLIB_BinaryStream_API", "copy", [](uint64 id) -> uint64 { + return BinaryStreamManager.copyBinaryStream(id); + }); RemoteCall::exportAs("GMLIB_BinaryStream_API", "reset", [](uint64 id) -> void { if (BinaryStreamManager.getBinaryStream(id) == nullptr) BinaryStreamManager.cretateBinaryStream(id); else BinaryStreamManager.getBinaryStream(id)->reset(); diff --git a/src/CompatibilityApi.cpp b/src/CompatibilityApi.cpp index 68e997a..66b067a 100644 --- a/src/CompatibilityApi.cpp +++ b/src/CompatibilityApi.cpp @@ -1,3 +1,4 @@ +#include "GMLIB/Mod/CustomRecipe/CustomRecipe.h" #include "Global.h" #include @@ -7,7 +8,7 @@ bool isInteger(const std::string& str) { } ActorUniqueID parseScriptUniqueID(std::string const& uniqueId) { - return isInteger(uniqueId) ? ActorUniqueID(std::stoll(uniqueId)) : ActorUniqueID::INVALID_ID; + return isInteger(uniqueId) ? ActorUniqueID(std::stoll(uniqueId)) : ActorUniqueID::INVALID_ID(); } void Export_Compatibility_API() { @@ -394,7 +395,7 @@ void Export_Compatibility_API() { RemoteCall::exportAs("GMLIB_API", "getAllScoreboardEntities", []() -> std::vector { std::vector result; for (auto& uniqueId : GMLIB_Scoreboard::getInstance()->getAllEntities()) { - result.push_back(std::to_string(uniqueId.id)); + result.push_back(std::to_string(uniqueId.rawID)); } return result; }); @@ -418,7 +419,7 @@ void Export_Compatibility_API() { for (auto& uniqueId : GMLIB_Scoreboard::getInstance()->getAllEntities()) { result.push_back({ {"Type", "Entity" }, - {"UniqueId", std::to_string(uniqueId.id)} + {"UniqueId", std::to_string(uniqueId.rawID)} }); } return result; @@ -431,7 +432,7 @@ void Export_Compatibility_API() { return ll::service::getLevel()->getPlayer(parseScriptUniqueID(uniqueId)); }); RemoteCall::exportAs("GMLIB_API", "getEntityFromUniqueId", [](std::string const& uniqueId) -> Actor* { - return ll::service::getLevel()->fetchEntity(parseScriptUniqueID(uniqueId)); + return ll::service::getLevel()->fetchEntity(parseScriptUniqueID(uniqueId), false); }); RemoteCall::exportAs("GMLIB_API", "getWorldSpawn", []() -> std::pair { return {GMLIB_Level::getInstance()->getWorldSpawn(), 0}; @@ -555,10 +556,7 @@ void Export_Compatibility_API() { return item->canDestroySpecial(*block); }); RemoteCall::exportAs("GMLIB_API", "blockCanDropWithAnyTool", [](Block const* block) -> bool { - return block->canDropWithAnyTool(); - }); - RemoteCall::exportAs("GMLIB_API", "blockIsAlwaysDestroyable", [](Block const* block) -> bool { - return block->getMaterial().isAlwaysDestroyable(); + return !block->requiresCorrectToolForDrops(); }); RemoteCall::exportAs( "GMLIB_API", @@ -583,7 +581,7 @@ void Export_Compatibility_API() { "getBlockLightEmission", [](std::string const& blockName, short legacyData) -> char { return Block::tryGetFromRegistry(blockName) - .transform([](const Block& block) -> char { return (char)block.getLightEmission().value; }) + .transform([](const Block& block) -> char { return (char)block.getLightEmission().mValue; }) .value_or(-1); } ); @@ -622,13 +620,6 @@ void Export_Compatibility_API() { return result; } ); - RemoteCall::exportAs("GMLIB_API", "getLegalEnchants", [](ItemStack const* item) -> std::vector { - std::vector result; - for (auto& enchant : EnchantUtils::getLegalEnchants(item->getItem())) { - result.push_back(Enchant::getEnchant((Enchant::Type)enchant)->getStringId()); - } - return result; - }); RemoteCall::exportAs("GMLIB_API", "getEnchantTypeNameFromId", [](int id) -> std::string { if (auto enchant = Enchant::getEnchant((Enchant::Type)id)) { return std::string(enchant->getStringId()); @@ -669,10 +660,10 @@ void Export_Compatibility_API() { [](Player* player, ItemStack const* item, bool randomly) -> bool { return player->drop(*item, randomly); } ); RemoteCall::exportAs("GMLIB_API", "getPlayerRuntimeId", [](Player* player) -> uint64 { - return player->getRuntimeID().id; + return player->getRuntimeID().rawID; }); RemoteCall::exportAs("GMLIB_API", "getEntityRuntimeId", [](Actor* entity) -> uint64 { - return entity->getRuntimeID().id; + return entity->getRuntimeID().rawID; }); RemoteCall::exportAs("GMLIB_API", "getEntityNameTag", [](Actor* entity) -> std::string { return entity->getNameTag(); @@ -730,7 +721,7 @@ void Export_Compatibility_API() { } ); RemoteCall::exportAs("GMLIB_API", "getPlayerHungry", [](Player* player) -> float { - return player->getMutableAttribute(Player::HUNGER)->getCurrentValue(); + return player->getMutableAttribute(Player::HUNGER())->getCurrentValue(); }); RemoteCall::exportAs("GMLIB_API", "getPlayerArmorCoverPercentage", [](Player* player) -> float { return player->getArmorCoverPercentage(); @@ -739,7 +730,7 @@ void Export_Compatibility_API() { return player->getArmorValue(); }); RemoteCall::exportAs("GMLIB_API", "getEntityOwnerUniqueId", [](Actor* entity) -> int64 { - return entity->getOwnerId().id; + return entity->getOwnerId().rawID; }); RemoteCall::exportAs("GMLIB_API", "getItemCategoryName", [](ItemStack const* item) -> std::string { return item->getCategoryName(); @@ -757,7 +748,7 @@ void Export_Compatibility_API() { return false; }); RemoteCall::exportAs("GMLIB_API", "setPlayerUIItem", [](Player* player, int slot, ItemStack const* item) -> void { - player->setPlayerUIItem((PlayerUISlot)slot, *item); + player->setPlayerUIItem((PlayerUISlot)slot, *item, false); }); RemoteCall::exportAs("GMLIB_API", "getPlayerUIItem", [](Player* player, int slot) -> ItemStack* { return const_cast(&player->getPlayerUIItem((PlayerUISlot)slot)); @@ -792,25 +783,25 @@ void Export_Compatibility_API() { }); RemoteCall::exportAs("GMLIB_API", "getEntityEffectDuration", [](Actor* entity, int effectId) -> int { if (auto effect = entity->getEffect(effectId)) { - return effect->mDuration; + return effect->mDuration->mValue; } return 0; }); RemoteCall::exportAs("GMLIB_API", "getEntityEffectDurationEasy", [](Actor* entity, int effectId) -> int { if (auto effect = entity->getEffect(effectId)) { - return effect->mDurationEasy; + return effect->mDurationEasy->transform([](auto&& duration) -> int { return duration.mValue; }).value_or(0); } return 0; }); RemoteCall::exportAs("GMLIB_API", "getEntityEffectDurationHard", [](Actor* entity, int effectId) -> int { if (auto effect = entity->getEffect(effectId)) { - return effect->mDurationHard; + return effect->mDurationHard->transform([](auto&& duration) -> int { return duration.mValue; }).value_or(0); } return 0; }); RemoteCall::exportAs("GMLIB_API", "getEntityEffectDurationNormal", [](Actor* entity, int effectId) -> int { if (auto effect = entity->getEffect(effectId)) { - return effect->mDurationNormal; + return effect->mDurationNormal->transform([](auto&& duration) -> int { return duration.mValue; }).value_or(0); } return 0; }); @@ -857,7 +848,13 @@ void Export_Compatibility_API() { std::vector types; char rt = 'A'; for (auto& ing : ingredients) { - types.emplace_back(ing, rt++, 1, 0); + auto ingredient = RecipeIngredient{ing, 0,1}; + types.push_back(Recipes::Type{ + (Item*)ingredient.getItem(), + ingredient.getBlock(), + ingredient, + rt++ + }); } GMLIB::Mod::CustomRecipe::registerShapelessCraftingTableRecipe(recipe_id, types, *result); } @@ -873,9 +870,32 @@ void Export_Compatibility_API() { std::vector types; char rt = 'A'; for (auto& ing : ingredients) { - types.emplace_back(ing, rt++, 1, 0); + auto ingredient = RecipeIngredient{ing, 0, 1}; + types.push_back(Recipes::Type{(Item*)ingredient.getItem(), ingredient.getBlock(), ingredient, rt++}); } - GMLIB::Mod::CustomRecipe::registerShapedCraftingTableRecipe(recipe_id, shape, types, *result); + auto tmp = RecipeUnlockingRequirement(); + tmp.mContext = RecipeUnlockingRequirement::UnlockingContext::AlwaysUnlocked; + ll::service::bedrock::getLevel()->getRecipes().addShapedRecipe( + recipe_id, + ItemInstance(*result), + shape, + types, + {"crafting_table"}, + 50, + nullptr, + tmp, + SemVersion(1, 20, 80, "", ""), + true + ); } ); + RemoteCall::exportAs("GMLIB_API", "entityIsType", [](Actor* entity, int type) -> bool { + return entity->isType((ActorType)type); + }); + RemoteCall::exportAs("GMLIB_API", "entityHasType", [](Actor* entity, int type) -> bool { + return entity->hasType((ActorType)type); + }); + RemoteCall::exportAs("GMLIB_API", "getEntityTypeId", [](Actor* entity) -> int { + return (int)entity->getEntityTypeId(); + }); } \ No newline at end of file diff --git a/src/Entry.cpp b/src/Entry.cpp index 51d0135..18fcd80 100644 --- a/src/Entry.cpp +++ b/src/Entry.cpp @@ -1,12 +1,10 @@ #include "Entry.h" #include "Global.h" -ll::Logger logger(PLUGIN_NAME); - namespace gmlib { -std::unique_ptr& LegacyRemoteCallApi::getInstance() { - static std::unique_ptr instance; +LegacyRemoteCallApi& LegacyRemoteCallApi::getInstance() { + static LegacyRemoteCallApi instance; return instance; } @@ -18,14 +16,15 @@ bool LegacyRemoteCallApi::load() { Export_Event_API(); Export_BinaryStream_API(); // Export_Form_API(); - logger.info("GMLIB-LegacyRemoteCallApi Loaded!"); - logger.info( + auto logger = ll::io::LoggerRegistry::getInstance().getOrCreate(PLUGIN_NAME); + logger->info("GMLIB-LegacyRemoteCallApi Loaded!"); + logger->info( "Loaded Version: {} with {}", fmt::format(fg(fmt::color::pink), "GMLIB-" + GMLIB::Version::getLibVersionString()), fmt::format(fg(fmt::color::light_green), "GMLIB-LegacyRemoteCallApi-" + LIB_VERSION.asString()) ); - logger.info("Author: GroupMountain"); - logger.info("Repository: https://github.com/GroupMountain/GMLIB-LegacyRemoteCallApi"); + logger->info("Author: GroupMountain"); + logger->info("Repository: https://github.com/GroupMountain/GMLIB-LegacyRemoteCallApi"); return true; } diff --git a/src/Entry.h b/src/Entry.h index 0606144..b24b034 100644 --- a/src/Entry.h +++ b/src/Entry.h @@ -7,9 +7,9 @@ namespace gmlib { class LegacyRemoteCallApi { public: - static std::unique_ptr& getInstance(); + static LegacyRemoteCallApi& getInstance(); - LegacyRemoteCallApi(ll::mod::NativeMod& self) : mSelf(self) {} + LegacyRemoteCallApi() : mSelf(*ll::mod::NativeMod::current()) {} [[nodiscard]] ll::mod::NativeMod& getSelf() const { return mSelf; } diff --git a/src/EventAPI.cpp b/src/EventAPI.cpp index c040bb9..c3772ef 100644 --- a/src/EventAPI.cpp +++ b/src/EventAPI.cpp @@ -1,249 +1,356 @@ #include "Global.h" using namespace ll::hash_utils; -class LegacyScriptEventManager { +class EventManager { private: - int64 mNextEventId = 0; - std::unordered_map mEventListeners; + std::unordered_map mEventIds; public: - std::string getNextEventId() { - mNextEventId++; - return "GMLIB_EVENT_" + std::to_string(mNextEventId); - } - - void emplaceListener(std::string const& scriptEventId, ll::event::ListenerPtr listenerPtr) { - mEventListeners[doHash(scriptEventId)] = std::move(listenerPtr); - } - - void removeListener(std::string const& scriptEventId) { - ll::event::EventBus::getInstance().removeListener(mEventListeners[doHash(scriptEventId)]); - mEventListeners.erase(doHash(scriptEventId)); - } - -public: - static LegacyScriptEventManager& getInstance() { - static std::unique_ptr instance; - if (!instance) { - instance = std::make_unique(); - } + static EventManager& getInstance() { + static std::unique_ptr instance; + if (!instance) instance = std::make_unique(); return *instance; } + + ullong getNextId() { + auto id = mEventIds.size(); + mEventIds.emplace(id, nullptr); + return id; + } + + bool addListener(ullong id, ll::event::ListenerPtr const& listener) { + if (mEventIds.contains(id) && mEventIds[id]) return false; + mEventIds[id] = listener; + return true; + } + + bool removeListener(ullong id) { + if (ll::event::EventBus::getInstance().removeListener(mEventIds[id])) { + mEventIds[id] = nullptr; + return true; + } + return false; + } + + bool hasListener(ullong id) { return mEventIds.contains(id) && mEventIds[id]; } + + ll::event::ListenerPtr getListener(ullong id) { return mEventIds.contains(id) ? mEventIds[id] : nullptr; } }; -#define REGISTER_EVENT_LISTEN(eventType, callFunction, eventParams, cancelFunction, otherFunction) \ - eventManager.emplaceListener( \ - eventId, \ - eventBus.emplaceListener([eventName, eventId, &eventBus, &eventManager](eventType& ev) -> void { \ - if (!RemoteCall::hasFunc(eventName, eventId)) { \ - eventManager.removeListener(eventId); \ +#define REGISTER_EVENT_LISTEN(eventType, paramType, params, cancelFun, ...) \ + auto eventPtr = ll::event::EventBus::getInstance().emplaceListener( \ + [pluginName, eventName, eventId](eventType& event) -> void { \ + if (!RemoteCall::hasFunc(pluginName, eventName + "_" + std::to_string(eventId))) { \ + EventManager::getInstance().removeListener(eventId); \ return; \ } \ - bool result = true; \ try { \ - otherFunction; \ - result = RemoteCall::importAs(eventName, eventId) eventParams; \ + __VA_ARGS__ \ + auto result = \ + RemoteCall::importAs(pluginName, eventName + "_" + std::to_string(eventId)) \ + params; \ + cancelFun \ } catch (...) {} \ - if (!result) cancelFunction; \ - }) \ + }, \ + ll::event::EventPriority(priority) \ ); \ - return true; + return eventId void Export_Event_API() { - RemoteCall::exportAs("GMLIB_Event_API", "getNextScriptEventId", []() -> std::string { - return LegacyScriptEventManager::getInstance().getNextEventId(); + RemoteCall::exportAs("GMLIB_Event_API", "removeListener", [](ll::event::ListenerId eventId) -> bool { + return EventManager::getInstance().removeListener(eventId); }); - auto& eventBus = ll::event::EventBus::getInstance(); - auto& eventManager = LegacyScriptEventManager::getInstance(); + + RemoteCall::exportAs("GMLIB_Event_API", "hasListener", [](ll::event::ListenerId eventId) -> bool { + return EventManager::getInstance().hasListener(eventId); + }); + + RemoteCall::exportAs("GMLIB_Event_API", "getListenerPriority", [](ll::event::ListenerId eventId) -> int { + if (auto event = EventManager::getInstance().getListener(eventId); event != nullptr) { + return (int)event->getPriority(); + } + return -1; + }); + RemoteCall::exportAs( "GMLIB_Event_API", - "callCustomEvent", - [&eventBus, &eventManager](std::string const& eventName, std::string const& eventId) -> bool { - if (!RemoteCall::hasFunc(eventName, eventId)) return false; + "emplaceListener", + [](std::string const& pluginName, std::string const& eventName, int priority) -> llong { + auto eventId = EventManager::getInstance().getNextId(); switch (doHash(eventName)) { - case doHash("onClientLogin"): { + case doHash("ll::ServerStoppingEvent"): { + REGISTER_EVENT_LISTEN(ll::event::ServerStoppingEvent, (), (), , ); + } + case doHash("gmlib::ClientLoginAfterEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::PacketEvent::ClientLoginAfterEvent, (std::string const& realName, std::string const& uuid, std::string const& serverXuid, std::string const& clientXuid), - (ev.getRealName(), ev.getUuid().asString(), ev.getServerAuthXuid(), ev.getClientAuthXuid()), - logger.error("Event \"onClientLogin\" cannot be intercepted"), - ) + (event.getRealName(), + event.getUuid().asString(), + event.getServerAuthXuid(), + event.getClientAuthXuid()), + if (result) event.disConnectClient(); + ); } - case doHash("onWeatherChange"): { + case doHash("gmlib::WeatherUpdateBeforeEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::LevelEvent::WeatherUpdateBeforeEvent, - (int lightningLevel, int rainLevel, int lightningLast, int rainLast), - (ev.getLightningLevel(), ev.getRainLevel(), ev.getLightningLastTick(), ev.getRainingLastTick()), - ev.cancel(), - ) + (float rainLevel, int rainTime, float lightningLevel, int lightningTime, bool isCancelled), + (event.getRainLevel(), + event.getRainingLastTick(), + event.getLightningLevel(), + event.getLightningLastTick(), + event.isCancelled()), + event.setCancelled(result); + ); } - case doHash("onMobPick"): { + case doHash("gmlib::WeatherUpdateAfterEvent"): { + REGISTER_EVENT_LISTEN( + GMLIB::Event::LevelEvent::WeatherUpdateAfterEvent, + (float rainLevel, int rainTime, float lightningLevel, int lightningTime), + (event.getRainLevel(), + event.getRainingLastTick(), + event.getLightningLevel(), + event.getLightningLastTick()), + , + ); + } + case doHash("gmlib::MobPickupItemBeforeEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::EntityEvent::MobPickupItemBeforeEvent, - (Actor * mob, Actor * item), - (&ev.self(), (Actor*)&ev.getItemActor()), - ev.cancel(), - ) + (Actor * mob, Actor * item, bool isCancelled), + (&event.self(), (Actor*)&event.getItemActor(), event.isCancelled()), + event.setCancelled(result); + ); } - case doHash("onItemTrySpawn"): { + case doHash("gmlib::MobPickupItemAfterEvent"): { + REGISTER_EVENT_LISTEN( + GMLIB::Event::EntityEvent::MobPickupItemAfterEvent, + (Actor * mob, Actor * item), + (&event.self(), (Actor*)&event.getItemActor()), + , + ); + } + case doHash("gmlib::ItemActorSpawnBeforeEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::EntityEvent::ItemActorSpawnBeforeEvent, - (const ItemStack* item, std::pair position, int64 spawnerUniqueId), - (&ev.getItem(), - {ev.getPosition(), ev.getBlockSource().getDimensionId().id}, - ev.getSpawner().has_value() ? ev.getSpawner()->getOrCreateUniqueID().id : -1), - ev.cancel(), - ) + (ItemStack * item, std::pair position, int64 spawnerUniqueId, bool isCancelled), + (&event.getItem(), + {event.getPosition(), event.getBlockSource().getDimensionId().id}, + event.getSpawner().has_value() ? event.getSpawner()->getOrCreateUniqueID().rawID : -1, + event.isCancelled()), + event.setCancelled(result); + ); } - case doHash("onItemSpawned"): { + case doHash("gmlib::ItemActorSpawnAfterEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::EntityEvent::ItemActorSpawnAfterEvent, - (const ItemStack* item, Actor* itemActor, std::pair position, int64 spawnerUniqueId), - (&ev.getItem(), - (Actor*)&ev.getItemActor(), - {ev.getPosition(), ev.getBlockSource().getDimensionId().id}, - ev.getSpawner().has_value() ? ev.getSpawner()->getOrCreateUniqueID().id : -1), - logger.error("Event \"onItemSpawned\" cannot be intercepted"), - ) + (Actor * item, std::pair position, int64 spawnerUniqueId), + (&event.self(), + {event.getPosition(), event.getBlockSource().getDimensionId().id}, + event.getSpawner().has_value() ? event.getSpawner()->getOrCreateUniqueID().rawID : -1), + , + ); } - case doHash("onEntityTryChangeDim"): { + case doHash("gmlib::ActorChangeDimensionBeforeEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::EntityEvent::ActorChangeDimensionBeforeEvent, - (Actor * entity, int toDimId), - (&ev.self(), ev.getToDimensionId()), - ev.cancel(), - ) + (Actor * entity, int toDimId, bool isCancelled), + (&event.self(), event.getToDimensionId(), event.isCancelled()), + event.setCancelled(result); + ); } - case doHash("onLeaveBed"): { + case doHash("gmlib::ActorChangeDimensionAfterEvent"): { + REGISTER_EVENT_LISTEN( + GMLIB::Event::EntityEvent::ActorChangeDimensionAfterEvent, + (Actor * entity, int fromDimId, int toDimId), + (&event.self(), event.getFromDimensionId(), event.getToDimensionId()), + , + ); + } + case doHash("gmlib::PlayerStartSleepBeforeEvent"): { + REGISTER_EVENT_LISTEN( + GMLIB::Event::PlayerEvent::PlayerStartSleepBeforeEvent, + (Player * entity, BlockPos pos, bool isCancelled), + (&event.self(), event.getPosition(), event.isCancelled()), + event.setCancelled(result); + ); + } + case doHash("gmlib::PlayerStartSleepAfterEvent"): { + REGISTER_EVENT_LISTEN( + GMLIB::Event::PlayerEvent::PlayerStartSleepAfterEvent, + (Player * entity, BlockPos pos, int result), + (&event.self(), event.getPosition(), (int)event.getResult()), + , + ); + } + case doHash("gmlib::PlayerStopSleepBeforeEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::PlayerEvent::PlayerStopSleepBeforeEvent, - (Player * pl), - (&ev.self()), - ev.cancel(), - ) + (Player * entity, bool forcefulWakeUp, bool updateLevelList, bool isCancelled), + (&event.self(), event.isForcefulWakeUp(), event.isUpdateLevelList(), event.isCancelled()), + event.setCancelled(result); + ); } - case doHash("onDeathMessage"): { + case doHash("gmlib::PlayerStopSleepAfterEvent"): { + REGISTER_EVENT_LISTEN( + GMLIB::Event::PlayerEvent::PlayerStopSleepAfterEvent, + (Player * entity, bool forcefulWakeUp, bool updateLevelList, bool), + (&event.self(), event.isForcefulWakeUp(), event.isUpdateLevelList(), false), + , + ); + } + case doHash("gmlib::DeathMessageAfterEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::EntityEvent::DeathMessageAfterEvent, (std::string const& message, std::vector, Actor* dead), - (ev.getDeathMessage().first, ev.getDeathMessage().second, &ev.self()), - logger.error("Event \"onDeathMessage\" cannot be intercepted"), - ) + (event.getDeathMessage().first, event.getDeathMessage().second, &event.self()), + , + ); } - case doHash("onMobHurted"): { + case doHash("gmlib::MobHurtAfterEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::EntityEvent::MobHurtAfterEvent, (Actor * mob, Actor * source, float damage, int cause), - (&ev.self(), source, ev.getDamage(), (int)damageSource.getCause()), - logger.error("Event \"onMobHurted\" cannot be intercepted"), - auto& damageSource = ev.getSource(); + (&event.self(), source, -event.getDamage(), (int)damageSource.getCause()), + , + auto& damageSource = event.getSource(); Actor* source = nullptr; if (damageSource.isEntitySource()) { auto uniqueId = damageSource.getDamagingEntityUniqueID(); - source = ll::service::getLevel()->fetchEntity(uniqueId); + source = ll::service::getLevel()->fetchEntity(uniqueId, false); if (source->getOwner()) source = source->getOwner(); } - ) + ); } - case doHash("onEndermanTake"): { + case doHash("gmlib::EndermanTakeBlockBeforeEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::EntityEvent::EndermanTakeBlockBeforeEvent, - (Actor * mob), - (&ev.self()), - ev.cancel(), - ) + (Actor * mob, bool isCancelled), + (&event.self(), event.isCancelled()), + event.setCancelled(result); + ); } - case doHash("onEntityChangeDim"): { - REGISTER_EVENT_LISTEN( - GMLIB::Event::EntityEvent::ActorChangeDimensionAfterEvent, - (Actor * mob, int fromDimId), - (&ev.self(), ev.getFromDimensionId()), - logger.error("Event \"onEntityChangeDim\" cannot be intercepted"), - ) - } - case doHash("onDragonRespawn"): { + case doHash("gmlib::DragonRespawnBeforeEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::EntityEvent::DragonRespawnBeforeEvent, - (int64 enderDragonUniqueID), - (ev.getEnderDragon().id), - ev.cancel(), - ) + (bool isCancelled), + (event.isCancelled()), + event.setCancelled(result); + ); } - case doHash("onProjectileTryCreate"): { + case doHash("gmlib::DragonRespawnAfterEvent"): { + REGISTER_EVENT_LISTEN( + GMLIB::Event::EntityEvent::DragonRespawnAfterEvent, + (Actor * mob), + (event.getEnderDragon()), + ); + } + case doHash("gmlib::ProjectileCreateBeforeEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::EntityEvent::ProjectileCreateBeforeEvent, - (Actor * mob, int64 uniqueId), - (&ev.self(), ev.getShooter() ? ev.getShooter()->getOrCreateUniqueID().id : -1), - ev.cancel(), - ) + (Actor * mob, int64 uniqueId, bool isCancelled), + (&event.self(), + event.getShooter() ? event.getShooter()->getOrCreateUniqueID().rawID : -1, + event.isCancelled()), + event.setCancelled(result); + ); } - case doHash("onProjectileCreate"): { + case doHash("gmlib::ProjectileCreateAfterEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::EntityEvent::ProjectileCreateAfterEvent, (Actor * mob, int64 uniqueId), - (&ev.self(), ev.getShooter() ? ev.getShooter()->getOrCreateUniqueID().id : -1), - logger.error("Event \"onProjectileCreate\" cannot be intercepted"), - ) + (&event.self(), event.getShooter() ? event.getShooter()->getOrCreateUniqueID().rawID : -1), + ); } - case doHash("onSpawnWanderingTrader"): { + case doHash("gmlib::SpawnWanderingTraderBeforeEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::EntityEvent::SpawnWanderingTraderBeforeEvent, - (std::pair pos), - ({ev.getPos(), ev.getRegion().getDimensionId()}), - ev.cancel(), - ) + (std::pair pos, bool isCancelled), + ({event.getPos(), event.getRegion().getDimensionId()}, event.isCancelled()), + event.setCancelled(result); + ); } - case doHash("onHandleRequestAction"): { - // clang-format off + case doHash("gmlib::SpawnWanderingTraderAfterEvent"): { REGISTER_EVENT_LISTEN( - GMLIB::Event::PlayerEvent::HandleRequestActionBeforeEvent, - ( - Player * player, - std::string const& actionType, - int count, - std::string const& sourceContainerNetId, - int sourceSlot, - std::string const& destinationContainerNetId, - int destinationSlot - ), - ( - (Player*)&ev.self(), - magic_enum::enum_name(requestAction.mActionType).data(), - (int)requestAction.mAmount, - magic_enum::enum_name(requestAction.mSrc.mOpenContainerNetId).data(), - (int)requestAction.mSrc.mSlot, - magic_enum::enum_name(requestAction.mDst.mOpenContainerNetId).data(), - (int)requestAction.mDst.mSlot - ), - ev.cancel(), - auto& requestAction = (ItemStackRequestActionTransferBase&)ev.getRequestAction(); - ) + GMLIB::Event::EntityEvent::SpawnWanderingTraderAfterEvent, + (std::pair pos), + ({event.getPos(), event.getRegion().getDimensionId()}), + ); + } + case doHash("gmlib::HandleRequestActionBeforeEvent"): { + // clang-format off + REGISTER_EVENT_LISTEN( + GMLIB::Event::PlayerEvent::HandleRequestActionBeforeEvent, + ( + Player * player, + std::string const& actionType, + int count, + std::string const& sourceContainerNetId, + int sourceSlot, + std::string const& destinationContainerNetId, + int destinationSlot, + bool isCancelled + ), + ( + (Player*)&event.self(), + magic_enum::enum_name(requestAction.mActionType).data(), + (int)requestAction.mAmount, + magic_enum::enum_name(requestAction.mSrc->mFullContainerName.mName).data(), + (int)requestAction.mSrc->mSlot, + magic_enum::enum_name(requestAction.mDst->mFullContainerName.mName).data(), + (int)requestAction.mDst->mSlot, + event.isCancelled() + ), + event.setCancelled(result);, + auto& requestAction = (ItemStackRequestActionTransferBase&)event.getRequestAction(); + ); // clang-format on } - case doHash("onSendContainerClosePacket"): { + case doHash("gmlib::HandleRequestActionAfterEvent"): { + // clang-format off + REGISTER_EVENT_LISTEN( + GMLIB::Event::PlayerEvent::HandleRequestActionAfterEvent, + ( + Player * player, + std::string const& actionType, + int count, + std::string const& sourceContainerNetId, + int sourceSlot, + std::string const& destinationContainerNetId, + int destinationSlot + ), + ( + (Player*)&event.self(), + magic_enum::enum_name(requestAction.mActionType).data(), + (int)requestAction.mAmount, + magic_enum::enum_name(requestAction.mSrc->mFullContainerName.mName).data(), + (int)requestAction.mSrc->mSlot, + magic_enum::enum_name(requestAction.mDst->mFullContainerName.mName).data(), + (int)requestAction.mDst->mSlot + ), + , + auto& requestAction = (ItemStackRequestActionTransferBase&)event.getRequestAction(); + ); + // clang-format on + } + case doHash("gmlib::ContainerClosePacketSendAfterEvent"): { REGISTER_EVENT_LISTEN( GMLIB::Event::PacketEvent::ContainerClosePacketSendAfterEvent, - (Player * player, int ContainerNetId), - (ev.getServerNetworkHandler() - .getServerPlayer(ev.getNetworkIdentifier(), ev.getPacket().mClientSubId), - (int)ev.getPacket().mContainerId), - logger.error("Event \"onSendContainerClosePacket\" cannot be intercepted"), - ) + (Player * player, int containerId, bool serverInitiatedClose, bool), + (event.getServerNetworkHandler() + ._getServerPlayer(event.getNetworkIdentifier(), event.getPacket().mClientSubId), + (int)event.getPacket().mContainerId, + event.getPacket().mServerInitiatedClose, + false), + , + ); } - case doHash("onServerStopping"): { - REGISTER_EVENT_LISTEN( - ll::event::server::ServerStoppingEvent, - (), - (), - logger.error("Event \"onServerStopping\" cannot be intercepted"), - ) - } - default: - return false; } + return -1; } ); } \ No newline at end of file diff --git a/src/Global.h b/src/Global.h index 775a31d..2d6e80c 100644 --- a/src/Global.h +++ b/src/Global.h @@ -7,12 +7,10 @@ #define LIB_VERSION_MAJOR 0 #define LIB_VERSION_MINOR 13 -#define LIB_VERSION_PATCH 4 +#define LIB_VERSION_PATCH 6 #define LIB_VERSION GMLIB::Version(LIB_VERSION_MAJOR, LIB_VERSION_MINOR, LIB_VERSION_PATCH) -extern ll::Logger logger; - extern void Export_Legacy_GMLib_ModAPI(); extern void Export_Legacy_GMLib_ServerAPI(); extern void Export_Compatibility_API(); diff --git a/src/LegacyModApi.cpp b/src/LegacyModApi.cpp index c22cbab..44a200f 100644 --- a/src/LegacyModApi.cpp +++ b/src/LegacyModApi.cpp @@ -149,7 +149,7 @@ void Export_Legacy_GMLib_ModAPI() { if (set.contains((AllExperiments)experiment_id)) { GMLIB_Level::addExperimentsRequire((AllExperiments)experiment_id); } else { - ll::Logger("Server").error("Experiment ID '{}' does not exist!", experiment_id); + ll::io::LoggerRegistry::getInstance().getOrCreate("Server")->error("Experiment ID '{}' does not exist!", experiment_id); } }); RemoteCall::exportAs("GMLib_ModAPI", "setExperimentEnabled", [](int experiment_id, bool value) -> void { @@ -158,7 +158,7 @@ void Export_Legacy_GMLib_ModAPI() { std::unordered_set set(list.begin(), list.end()); if (set.contains((AllExperiments)experiment_id)) { GMLIB_Level::getInstance()->setExperimentEnabled(((AllExperiments)experiment_id), value); - } else ll::Logger("Server").error("Experiment ID '{}' does not exist!", experiment_id); + } else ll::io::LoggerRegistry::getInstance().getOrCreate("Server")->error("Experiment ID '{}' does not exist!", experiment_id); } }); RemoteCall::exportAs("GMLib_ModAPI", "getExperimentEnabled", [](int experiment_id) -> bool { @@ -168,7 +168,7 @@ void Export_Legacy_GMLib_ModAPI() { if (set.contains((AllExperiments)experiment_id)) { return GMLIB_Level::getInstance()->getExperimentEnabled(((AllExperiments)experiment_id)); } - ll::Logger("Server").error("Experiment ID '{}' does not exist!", experiment_id); + ll::io::LoggerRegistry::getInstance().getOrCreate("Server")->error("Experiment ID '{}' does not exist!", experiment_id); } return false; }); diff --git a/src/MemoryOperators.cpp b/src/MemoryOperators.cpp index f7c918a..7d40c07 100644 --- a/src/MemoryOperators.cpp +++ b/src/MemoryOperators.cpp @@ -4,4 +4,4 @@ #define LL_MEMORY_OPERATORS -#include +#include \ No newline at end of file diff --git a/tooth.json b/tooth.json index 6c86a5b..9af9198 100644 --- a/tooth.json +++ b/tooth.json @@ -1,7 +1,7 @@ { "format_version": 2, "tooth": "github.com/GroupMountain/GMLIB-LegacyRemoteCallApi", - "version": "0.13.4", + "version": "0.13.6", "info": { "name": "GMLIB-LegacyRemoteCallApi", "description": "Legacy RemoteCall API for GMLIB", @@ -14,9 +14,9 @@ "library" ] }, - "asset_url": "https://github.com/GroupMountain/GMLIB-LegacyRemoteCallApi/releases/download/v0.13.4/GMLIB-LegacyRemoteCallApi-windows-x64.zip", + "asset_url": "https://github.com/GroupMountain/GMLIB-LegacyRemoteCallApi/releases/download/v0.13.6/GMLIB-LegacyRemoteCallApi-windows-x64.zip", "dependencies": { - "github.com/GroupMountain/GMLIB": ">=0.13.0" + "github.com/GroupMountain/GMLIB": ">=0.13.9" }, "files": { "place": [ diff --git a/xmake.lua b/xmake.lua index 5a928d5..e567784 100644 --- a/xmake.lua +++ b/xmake.lua @@ -7,43 +7,12 @@ if not has_config("vs_runtime") then set_runtimes("MD") end --- Option 1: Use the latest version of LeviLamina released on GitHub. -add_requires("levilaminalibrary") +add_requires("levilamina", {configs = {target_type = "server"}}) add_requires("legacyremotecall") -add_requires("gmlib 0.13.7") +add_requires("gmlib") +add_requires("levibuildscript") --- Option 2: Use a specific version of LeviLamina released on GitHub. --- add_requires("levilamina x.x.x") - --- Option 3: Use the latest commit of LeviLamina on GitHub. --- -- Here, "develop" is the branch name. You can change it to any branch name you want. --- add_requires("levilamina develop") --- -- You can also use debug build of LeviLamina. --- -- add_requires("levilamina develop", {debug = true}) --- package("levilamina") --- add_urls("https://github.com/LiteLDev/LeviLamina.git") - --- add_deps("ctre 3.8.1") --- add_deps("entt 3.12.2") --- add_deps("fmt 10.1.1") --- add_deps("gsl 4.0.0") --- add_deps("leveldb 1.23") --- add_deps("magic_enum 0.9.0") --- add_deps("nlohmann_json 3.11.2") --- add_deps("rapidjson 1.1.0") --- add_deps("pcg_cpp 1.0.0") --- add_deps("pfr 2.1.1") --- add_deps("preloader 1.4.0") --- add_deps("symbolprovider 1.1.0") - --- -- You may need to change this to the target BDS version of your choice. --- add_deps("bdslibrary 1.20.50.03") - --- on_install(function (package) --- import("package.tools.xmake").install(package) --- end) - -target("GMLIB-LegacyRemoteCallApi") -- Change this to your plugin name. +target("GMLIB-LegacyRemoteCallApi") add_cxflags( "/EHa", "/utf-8" @@ -59,14 +28,12 @@ target("GMLIB-LegacyRemoteCallApi") -- Change this to your plugin name. "src" ) add_packages( - "levilaminalibrary", + "levilamina", "legacyremotecall", "gmlib" ) - add_shflags( - "/DELAYLOAD:bedrock_server.dll" -- Magic to import symbols from BDS - ) - set_exceptions("none") -- To avoid conflicts with /EHa + add_rules("@levibuildscript/linkrule") + set_exceptions("none") set_kind("shared") set_languages("c++23") set_symbols("debug")