diff --git a/bot.js b/bot.js index 7fba480..e033562 100644 --- a/bot.js +++ b/bot.js @@ -101,7 +101,7 @@ function createBot (options = {}) { if (bot.autoReconnect && !options.client) { setTimeout(() => { bot._initClient() - }, 6000) + }, 6000) } }) diff --git a/commands/seen.js b/commands/seen.js index ce878ce..ad7a6ff 100644 --- a/commands/seen.js +++ b/commands/seen.js @@ -41,9 +41,21 @@ module.exports = { { text: '', ...bot.styles.primary }, { text: username, ...bot.styles.secondary }, ' was first seen on ', - { text: first, ...bot.styles.secondary }, + { text: first.date + '', ...bot.styles.secondary }, + ' at ', + { ...this.formatServer(first), ...bot.styles.secondary }, ' and last seen on ', - { text: last, ...bot.styles.secondary } + { text: last.date + '', ...bot.styles.secondary }, + ' at ', + { ...this.formatServer(last), ...bot.styles.secondary } ], false) + }, + + formatServer (value) { + if (!value.host) return { text: 'unknown server', italic: true } + + let text = value.host + if (value.port && value.port !== 25565) text += ':' + value.port + return { text } } } diff --git a/plugins/player_data.js b/plugins/player_data.js index bea5da4..42e2b7a 100644 --- a/plugins/player_data.js +++ b/plugins/player_data.js @@ -54,7 +54,16 @@ async function inject (bot) { bot.emit('player_data_unloading', player, data) - await data.unload(true) + try { + await data.unload(true) + } catch (error) { + console.error('Failed to unload data for player %s (%s):', data?.data?.username, data?.filename, error) + try { + console.error('Contents:', JSON.stringify(data)) + } catch { + console.log('Unable to print contents') + } + } delete bot.playerData[player.uuid] }) } @@ -64,7 +73,7 @@ async function saveAll () { for (const uuid in playerData) { const data = playerData[uuid] if (!data?.data) { - // We _somehow_ found some unloaded data + // We *somehow* found some unloaded data delete playerData[uuid] continue } @@ -72,7 +81,7 @@ async function saveAll () { try { await data.save() } catch (error) { - console.error('Unable to write data for player %s:', data?.data?.username, error) + console.error('Unable to write data for player %s (%s):', data?.data?.username, data?.filepath, error) } } console.log('Saved!') diff --git a/plugins/seen.js b/plugins/seen.js index 60c0ca8..b9f2d08 100644 --- a/plugins/seen.js +++ b/plugins/seen.js @@ -4,20 +4,24 @@ function inject (bot) { const seenData = data.data.seen if (seenData.first == null) { - seenData.first = new Date() + seenData.first = createSeenValue() bot.tellraw([ { text: 'Welcome ', ...bot.styles.primary }, { text: player.username, ...bot.styles.secondary }, ' to the server!' ], '@a') } - seenData.last = new Date() + seenData.last = createSeenValue() }) bot.on('player_data_unloading', (player, data) => { const seenData = data.data.seen - if (seenData != null) seenData.last = new Date() + if (seenData != null) seenData.last = createSeenValue() }) + + function createSeenValue () { + return { date: new Date(), host: bot.host, port: bot.port ?? 25565 } + } } module.exports = inject diff --git a/plugins/self_care.js b/plugins/self_care.js index ae282fc..570bd93 100644 --- a/plugins/self_care.js +++ b/plugins/self_care.js @@ -8,7 +8,7 @@ const COMMANDSPY_DISABLED_MESSAGE_2 = { extra: [ 'Successfully ', 'disabled', ' function inject (bot) { let permissionLevel, gamemode, commandSpyEnabled, vanished, godEnabled - bot.on('packet.login', packet => {console.log(packet) + bot.on('packet.login', packet => { permissionLevel = 0 gamemode = packet.gameMode commandSpyEnabled = false diff --git a/util/player_data.js b/util/player_data.js index 4a24734..edc251a 100644 --- a/util/player_data.js +++ b/util/player_data.js @@ -12,8 +12,8 @@ class PlayerData extends PersistentData { if (data.seen?.value) { parsed.seen = {} - if (data.seen.value.first?.value) parsed.seen.first = new Date(Number(data.seen.value.first?.value)) - if (data.seen.value.last?.value) parsed.seen.last = new Date(Number(data.seen.value.last?.value)) + if (data.seen.value.first?.value) parsed.seen.first = this.#parseSeenValue(data.seen.value.first) + if (data.seen.value.last?.value) parsed.seen.last = this.#parseSeenValue(data.seen.value.last) } if (data.mail?.value?.value && Array.isArray(data.mail.value.value)) { @@ -26,26 +26,39 @@ class PlayerData extends PersistentData { } #parseMail (mail) { - const signedPort = Number(mail?.port?.value ?? 25565) - const uint16Array = new Uint16Array(1) - uint16Array[0] = signedPort - const unsignedPort = uint16Array[0] - return { sender: String(mail?.sender?.value), message: String(mail?.message?.value), host: String(mail?.host?.value), - port: unsignedPort + port: this.#int16ToUint16(Number(mail?.port?.value ?? 25565)) } } + #parseSeenValue (value) { + if (typeof value.value === 'number' || typeof value.value === 'bigint' || value.type === 'long' /* BigIntExtended moment */) { + return { date: new Date(Number(value.value)) } + } + + const result = {} + if (value.value?.date?.value) result.date = new Date(Number(value?.value?.date?.value)) + if (value.value?.host?.value) result.host = String(value?.value?.host?.value) + if (value.value?.port?.value) result.port = this.#int16ToUint16(Number(value?.value?.port?.value ?? 25565)) + return result + } + + #int16ToUint16 (value) { + const uint16Array = new Uint16Array(1) + uint16Array[0] = value + return uint16Array[0] + } + unparse (parsed) { const data = {} if (parsed.username) data.username = nbt.string(parsed.username) if (parsed.seen) { - data.seen = nbt.comp({ first: nbt.long(BigInt(parsed.seen.first.getTime())), last: nbt.long(BigInt(parsed.seen.last.getTime())) }) + data.seen = nbt.comp({ first: this.#unparseSeenValue(parsed.seen.first), last: this.#unparseSeenValue(parsed.seen.last) }) } if (parsed.mail) { @@ -58,19 +71,30 @@ class PlayerData extends PersistentData { } #unparseMail (mail) { - const unsignedPort = mail.port ?? 25565 - const int16Array = new Int16Array(1) - int16Array[0] = unsignedPort - const signedPort = int16Array[0] - const result = { sender: nbt.string(mail.sender), message: nbt.string(mail.message), host: nbt.string(mail.host) } - if (unsignedPort !== 25565) result.port = nbt.short(signedPort) + if (mail.port !== 25565) result.port = nbt.short(this.#uint16ToInt16(mail.port)) return result } + + #unparseSeenValue (value) { + if (value.host == null && value.port == null) return nbt.long(BigInt(value.date.getTime())) + + return nbt.comp({ + date: nbt.long(BigInt(value.date.getTime())), + host: nbt.string(value.host), + port: nbt.short(this.#uint16ToInt16(value.port)) + }) + } + + #uint16ToInt16 (value) { + const int16Array = new Int16Array(1) + int16Array[0] = value + return int16Array[0] + } } module.exports = PlayerData