From 8fe38b9a65f103647a20177413c9763fb9e42e4c Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 6 Sep 2024 10:21:45 +0300 Subject: [PATCH] fix(regression,critical): chunks were stopped loading after moving to another chunk fix: fix command blocks parsing for most versions fix: chat was not working for 1.19+ fix: better range adjustment for plate command block activation fix: was not possible to change the warp --- src/lib/modules/chat.ts | 4 ++++ src/lib/modules/commandBlocks.ts | 33 ++++++++++++++++++++++++++++++++ src/lib/modules/placeBlock.ts | 13 ++++--------- src/lib/modules/redstone.ts | 5 +++-- src/lib/modules/warps.ts | 5 +++-- src/lib/modules/world.ts | 26 +++++++------------------ 6 files changed, 54 insertions(+), 32 deletions(-) create mode 100644 src/lib/modules/commandBlocks.ts diff --git a/src/lib/modules/chat.ts b/src/lib/modules/chat.ts index f2d11116..943dece5 100644 --- a/src/lib/modules/chat.ts +++ b/src/lib/modules/chat.ts @@ -160,6 +160,8 @@ export const player = function (player: Player, serv: Server) { player.chat = message => { if (typeof message === 'string') message = serv.parseClassic(message) player._client.write('chat', { message: JSON.stringify(message), position: 0, sender: '0' }) + // 1.19+ + player._client.write('systemChat', { formattedMessage: JSON.stringify(message), position: 0, sender: '0' }) } player.emptyChat = (count = 1) => { @@ -171,6 +173,8 @@ export const player = function (player: Player, serv: Server) { player.system = message => { if (typeof message === 'string') message = serv.parseClassic(message) player._client.write('chat', { message: JSON.stringify(message), position: 2, sender: '0' }) + // 1.19+ + player._client.write('systemChat', { formattedMessage: JSON.stringify(message), position: 2, sender: '0' }) } } declare global { diff --git a/src/lib/modules/commandBlocks.ts b/src/lib/modules/commandBlocks.ts new file mode 100644 index 00000000..0722288c --- /dev/null +++ b/src/lib/modules/commandBlocks.ts @@ -0,0 +1,33 @@ +import { Block } from 'prismarine-block' + + +export const server = function (serv: Server) { + serv.getCommandBlockData = (commandBlock: Block) => { + const pos = commandBlock.position + const key = `${pos.x},${pos.y},${pos.z}` + let entity = serv.overworld.blockEntityData[key] + entity = entity?.value ?? entity + if (!entity) return + return Object.keys(entity).reduce((acc, key) => { + acc[key] = entity[key].value + return acc + }, {} as any) + } +} + +declare global { + interface Server { + getCommandBlockData: (commandBlock: Block) => { + Command: string + LastOutput: string + TrackOutput: Number + SuccessCount: number + CustomName: string + powered: boolean + conditionMet: boolean + UpdateLastExecution?: boolean + LastExecution?: number + // color: string + } | undefined + } +} diff --git a/src/lib/modules/placeBlock.ts b/src/lib/modules/placeBlock.ts index 0a1ddde7..bb6e36eb 100644 --- a/src/lib/modules/placeBlock.ts +++ b/src/lib/modules/placeBlock.ts @@ -132,14 +132,9 @@ export const server = (serv: Server, { version }: Options) => { const commandBlocks = blocks.filter(b => b.name.endsWith('command_block')).map((b) => b.name) for (const block of commandBlocks) { serv.onBlockInteraction(block, ({ block, player }) => { - const pos = block.position - const key = `${pos.x},${pos.y},${pos.z}` - const entity = serv.overworld.blockEntityData[key] - // todo use block.entity - if (entity) { - // todo simplify - const command = entity.value.Command.value - player.chat(command) + const { Command } = serv.getCommandBlockData(block) ?? {} + if (Command) { + player.chat(Command) } else { player.chat('No entity data') } @@ -236,6 +231,6 @@ declare global { * * The argument given to the handler is an object containing the clicked block and the player. It should return true if the block interaction occurred and the block placement should be cancelled. */ - 'onBlockInteraction': (name: string, handler: (data: {block: Block, player: Player}) => void) => void + 'onBlockInteraction': (name: string, handler: (data: { block: Block, player: Player }) => void) => void } } diff --git a/src/lib/modules/redstone.ts b/src/lib/modules/redstone.ts index f8c0d8b1..3dbd29a2 100644 --- a/src/lib/modules/redstone.ts +++ b/src/lib/modules/redstone.ts @@ -321,9 +321,9 @@ export const server = function (serv: Server, { version }: Options) { const entity = serv.overworld.blockEntityData[key] if (!entity) return - const command = entity.value.Command.value + const command = serv.getCommandBlockData(block)?.Command if (!command) return - await serv.handleCommand(command, { + await serv.handleCommand(command.replace(/^\//, ''), { //@ts-ignore player: { world: world, @@ -379,6 +379,7 @@ export const server = function (serv: Server, { version }: Options) { serv.onBlockInteraction(pushable, async ({ block, player }) => { const nearby = isPlate ? [ // below + block.position.offset(0, -2, 0), block.position.offset(0, -1, 0), block.position.offset(1, -1, 0), block.position.offset(-1, -1, 0), diff --git a/src/lib/modules/warps.ts b/src/lib/modules/warps.ts index e02ae5a3..f2f6141b 100644 --- a/src/lib/modules/warps.ts +++ b/src/lib/modules/warps.ts @@ -58,9 +58,10 @@ export const server = async function (serv: Server, options: Options) { } serv.setWarp = async (warp: WorldWarp) => { - if (!serv.warps.find(w => w.name === warp.name)) { - serv.warps.push(warp) + if (serv.warps.find(w => w.name === warp.name)) { + serv.warps = serv.warps.filter(w => w.name !== warp.name) } + serv.warps.push(warp) // write to fs, ensure dir if (!await existsViaStats(warpsFolder)) { diff --git a/src/lib/modules/world.ts b/src/lib/modules/world.ts index 242b699b..66ce8317 100644 --- a/src/lib/modules/world.ts +++ b/src/lib/modules/world.ts @@ -139,27 +139,15 @@ export const server: ServerModule = async function (serv, options) { .forEach(player => player.sendBlockAction(position, actionId, actionParam, blockType)) } - serv.reloadChunks = (world, chunks) => { - serv.players - .filter(player => player.world === world) - .forEach(oPlayer => { - chunks - .filter(({ chunkX, chunkZ }) => oPlayer.loadedChunks[chunkX + ',' + chunkZ] !== undefined) - .forEach(({ chunkX, chunkZ }) => oPlayer._unloadChunk(chunkX, chunkZ)) - oPlayer.sendRestMap() - }) - } - serv.chunksUsed = {} - serv._loadPlayerChunk = (chunkX, chunkZ, player) => { + serv._finishPlayerChunkLoading = (chunkX, chunkZ, player) => { const id = chunkX + ',' + chunkZ + if (player.loadedChunks[id]) return if (!serv.chunksUsed[id]) { serv.chunksUsed[id] = 0 } serv.chunksUsed[id]++ - const loaded = player.loadedChunks[id] - if (!loaded) player.loadedChunks[id] = 1 - return !loaded + player.loadedChunks[id] = 1 } serv._unloadPlayerChunk = (chunkX, chunkZ, player) => { const id = chunkX + ',' + chunkZ @@ -341,6 +329,8 @@ export const player = function (player: Player, serv: Server, settings: Options) z: chunkZ, chunk: column }, ({ x, z, chunk }/* : {x, z, chunk: import('prismarine-chunk').PCChunk} */) => { + serv._finishPlayerChunkLoading(chunkX, chunkZ, player) + const newLightsFormat = serv.supportFeature('newLightingDataFormat') const dumpedLights = chunk.dumpLight() const newLightsData = newLightsFormat ? { skyLight: dumpedLights.skyLight, blockLight: dumpedLights.blockLight } : undefined @@ -442,7 +432,7 @@ export const player = function (player: Player, serv: Server, settings: Options) chunkX: playerChunkX + t[0], chunkZ: playerChunkZ + t[1] })) - .filter(({ chunkX, chunkZ }) => serv._loadPlayerChunk(chunkX, chunkZ, player)) + .filter(({ chunkX, chunkZ }) => !player.loadedChunks[`${chunkX},${chunkZ}`]) .reduce((acc, { chunkX, chunkZ }) => { const p = acc .then(() => { @@ -566,11 +556,9 @@ declare global { /** Sends a block action to all players of the same world. */ "setBlockAction": (world: CustomWorld, position: Vec3, actionId: number, actionParam: any) => Promise /** @internal */ - "reloadChunks": (world: CustomWorld, chunks: any) => void - /** @internal */ "chunksUsed": {} /** @internal */ - "_loadPlayerChunk": (chunkX: number, chunkZ: number, player: Player) => boolean + "_finishPlayerChunkLoading": (chunkX: number, chunkZ: number, player: Player) => void /** @internal */ "_unloadPlayerChunk": (chunkX: number, chunkZ: number, player: Player) => boolean /** @internal */