From 69e2a72751b9458324b92345e8eff55fb7d468bf Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 21 Nov 2024 20:39:32 +0300 Subject: [PATCH] fix: fix gamerules handling! fix: improve output commands formatting, especially errored ones --- src/lib/command.ts | 20 +++++++++++++++----- src/lib/modules/commands.ts | 11 +++++++---- src/lib/modules/daycycle.ts | 2 +- src/lib/modules/gamerules.ts | 31 +++++++++++++++++++++++++------ src/lib/modules/world.ts | 2 +- 5 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/lib/command.ts b/src/lib/command.ts index fab49e26..41d96b60 100644 --- a/src/lib/command.ts +++ b/src/lib/command.ts @@ -48,7 +48,7 @@ class Command { return undefined } - async use (command, ctx: Ctx = {}, op = true) { + async use (command: string, ctx: Ctx, op = true) { const resultsFound = this.find(command) let parsedResponse if (resultsFound) { @@ -69,10 +69,20 @@ class Command { parsedResponse = passedArgs.match(customArgsParser) } } - let output - if (parsedResponse) output = await wantedCommand.params.action(parsedResponse, ctx) - else output = await wantedCommand.params.action(resultsFound[1], ctx) // just give back the passed arg - if (output) return '' + output + try { + let output + if (parsedResponse) output = await wantedCommand.params.action(parsedResponse, ctx) + else output = await wantedCommand.params.action(resultsFound[1], ctx) // just give back the passed arg + if (output) return { + success: output + } + } catch (err) { + console.error(`Error in command from ${ctx.player?.username || 'server'} "${command}":`) + console.error(err) + return { + error: `Internal server error: ${err.message}` + } + } } else { if (ctx.player) return 'Command not found' else throw new UserError('Command not found') diff --git a/src/lib/modules/commands.ts b/src/lib/modules/commands.ts index 1c64e992..36968e7c 100644 --- a/src/lib/modules/commands.ts +++ b/src/lib/modules/commands.ts @@ -7,7 +7,9 @@ export const player = function (player: Player, serv: Server, { version }: Optio player.handleCommand = async (str) => { try { const res = await serv.commands.use(str, { player }, player.op) - if (res) player.chat(serv.color.green + res) + const success = typeof res === 'string' ? res : (res && 'success' in res ? res.success : '') + if (success) player.chat(serv.color.green + success) + else if (res && typeof res === 'object' && 'error' in res) player.chat(serv.color.red + res.error) } catch (err) { if (err.userError) player.chat(serv.color.red + 'Error: ' + err.message) else setTimeout(() => { throw err }, 0) @@ -23,9 +25,10 @@ export const entity = function (entity: Entity, serv: Server) { export const server = function (serv: Server, { version }: Options) { serv.handleCommand = async (str, ctx, op) => { try { - const res = await serv.commands.use(str, ctx, op) - if (res) serv.info(res) - return res + const res = await serv.commands.use(str, ctx ?? {}, op) + const success = typeof res === 'string' ? res : (res && 'success' in res ? res.success : '') + if (success) serv.info(success) + return typeof res === 'string' ? res : (res && 'success' in res ? res.success : res?.error) } catch (err) { if (err.userError) serv.err(err.message) else setTimeout(() => { throw err }, 0) diff --git a/src/lib/modules/daycycle.ts b/src/lib/modules/daycycle.ts index d54e4cd8..cddabcb9 100644 --- a/src/lib/modules/daycycle.ts +++ b/src/lib/modules/daycycle.ts @@ -14,7 +14,7 @@ export const server = function (serv: Server) { serv.on('tick', (delta, count) => { // TODO // const disabledByGamerule = 'doDayLightCycle doDayLightcycle DayNightCycle' - const disabledByGamerule = 'doDayLightCycle'.split(' ').some(x => serv.levelData?.GameRules[x] === 'false') || !serv.gamerules.doDayLightCycle + const disabledByGamerule = !serv.gamerules.doDaylightCycle if (!serv.doDaylightCycle || disabledByGamerule) return if (count % 20 === 0) { serv.behavior('changeTime', { diff --git a/src/lib/modules/gamerules.ts b/src/lib/modules/gamerules.ts index 3db457c0..2c826810 100644 --- a/src/lib/modules/gamerules.ts +++ b/src/lib/modules/gamerules.ts @@ -1,13 +1,31 @@ export const server = function (serv: Server, options: Options) { serv.gamerules ??= {} - serv.on('asap', () => { + serv.on('pluginsReady', () => { for (const [key, val] of Object.entries(serv.levelData?.GameRules ?? {})) { serv.gamerules[key] = val === 'true' } }) - const gameRules = { - 'doDayLightCycle': 'Wether to enable daylight cycle' + const knownGameRules = [ + "doTileDrops", + "doFireTick", + "reducedDebugInfo", + "naturalRegeneration", + "doMobLoot", + "keepInventory", + "doEntityDrops", + "mobGriefing", + "randomTickSpeed", + "commandBlockOutput", + "doMobSpawning", + "logAdminCommands", + "sendCommandFeedback", + "doDaylightCycle", + "showDeathMessages", + ] + + const gameRules: Partial = { + 'doDaylightCycle': 'Wether to enable daylight cycle' } serv.commands.add({ @@ -23,9 +41,10 @@ export const server = function (serv: Server, options: Options) { if (!rule) { return `Available these gamerules: ${Object.entries(gameRules).map(([key, desc]) => `${key}: ${desc}`).join(', ')}` } + if (!knownGameRules.includes(rule)) ctx.player?.chat(serv.color.yellow + `Warning: gamerule ${rule} is not known`) if (newVal) { - serv.gameMode[rule] = newVal === 'false' ? false : true - return `set ${rule} to ${serv.gamerules[rule]}` + serv.gamerules[rule] = newVal === 'false' ? false : true + return `Set ${rule} to ${serv.gamerules[rule]}` } else { const gamerule = serv.gamerules[rule] return `${rule} is ${gamerule ? 'Enabled' : 'Disabled'} (${gamerule})` @@ -36,6 +55,6 @@ export const server = function (serv: Server, options: Options) { declare global { interface Server { - gamerules: Record + gamerules: Partial['GameRules']>> } } diff --git a/src/lib/modules/world.ts b/src/lib/modules/world.ts index 49585cf5..558956be 100644 --- a/src/lib/modules/world.ts +++ b/src/lib/modules/world.ts @@ -536,7 +536,7 @@ declare global { /** Global spawn and respawn point for every player */ spawnPoint?: Vec3 /** Parsed level.dat of the loaded world (only if worldFolder is specificed) */ - levelData?: LevelDatFull & { GameRules?} + levelData?: Partial worlds: Record /** Contains the overworld world. This is where the default spawn point is */ "overworld": CustomWorld