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 */