Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit 68f3f96d04057a184de4f5bc5b522f347666ca5b
Author: Ic3Tank <[email protected]>
Date:   Wed Dec 7 15:16:03 2022 +0100

    Squashed commit of the following:

    commit 39c1a0cab3696cab3cffa6c48b5bd1e8d4097e1d
    Author: Ic3Tank <[email protected]>
    Date:   Wed Dec 7 15:10:10 2022 +0100

        Add position spoofing

    commit 1877c2f
    Author: Ic3Tank <[email protected]>
    Date:   Tue Dec 6 20:54:23 2022 +0100

        Update gitignore

    commit 8913252
    Author: Ic3Tank <[email protected]>
    Date:   Sun Nov 13 21:12:20 2022 +0100

        Add world caching support

commit a7a5621
Merge: 960b0fc 4a7b1da
Author: Ic3Tank <[email protected]>
Date:   Tue Dec 6 20:52:05 2022 +0100

    Merge branch 'master' of https://github.com/IceTank/mineflayer-proxy-inspector

commit 960b0fc
Author: Ic3Tank <[email protected]>
Date:   Tue Dec 6 20:51:55 2022 +0100

    Update gitignore

commit a7394ef
Author: Ic3Tank <[email protected]>
Date:   Wed Nov 2 19:19:39 2022 +0100

    Add server close event
  • Loading branch information
IceTank committed Dec 7, 2022
1 parent 8a373f6 commit e2f0ba2
Show file tree
Hide file tree
Showing 9 changed files with 448 additions and 50 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules
package-lock.json
dist
dist
worlds/**
nmp-cache/**
78 changes: 53 additions & 25 deletions example/simpleProxy.js
Original file line number Diff line number Diff line change
@@ -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: '[email protected]',
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)
Expand Down
9 changes: 9 additions & 0 deletions example/writeLevel.js
Original file line number Diff line number Diff line change
@@ -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 <level.dat>')
process.exit(1)
}

writeLevel(process.argv[2], { RandomSeed: [123, 0] })
.catch(function (err) { console.log(err.stack) })
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
94 changes: 81 additions & 13 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -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 }

Expand Down Expand Up @@ -45,6 +49,8 @@ export interface ProxyOptions {
toClientMiddlewares?: PacketMiddleware[]
toServerMiddlewares?: PacketMiddleware[]
disabledCommands?: boolean

positionOffset?: Vec3
}

declare module 'mineflayer' {
Expand Down Expand Up @@ -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']
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -200,6 +223,7 @@ export class InspectorProxy extends EventEmitter {
if (!this.server) return
this.server.close()
this.server = undefined
this.emit('serverClose')
}

startServer() {
Expand All @@ -222,6 +246,7 @@ export class InspectorProxy extends EventEmitter {
}
})

// @ts-ignore
this.server.on('login', this.onClientLogin.bind(this))
}

Expand All @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 $
Expand Down Expand Up @@ -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
}
}
}
Expand All @@ -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
Expand All @@ -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') {
Expand Down
4 changes: 4 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit e2f0ba2

Please sign in to comment.