diff --git a/.gitignore b/.gitignore index 897cb9f..0feb046 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules package-lock.json -dist \ No newline at end of file +dist +worlds/** +nmp-cache/** diff --git a/example/simpleProxy.js b/example/simpleProxy.js index 4b88a7b..f300f78 100644 --- a/example/simpleProxy.js +++ b/example/simpleProxy.js @@ -1,42 +1,70 @@ const { InspectorProxy } = require('../') -const readline = require('readline') -const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout -}) +// const readline = require('readline') +// const rl = readline.createInterface({ +// input: process.stdin, +// output: process.stdout +// }) -rl.on('line', (line) => { - line = line.trim().toLowerCase() - if (line === 'stopserver') { - proxy.stopServer() - } else if (line === 'startserver') { - proxy.startServer() - } else if (line === 'stopbot') { - proxy.stopBot() - } else if (line === 'startbot') { - proxy.startBot() - } -}) +// rl.on('line', (line) => { +// line = line.trim().toLowerCase() +// if (line === 'stopserver') { +// proxy.stopServer() +// } else if (line === 'startserver') { +// proxy.startServer() +// } else if (line === 'stopbot') { +// proxy.stopBot() +// } else if (line === 'startbot') { +// proxy.startBot() +// } +// }) + +let highestId = -Infinity + +/** @type { import('@rob9315/mcproxy').PacketMiddleware } */ +const mapShowMiddleware = ({ meta, pclient, data }) => { + if (meta.name !== 'map') return + const mapId = data.itemDamage + if (mapId !== 0 && mapId > highestId) highestId = mapId +} const proxy = new InspectorProxy({ + // host: 'localhost', + // username: 'mcIc3Tank@outlook.com', host: 'localhost', username: 'proxyBot', - version: '1.12.2' + auth: 'offline', + profilesFolder: './nmp-cache', + version: '1.12.2', + checkTimeoutInterval: 90_000, + // port: 25567 }, { - linkOnConnect: true, + // linkOnConnect: true, botAutoStart: false, // start the bot when the proxy starts - botStopOnLogoff: false, // Stop the bot when the last person leaves the proxy + botStopOnLogoff: true, // Stop the bot when the last person leaves the proxy serverAutoStart: true, // start the server when the proxy starts serverStopOnBotStop: false, // Stop the server when the bot stops - autoStartBotOnServerLogin: false + autoStartBotOnServerLogin: true, + toClientMiddlewares: [mapShowMiddleware] +}) + +proxy.on('clientConnect', (client) => { + console.info(`Client ${client.username} connected`) + setInterval(() => { + proxy.message(client, `Current id ${highestId}`, undefined, undefined, 2) + }, 2000) }) +proxy.on('clientDisconnect', () => { + console.info('Client disconnected') +}) + +proxy.on('serverStart', () => console.info('Server started')) +proxy.on('serverClose', () => console.info('Server closed')) + proxy.on('botStart', (conn) => { - conn.bot.on('spawn', () => { - console.info('Bot spawned') - }) - + console.info('Bot spawned') + proxy.on('clientChat', (client, line) => { if (line === 'test') { console.info(proxy.conn.receivingClients) diff --git a/example/writeLevel.js b/example/writeLevel.js new file mode 100644 index 0000000..49f7778 --- /dev/null +++ b/example/writeLevel.js @@ -0,0 +1,9 @@ +const writeLevel = require('prismarine-provider-anvil').level.writeLevel + +if (process.argv.length !== 3) { + console.log('Usage : node example_write_level.js ') + process.exit(1) +} + +writeLevel(process.argv[2], { RandomSeed: [123, 0] }) + .catch(function (err) { console.log(err.stack) }) \ No newline at end of file diff --git a/package.json b/package.json index 43344ff..95221bd 100644 --- a/package.json +++ b/package.json @@ -13,11 +13,16 @@ "author": "Ic3Tank", "license": "ISC", "dependencies": { - "@rob9315/mcproxy": "^1.0.0", + "@rob9315/mcproxy": "IceTank/mcproxy-1.git#position-spoofing", "minecraft-protocol": "^1.35.0", - "mineflayer": "^4.2.0" + "mineflayer": "^4.2.0", + "prismarine-provider-anvil": "^2.7.0", + "prismarine-world": "IceTank/prismarine-world.git#storage-provider-save-fix" }, "devDependencies": { "@types/node": "^16.11.13" + }, + "resolutions": { + "mineflayer/prismarine-world": "IceTank/prismarine-world.git#storage-provider-save-fix" } } diff --git a/src/index.ts b/src/index.ts index 32b3f3d..e9de240 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,15 @@ import { Client, Conn, PacketMiddleware, packetAbilities, sendTo } from "@rob9315/mcproxy"; import { createServer, ServerClient } from "minecraft-protocol"; import type { Server } from "minecraft-protocol"; -import { FakeSpectator, FakePlayer, sendMessage, onceWithCleanup } from "./util"; +import { FakeSpectator, FakePlayer, sendMessage, sleep, onceWithCleanup } from "./util"; import { BotOptions } from "mineflayer"; import EventEmitter, { once } from "events"; import { setTimeout } from "timers/promises"; import type { ChatMessage } from 'prismarine-chat' +import path from "path"; +import fs from 'fs' +import { WorldManager } from "./worldManager"; +import { Vec3 } from 'vec3' export { sendMessage } @@ -45,6 +49,8 @@ export interface ProxyOptions { toClientMiddlewares?: PacketMiddleware[] toServerMiddlewares?: PacketMiddleware[] disabledCommands?: boolean + + positionOffset?: Vec3 } declare module 'mineflayer' { @@ -75,21 +81,30 @@ export interface InspectorProxy { on(event: 'botReady', listener: (conn: Conn) => void): this on(event: 'botEnd', listener: (conn?: Conn) => void): this on(event: 'serverStart', listener: () => void): this + on(event: 'serverClose', listener: () => void): this } export class InspectorProxy extends EventEmitter { options: BotOptions proxyOptions: ProxyOptions + worldManager: WorldManager conn?: Conn server: Server | undefined fakePlayer?: FakePlayer fakeSpectator?: FakeSpectator blockedPacketsWhenNotInControl: string[] proxyChatPrefix: string = '§6Proxy >>§r' + worldSave = 'worlds' + positionOffset?: Vec3 constructor(options: BotOptions, proxyOptions: ProxyOptions = {}) { super() - this.options = options + this.worldManager = new WorldManager('worlds') + this.options = { + ...options, + // @ts-ignore + storageBuilder: this.worldManager.onStorageBuilder() + } this.proxyOptions = proxyOptions this.server = undefined this.blockedPacketsWhenNotInControl = ['abilities', 'position'] @@ -145,12 +160,20 @@ export class InspectorProxy extends EventEmitter { async startBot() { if (this.conn) { + console.info('Already started not starting') return } - this.conn = new Conn(this.options, { + console.info('Starting bot') + let offset: Vec3 | undefined = undefined + if (this.proxyOptions.positionOffset) { + offset = this.proxyOptions.positionOffset + } + const conn = new Conn(this.options, { toClientMiddleware: [...this.genToClientMiddleware(), ...(this.proxyOptions.toClientMiddlewares || [])], - toServerMiddleware: [...this.genToServerMiddleware(), ...(this.proxyOptions.toServerMiddlewares || [])] + toServerMiddleware: [...this.genToServerMiddleware(), ...(this.proxyOptions.toServerMiddlewares || [])], + positionTransformer: offset }) + this.conn = conn this.registerBotEvents() setTimeout().then(() => { this.emit('botReady', this.conn) @@ -200,6 +223,7 @@ export class InspectorProxy extends EventEmitter { if (!this.server) return this.server.close() this.server = undefined + this.emit('serverClose') } startServer() { @@ -222,6 +246,7 @@ export class InspectorProxy extends EventEmitter { } }) + // @ts-ignore this.server.on('login', this.onClientLogin.bind(this)) } @@ -232,12 +257,15 @@ export class InspectorProxy extends EventEmitter { }) } - attach(client: ServerClient) { + attach(client: ServerClient | Client, options: { + toClientMiddleware?: PacketMiddleware[], + toServerMiddleware?: PacketMiddleware[] + } = {}) { if (!this.conn) return // const toClientMiddleware = this.genToClientMiddleware() // const toServerMiddleware = this.genToServerMiddleware() - this.conn.attach(client as unknown as Client) + this.conn.attach(client as unknown as Client, options) } link(client: ServerClient | Client) { @@ -266,7 +294,7 @@ export class InspectorProxy extends EventEmitter { } } - unlink(client?: Client | ServerClient) { + unlink(client: Client | ServerClient | null) { if (!this.conn) return if (client) { if (client !== this.conn.pclient) { @@ -285,8 +313,12 @@ export class InspectorProxy extends EventEmitter { }) } - sendPackets(client: ServerClient) { - this.conn?.sendPackets(client as unknown as Client) + async sendPackets(client: Client) { + // this.conn?.sendPackets(client as unknown as Client) + while (!this.conn?.stateData.bot?.player) { + await sleep(100) + } + this.conn.sendPackets(client) } makeViewFakePlayer(client: ServerClient | Client) { @@ -376,21 +408,34 @@ export class InspectorProxy extends EventEmitter { if (this.proxyOptions.logPlayerJoinLeave) { console.info(`Player ${client.username} joined the proxy`) } - this.sendPackets(client) - this.attach(client) + + const managedPlayer = this.worldManager.newManagedPlayer(client, this.conn.bot.entity.position) + managedPlayer.loadedChunks = this.conn.bot.world.getColumns().map(({ chunkX, chunkZ }: {chunkX: number, chunkZ: number}) => new Vec3(chunkX * 16, 0, chunkZ * 16)) + this.conn.bot.on('spawn', () => { + if (!this.conn?.bot) return + managedPlayer.pos = this.conn.bot.entity.position + }) + this.conn.stateData.bot.physicsEnabled = false + this.attach(client, { + toClientMiddleware: [...managedPlayer.getMiddlewareToClient()] + }) + await this.sendPackets(client as unknown as Client) const connect = this.proxyOptions.linkOnConnect && !this.conn.pclient this.broadcastMessage(`User §3${client.username}§r logged in. ${connect ? 'He is in control' : 'He is not in control'}`) this.printHelp(client) if (!connect) { + // @ts-ignore this.fakePlayer?.register(client) + // @ts-ignore this.fakeSpectator?.makeSpectator(client) } else { this.link(client) } client.once('end', () => { + // @ts-ignore this.fakePlayer?.unregister(client) this.unlink(client) this.emit('clientDisconnect', client) @@ -438,6 +483,7 @@ export class InspectorProxy extends EventEmitter { let returnValue: false | undefined = undefined if (meta.name === 'chat' && !this.proxyOptions.disabledCommands) { this.emit('clientChatRaw', pclient, data.message) + let isCommand = false if ((data.message as string).startsWith('$')) { // command returnValue = false // Cancel everything that starts with $ const cmd = (data.message as string).trim().substring(1) // remove $ @@ -465,19 +511,40 @@ export class InspectorProxy extends EventEmitter { } this.fakeSpectator?.revertPov(pclient) this.fakeSpectator?.tpToOrigin(pclient) + } else if (cmd.startsWith('viewdistance')) { + const words = cmd.split(' ') + if (words[1] === 'disable') { + this.message(pclient, 'Disabling extended render distance') + this.worldManager.disableClientExtension(pclient) + return + } + let chunkViewDistance = Number(words[1]) + if (isNaN(chunkViewDistance)) { + chunkViewDistance = 20 + } + this.message(pclient, `Setting player view distance to ${chunkViewDistance}`, true, true) + this.worldManager.setClientView(pclient, chunkViewDistance) + // this.worldManager.test(this.conn.bot.entity.position, this.worldManager.worlds['minecraft_overworld'], viewDistance) + } else if (cmd === 'reloadchunks') { + this.message(pclient, 'Reloading chunks', true, true) + this.worldManager.reloadClientChunks(pclient, 2) } else { this.printHelp(pclient) } + return false } else { // Normal chat messages data.message = data.message.substring(0, 250) this.emit('clientChat', pclient, data.message) returnValue = undefined } + return data + } else if (meta.name === 'use_entity') { return } else if (meta.name === 'use_entity') { if (this.fakeSpectator?.clientsInCamera[pclient.uuid] && this.fakeSpectator?.clientsInCamera[pclient.uuid].status) { if (data.mouse === 0 || data.mouse === 1) { this.fakeSpectator.revertPov(pclient) + return false } } } @@ -488,7 +555,7 @@ export class InspectorProxy extends EventEmitter { } private genToClientMiddleware() { - const inspector_toClientMiddleware: PacketMiddleware = ({ isCanceled, bound, meta }) => { + const inspector_toClientMiddleware: PacketMiddleware = ({ meta, isCanceled, bound }) => { if (!this.conn) return if (isCanceled) return if (bound !== 'client') return @@ -512,9 +579,10 @@ export class InspectorProxy extends EventEmitter { data.entityId = FakePlayer.fakePlayerId return data } + return data } - const inspector_toClientMiddlewareRecipesFix: PacketMiddleware = ({ meta, bound, pclient, data, isCanceled}) => { + const inspector_toClientMiddlewareRecipesFix: PacketMiddleware = ({ meta, bound, isCanceled }) => { if (isCanceled) return if (bound !== 'client') return if (meta.name === 'unlock_recipes') { diff --git a/src/util.ts b/src/util.ts index 5c8c5fd..820f6d8 100644 --- a/src/util.ts +++ b/src/util.ts @@ -512,6 +512,10 @@ export class FakeSpectator { } } +export async function sleep(ms: number) { + await asyncTimeout(ms) +} + function gamemodeToNumber(str: GameState["gameMode"]) { if (str === 'survival') { return 0 diff --git a/src/worldManager.ts b/src/worldManager.ts new file mode 100644 index 0000000..7111d8e --- /dev/null +++ b/src/worldManager.ts @@ -0,0 +1,274 @@ +import path from "path"; +import fs from 'fs' +import { Vec3, default as VectorBuilder } from 'vec3' +import { Packet, PacketMiddleware } from "@rob9315/mcproxy"; +import { Client } from 'minecraft-protocol' +import { SmartBuffer } from 'smart-buffer'; +import { setTimeout } from 'timers/promises' +const { SpiralIterator2d } = require("prismarine-world").iterators +import { default as PChat } from 'prismarine-chat' +const ChatMessage = PChat('1.12.2') + +const MAX_CHUNK_DATA_LENGTH = 31598; + +export class WorldManager { + savePath: string + worlds: Record = {} + players: Record = {} + constructor(savePath: string) { + this.savePath = savePath + setInterval(() => { + this.onTick() + }, 500) + } + + onStorageBuilder() { + return ({ version, worldName }: { version: string, worldName: string }) => { + worldName = worldName.replace(/:/g, '_') + if (!(worldName in this.worlds)) { + const Anvil = require('prismarine-provider-anvil').Anvil(version) + const worldPath = path.join(this.savePath, worldName, 'region') + if (!fs.existsSync(worldPath)) fs.mkdirSync(worldPath, { recursive: true }) + this.worlds[worldName] = new Anvil(worldPath) + } + return this.worlds[worldName] + } + } + + async getChunk(dimension: string, chunkX: number, chunkZ: number) { + if (!(dimension in this.worlds)) return null + return await this.worlds[dimension].load(chunkX * 16, chunkZ * 16) + } + + /** + * Returns the chunks that should be loaded for a given position and view distance + * @param chunkViewDistance View distance as number off blocks + * @param pos Player position + */ + getChunksForPosition(chunkViewDistance: number, pos: Vec3) { + const spiralIterator = new SpiralIterator2d(pos.scaled(1 / 16).floored(), chunkViewDistance) + const list: Vec3[] = [] + spiralIterator.next() // First one is always the starting position + let next = spiralIterator.next() + while (next) { + list.push(next.scaled(16)) + next = spiralIterator.next() + } + return list + } + + setClientView(client: Client, chunkViewDistance: number) { + const managedPlayer = this.players[client.uuid] + if (!managedPlayer) { + console.info('Player not found') + return + } + managedPlayer.chunkViewDistance = chunkViewDistance + managedPlayer.isActive = true + } + + reloadClientChunks(client: Client, chunkRadius: number = 2) { + const managedPlayer = this.players[client.uuid] + if (!managedPlayer) { + console.info('Player not found') + return + } + managedPlayer.reloadChunks(chunkRadius) + } + + disableClientExtension(client: Client) { + const managedPlayer = this.players[client.uuid] + if (!managedPlayer) { + console.info('Player not found') + return + } + managedPlayer.chunkViewDistance = 6 + managedPlayer.isActive = false + } + + newManagedPlayer(client: Client, pos: Vec3) { + if (!(client.uuid in this.players)) { + this.players[client.uuid] = new ManagedPlayer(this, client, pos) + } + client.once('end', () => { + this.players[client.uuid]?.remove() + delete this.players[client.uuid] + }) + return this.players[client.uuid] + } + + onTick() { + Object.values(this.players).forEach(p => { + p.onTick() + }) + } +} + +class ManagedPlayer { + worldManager: WorldManager + currentWorld: string = 'minecraft_overworld' + /** Loaded chunks in in game coordinates */ + loadQueue = new Set() + client: Client + loadedChunks: Vec3[] = [] + isActive: boolean = false + chunkViewDistance: number = 5 + pos: Vec3 + + private currentlyExpanding = false + + constructor(worldManager: WorldManager, client: Client, pos: Vec3) { + this.worldManager = worldManager + this.client = client + this.pos = pos + } + + getMiddlewareToClient() { + const inspector_toClientMiddlewareMapListener: PacketMiddleware = ({ meta, data, isCanceled, bound }) => { + if (isCanceled) return + if (!this.isActive) return + if (bound !== 'client') return + if (meta.name === 'map_chunk') { + const chunkPos = new Vec3(data.x, 0, data.z).scaled(16) + if (!this.loadedChunks.find(l => l.equals(chunkPos))) { + this.loadedChunks.push() + } + } else if (meta.name === 'unload_chunk') { + const pos = new Vec3(data.chunkX, 0, data.chunkZ).scaled(16) + if (this.isWithinViewDistance(pos)) return false + this.loadedChunks = this.loadedChunks.filter(v => !v.equals(pos)) + } + } + return [inspector_toClientMiddlewareMapListener] + } + + getMiddlewareToServer() { + + } + + private updateLoadQueue() { + const poss = this.worldManager.getChunksForPosition(this.chunkViewDistance, this.pos) + for (const inRange of poss) { + let found = false + for (const loaded of this.loadedChunks) { + if (loaded.equals(inRange)) { + found = true + break + } + } + if (!found) { + const hash = inRange.floored().toString() + if (!this.loadQueue.has(hash)) this.loadQueue.add(hash) + } + } + } + + isWithinViewDistance(pos: Vec3) { + return pos.manhattanDistanceTo(this.pos) < 16 * this.chunkViewDistance + } + + reloadChunks(chunkRadius: number = 2) { + this.loadQueue.clear() + this.loadedChunks = this.loadedChunks.filter(c => { + return this.pos.distanceTo(c) < chunkRadius * 16 + }) + } + + async expand() { + if (this.currentlyExpanding) return + this.currentlyExpanding = true + const world = this.worldManager.worlds[this.currentWorld] + if (!world) { + console.warn('World currently not loaded') + this.currentlyExpanding = false + return + } + // console.info('Loaded chunks', this.loadedChunks) + let next = Array.from(this.loadQueue).map(hash => VectorBuilder(hash)).sort((a, b) => a.distanceTo(this.pos) - b.distanceTo(this.pos))[0] + while (next) { + debugger + const { x, z } = next.scaled(1 / 16).floored() + const column = await world.load(x, z) + if (column) { + if (!this.loadedChunks.find(l => l.equals(next))) { + this.loadedChunks.push(next) + console.info('Generating chunk for ', next.floored(), 'distance', this.pos.distanceTo(next)) + const packets = chunkColumnToPackets(world, { chunkX: x, chunkZ: z, column }) + packets.forEach(p => { + this.client.write(p[0], p[1]) + }) + await setTimeout(1) + } + } + this.loadQueue.delete(next.toString()) + next = Array.from(this.loadQueue).map(hash => VectorBuilder(hash)).sort((a, b) => a.distanceTo(this.pos) - b.distanceTo(this.pos))[0] + } + this.currentlyExpanding = false + } + + remove() { + + } + + onTick() { + if (!this.isActive) return + this.updateLoadQueue() + this.expand().catch(console.error) + } +} + +function chunkColumnToPackets( + world: any, + { chunkX: x, chunkZ: z, column }: { chunkX: number; chunkZ: number; column: any }, + lastBitMask?: number, + chunkData: SmartBuffer = new SmartBuffer(), + chunkEntities: ChunkEntity[] = [] +): Packet[] { + let bitMask = !!lastBitMask ? column.getMask() ^ (column.getMask() & ((lastBitMask << 1) - 1)) : column.getMask(); + let bitMap = lastBitMask ?? 0b0; + let newChunkData = new SmartBuffer(); + + // blockEntities + // chunkEntities.push(...Object.values(column.blockEntities as Map)); + + // checks with bitmask if there is a chunk in memory that (a) exists and (b) was not sent to the client yet + for (let i = 0; i < 16; i++) + if (bitMask & (0b1 << i)) { + column.sections[i].write(newChunkData); + bitMask ^= 0b1 << i; + if (chunkData.length + newChunkData.length > MAX_CHUNK_DATA_LENGTH) { + if (!lastBitMask) column.biomes?.forEach((biome: number) => chunkData.writeUInt8(biome)); + return [ + ['map_chunk', { x, z, bitMap, chunkData: chunkData.toBuffer(), groundUp: !lastBitMask, blockEntities: [] }], + ...chunkColumnToPackets(world, { chunkX: x, chunkZ: z, column }, 0b1 << i, newChunkData), + ...getChunkEntityPackets(world, column.blockEntities), + ]; + } + bitMap ^= 0b1 << i; + chunkData.writeBuffer(newChunkData.toBuffer()); + newChunkData.clear(); + } + if (!lastBitMask) column.biomes?.forEach((biome: number) => chunkData.writeUInt8(biome)); + return [['map_chunk', { x, z, bitMap, chunkData: chunkData.toBuffer(), groundUp: !lastBitMask, blockEntities: [] }], ...getChunkEntityPackets(world, column.blockEntities)]; +} + +type NbtPositionTag = { type: 'int'; value: number }; +type BlockEntity = { x: NbtPositionTag; y: NbtPositionTag; z: NbtPositionTag; id: object }; +type ChunkEntity = { name: string; type: string; value: BlockEntity }; +function getChunkEntityPackets(world: any, blockEntities: { [pos: string]: ChunkEntity }) { + const packets: Packet[] = []; + for (const nbtData of Object.values(blockEntities)) { + const { + x: { value: x }, + y: { value: y }, + z: { value: z }, + } = nbtData.value; + const location = { x, y, z }; + packets.push(['tile_entity_data', { location, nbtData }]); + const block = world.getBlock(new Vec3(x, y, z)); + if (block?.name == 'minecraft:chest') { + packets.push(['block_action', { location, byte1: 1, byte2: 0, blockId: block.type }]); + } + } + return packets; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index af1eca3..3b8dc3f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "ES2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ @@ -43,7 +43,7 @@ /* Emit */ "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ diff --git a/yarn.lock b/yarn.lock index bb5c5ca..3fcefa0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,10 +16,9 @@ jsonwebtoken "^8.5.1" uuid "^8.3.0" -"@rob9315/mcproxy@^1.0.0": +"@rob9315/mcproxy@IceTank/mcproxy-1.git#position-spoofing": version "1.0.0" - resolved "https://registry.yarnpkg.com/@rob9315/mcproxy/-/mcproxy-1.0.0.tgz#fb3e4d49ee6bc3f85f04070bf02c089a433c8e24" - integrity sha512-9ocEzDt3jmimqCOtfp4ut4Xx4v0Ub17YSEBEDP/yAb27/jgzK3lree/UhDx5QBBVDKhPDu13VcIS+Ho2jWDq4g== + resolved "https://codeload.github.com/IceTank/mcproxy-1/tar.gz/b58dca9d2c78227e2750bed6adad336164109a1c" dependencies: minecraft-data "^3.0.0" minecraft-protocol "^1.32.0" @@ -445,6 +444,16 @@ prismarine-physics@^1.3.1: prismarine-nbt "^2.0.0" vec3 "^0.1.7" +prismarine-provider-anvil@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/prismarine-provider-anvil/-/prismarine-provider-anvil-2.7.0.tgz#b3aef307d66de257bcf44f03bd0edb847a778c0c" + integrity sha512-a4NfihRfy+PeKpiWp2CJxTUPMhSROXb7JzA44nfRXqHPDnK4ilC2+MBNeZyi5Wj5OuYRbSd8ZS44YkQMoFR9aQ== + dependencies: + prismarine-chunk "^1.29.0" + prismarine-nbt "^2.0.0" + uint4 "^0.1.2" + vec3 "^0.1.6" + prismarine-recipe@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/prismarine-recipe/-/prismarine-recipe-1.2.0.tgz#95c223a37fc1047e4f8f619988d3923ec0c943f7" @@ -466,10 +475,9 @@ prismarine-windows@^2.4.2: minecraft-data "^3.0.0" prismarine-item "^1.5.0" -prismarine-world@^3.6.0: +prismarine-world@IceTank/prismarine-world.git#storage-provider-save-fix, prismarine-world@^3.6.0: version "3.6.1" - resolved "https://registry.yarnpkg.com/prismarine-world/-/prismarine-world-3.6.1.tgz#c3923ddb8c4806947fb86695f7c8359380aef650" - integrity sha512-sv7rR+vJ/ac3/dm4MoumreL4eqMi3B+h8I+JDYXQkNCdSJJISniQvi5qS4zTnAUCGXx/N6QfQ02bjBfyEoZuRw== + resolved "https://codeload.github.com/IceTank/prismarine-world/tar.gz/707c62437b9faec648bf0f4300fcd7feecbf238f" dependencies: vec3 "^0.1.7" @@ -595,7 +603,7 @@ uuid@^8.2.0, uuid@^8.3.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -vec3@^0.1.3, vec3@^0.1.4, vec3@^0.1.7: +vec3@^0.1.3, vec3@^0.1.4, vec3@^0.1.6, vec3@^0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/vec3/-/vec3-0.1.7.tgz#e203a7bcc2d074c328721421beed48b30c81e41b" integrity sha512-EZSeXBL+L3go2wWwtQQse4fEcNGIQjT14qvi4LYVj1ifZt/J5XZ1QZqkDuOVVH07YwTEIFbsAv3pzwUpF7x9Wg==