Add experimental username scheme & organize playerdata by first uuid octet
This commit is contained in:
parent
d2166651be
commit
9d41812df0
6 changed files with 65 additions and 28 deletions
59
bot.js
59
bot.js
|
@ -1,7 +1,10 @@
|
|||
const mc = require('minecraft-protocol')
|
||||
const nbt = require('prismarine-nbt')
|
||||
const { EventEmitter } = require('events')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const fileExists = require('./util/file_exists')
|
||||
const crypto = require('crypto')
|
||||
|
||||
const plugins = []
|
||||
for (const filename of fs.readdirSync(path.resolve(__dirname, 'plugins'))) {
|
||||
|
@ -9,6 +12,32 @@ for (const filename of fs.readdirSync(path.resolve(__dirname, 'plugins'))) {
|
|||
plugins.push(require(path.resolve(__dirname, 'plugins', filename)))
|
||||
}
|
||||
|
||||
const usernameSchemes = {
|
||||
async random_playerdata (bot, options) {
|
||||
const playerDataDir = await path.join(bot.paths.persistent, 'playerdata')
|
||||
if (!await fileExists(playerDataDir)) return undefined
|
||||
|
||||
let subdir
|
||||
try {
|
||||
const subdirs = (await fs.promises.readdir(playerDataDir)).filter(filename => !filename.endsWith('_old'))
|
||||
subdir = path.join(playerDataDir, subdirs[crypto.randomInt(0, subdirs.length)])
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
|
||||
let data
|
||||
try {
|
||||
const files = await fs.promises.readdir(subdir)
|
||||
const raw = await fs.promises.readFile(path.join(subdir, files[crypto.randomInt(0, files.length)]))
|
||||
data = await nbt.parse(raw)
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return data?.parsed?.value?.username?.value
|
||||
}
|
||||
}
|
||||
|
||||
function createBot (options = {}) {
|
||||
// defaults
|
||||
options.username ??= 'Bot'
|
||||
|
@ -27,6 +56,7 @@ function createBot (options = {}) {
|
|||
options['online-mode'].username ??= null
|
||||
options['online-mode'].password ??= null
|
||||
|
||||
options.paths ??= {}
|
||||
options.paths.logs ??= 'logs'
|
||||
options.paths.music ??= 'music'
|
||||
options.paths.images ??= 'images'
|
||||
|
@ -68,13 +98,10 @@ function createBot (options = {}) {
|
|||
bot.loggedIn = false
|
||||
bot.emit('end', reason)
|
||||
// auto reconnect
|
||||
if (bot.autoReconnect) {
|
||||
if (bot.autoReconnect && !options.client) {
|
||||
setTimeout(() => {
|
||||
if (bot.randomizeUsername && !bot['online-mode'].enabled) { options.username = options.username.slice(0, -2) + '\u00a7' + String.fromCharCode(Math.floor(Math.random() * 65535)) }
|
||||
|
||||
bot._client = mc.createClient(options)
|
||||
bot.emit('set_client', bot._client)
|
||||
}, 6000)
|
||||
bot._initClient()
|
||||
}, 6000)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -92,11 +119,25 @@ function createBot (options = {}) {
|
|||
bot.emit('packet.' + meta.name, data);
|
||||
})
|
||||
})
|
||||
bot._client = options.client ?? mc.createClient(options)
|
||||
|
||||
for (const plugin of plugins) plugin(bot, options) // Load plugins before emitting set_client so that plugins can listen for the event
|
||||
async function _initClient () {
|
||||
const usernameScheme = typeof options.usernameScheme === 'function' ? options.usernameScheme : usernameSchemes[options.usernameScheme]
|
||||
const username = await usernameScheme?.(bot, options)
|
||||
if (username) options.username = username
|
||||
|
||||
bot.emit('set_client', bot._client)
|
||||
bot._client = mc.createClient(options)
|
||||
bot.emit('set_client', bot._client)
|
||||
}
|
||||
bot._initClient = _initClient
|
||||
|
||||
for (const plugin of plugins) plugin(bot, options)
|
||||
|
||||
if (options.client) {
|
||||
bot._client = options.client
|
||||
bot.emit('set_client', bot._client)
|
||||
} else {
|
||||
bot._initClient()
|
||||
}
|
||||
|
||||
function loadPlugin (plugin) {
|
||||
try {
|
||||
|
|
4
index.js
4
index.js
|
@ -14,12 +14,12 @@ async function main () {
|
|||
const configPath = process.argv[2] ?? 'config.json5'
|
||||
if (!await fileExists(configPath)) {
|
||||
await fs.copyFile(path.join(__dirname, 'default.json5'), configPath)
|
||||
console.info('No config file was found, so a default one was created')
|
||||
globalThis.console.info('No config file was found, so a default one was created')
|
||||
}
|
||||
const config = json5.parse(await fs.readFile(configPath, 'utf-8'))
|
||||
|
||||
// logging
|
||||
const logdir = config.paths.logs ?? 'logs'
|
||||
const logdir = config.paths?.logs ?? 'logs'
|
||||
if (!await fileExists(logdir)) await fs.mkdir(logdir)
|
||||
|
||||
const rl = readline.createInterface({
|
||||
|
|
14
package-lock.json
generated
14
package-lock.json
generated
|
@ -4,6 +4,7 @@
|
|||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "chipmunkbot3",
|
||||
"dependencies": {
|
||||
"@mozilla/readability": "^0.4.1",
|
||||
"@skeldjs/client": "^2.15.17",
|
||||
|
@ -2413,9 +2414,10 @@
|
|||
"integrity": "sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA=="
|
||||
},
|
||||
"node_modules/matrix-js-sdk": {
|
||||
"version": "31.5.0",
|
||||
"resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-31.5.0.tgz",
|
||||
"integrity": "sha512-d8Y/Vt6PdX8leSOQ06yoArJ1xMwCzxSb1H2GzW9mtOgXnHpeYvrAuPrYr32k5hfdUAJp0xPibSqDP+/+2kCnpg==",
|
||||
"version": "31.6.1",
|
||||
"resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-31.6.1.tgz",
|
||||
"integrity": "sha512-XDSafXV2mrOQvkyZ8i1eDwqmicjLVTkdA2iAw1QsfAZtERz4CAlp1QJULcN1X2WhBx7pMnsN8M/k98LruUqMMQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@matrix-org/matrix-sdk-crypto-wasm": "^4.6.0",
|
||||
|
@ -5694,9 +5696,9 @@
|
|||
"integrity": "sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA=="
|
||||
},
|
||||
"matrix-js-sdk": {
|
||||
"version": "31.5.0",
|
||||
"resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-31.5.0.tgz",
|
||||
"integrity": "sha512-d8Y/Vt6PdX8leSOQ06yoArJ1xMwCzxSb1H2GzW9mtOgXnHpeYvrAuPrYr32k5hfdUAJp0xPibSqDP+/+2kCnpg==",
|
||||
"version": "31.6.1",
|
||||
"resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-31.6.1.tgz",
|
||||
"integrity": "sha512-XDSafXV2mrOQvkyZ8i1eDwqmicjLVTkdA2iAw1QsfAZtERz4CAlp1QJULcN1X2WhBx7pMnsN8M/k98LruUqMMQ==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@matrix-org/matrix-sdk-crypto-wasm": "^4.6.0",
|
||||
|
|
|
@ -3,7 +3,7 @@ function inject (bot) {
|
|||
bot.kbwl.enabled = false
|
||||
bot.kbwl.players = ['_ChipMC_']
|
||||
|
||||
bot._client.on('player_info', (packet) => {
|
||||
bot.on('packet.player_info', (packet) => {
|
||||
if (bot.kbwl.enabled && packet.action === 0) {
|
||||
packet.data.forEach((player) => {
|
||||
if (player.UUID !== bot.uuid && !bot.kbwl.players.includes(player.name)) { bot.exploits.titleKick(`@a[name="${player.name.replace(/"/, '\\"')}"]`) }
|
||||
|
|
|
@ -11,18 +11,9 @@ async function inject (bot) {
|
|||
const persistentDir = bot.paths.persistent
|
||||
const playerDataDir = path.join(persistentDir, 'playerdata')
|
||||
|
||||
if (!await fileExists(playerDataDir)) await fs.mkdir(playerDataDir)
|
||||
|
||||
bot.playerData = playerData
|
||||
bot.loadPlayerData = loadPlayerData
|
||||
|
||||
if (bot.loggedIn && bot.players) {
|
||||
for (const player of bot.players) {
|
||||
// If we logged in while the async file operations were happening (highly unlikely but possible), load the player data for the players on the server
|
||||
handlePlayerAdded(player)
|
||||
}
|
||||
}
|
||||
|
||||
bot.on('player_added', handlePlayerAdded)
|
||||
|
||||
async function handlePlayerAdded (player) {
|
||||
|
@ -49,7 +40,7 @@ async function inject (bot) {
|
|||
uuid = getOfflineUUID(uuid)
|
||||
}
|
||||
|
||||
const data = new PlayerData(path.join(playerDataDir, uuid + '.dat'))
|
||||
const data = new PlayerData(path.join(playerDataDir, uuid.substring(0, 2) + '/' + uuid.substring(2) + '.dat'))
|
||||
await data.load()
|
||||
return data
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const fs = require('fs/promises')
|
||||
const path = require('path')
|
||||
const { createWriteStream } = require('fs')
|
||||
const zlib = require('zlib')
|
||||
const stream = require('stream/promises')
|
||||
|
@ -38,6 +39,8 @@ class PersistentData {
|
|||
}
|
||||
|
||||
async save () {
|
||||
await fs.mkdir(path.dirname(this.filepath), { recursive: true })
|
||||
|
||||
const data = this.unparse(this.data)
|
||||
if (await fileExists(this.filepath)) await fs.copyFile(this.filepath, this.filepath + '_old') // Back up our data before a save
|
||||
|
||||
|
|
Loading…
Reference in a new issue