Skip to content

Commit

Permalink
fix a few bugs in packet, replayer
Browse files Browse the repository at this point in the history
feat: add a way to ALWAYS inspect 30 packets on disconnect
fix: fix a few server packets
  • Loading branch information
zardoy committed Feb 23, 2025
1 parent 1387cb0 commit 334e8a5
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 18 deletions.
2 changes: 2 additions & 0 deletions src/globalDomListeners.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { saveServer } from './flyingSquidUtils'
import { isGameActive, activeModalStack } from './globalState'
import { options } from './optionsStorage'
import { isInRealGameSession } from './utils'

window.addEventListener('unload', (e) => {
if (!window.justReloaded) {
Expand All @@ -25,6 +26,7 @@ window.addEventListener('beforeunload', (event) => {
if (!isGameActive(true) && activeModalStack.at(-1)?.elem?.id !== 'chat') return
if (sessionStorage.lastReload && !options.preventDevReloadWhilePlaying) return
if (!options.closeConfirmation) return
if (!isInRealGameSession()) return

// For major browsers doning only this is enough
event.preventDefault()
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ import { ref, subscribe } from 'valtio'
import { signInMessageState } from './react/SignInMessageProvider'
import { updateAuthenticatedAccountData, updateLoadedServerData, updateServerConnectionHistory } from './react/serversStorage'
import { versionToNumber } from 'renderer/viewer/prepare/utils'
import packetsPatcher from './packetsPatcher'
import packetsPatcher from './mineflayer/plugins/packetsPatcher'
import { mainMenuState } from './react/MainMenuRenderApp'
import { ItemsRenderer } from 'mc-assets/dist/itemsRenderer'
import './mobileShim'
Expand Down
29 changes: 29 additions & 0 deletions src/mineflayer/plugins/localRelay.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { viewerConnector } from 'mcraft-fun-mineflayer'
import { PACKETS_REPLAY_FILE_EXTENSION, WORLD_STATE_FILE_EXTENSION } from 'mcraft-fun-mineflayer/build/worldState'
import { Bot } from 'mineflayer'
import CircularBuffer from 'flying-squid/dist/circularBuffer'
import { PacketsLogger } from 'mcraft-fun-mineflayer/build/packetsLogger'

export const localRelayServerPlugin = (bot: Bot) => {
bot.loadPlugin(
Expand All @@ -23,10 +25,37 @@ export const localRelayServerPlugin = (bot: Bot) => {
a.click()
URL.revokeObjectURL(url)
}

circularBuffer = new CircularBuffer(AUTO_CAPTURE_PACKETS_COUNT)
bot._client.on('writePacket' as any, (name, params) => {
circularBuffer!.add({ name, params, isFromServer: false })
})
bot._client.on('packet', (data, { name }) => {
circularBuffer!.add({ name, params: data, isFromServer: true })
})
}

declare module 'mineflayer' {
interface Bot {
downloadCurrentWorldState: () => void
}
}

const AUTO_CAPTURE_PACKETS_COUNT = 30
let circularBuffer: CircularBuffer | undefined

export const getLastAutoCapturedPackets = () => circularBuffer?.size
export const downloadAutoCapturedPackets = () => {
const logger = new PacketsLogger()
for (const packet of circularBuffer?.getLastElements() ?? []) {
logger.log(packet.isFromServer, packet.name, packet.params)
}
const textContents = logger.contents
const blob = new Blob([textContents], { type: 'text/plain' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `${bot.username}-auto-captured-packets.txt`
a.click()
URL.revokeObjectURL(url)
}
50 changes: 50 additions & 0 deletions src/mineflayer/plugins/packetsPatcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
export default () => {
// not plugin so its loaded earlier
customEvents.on('mineflayerBotCreated', () => {
botInit()
})
}

const waitingPackets = {} as Record<string, Array<{ name: string, data: any }>>

const botInit = () => {
// PATCH READING
bot._client.on('packet', (data, meta) => {
if (meta.name === 'map_chunk') {
if (data.groundUp && data.bitMap === 1 && data.chunkData.every(x => x === 0)) {
data.chunkData = Buffer.from(Array.from({ length: 12_544 }).fill(0) as any)
}
}
})

// PATCH WRITING

const clientWrite = bot._client.write.bind(bot._client)
const sendAllPackets = (name: string, data: any) => {
for (const packet of waitingPackets[name]) {
clientWrite(packet.name, packet.data)
}
delete waitingPackets[name]
}

//@ts-expect-error
bot._client.write = (name: string, data: any) => {
// if (name === 'position' || name === 'position_look' || name === 'look' || name === 'teleport_confirm') {
// const chunkX = Math.floor(bot.entity.position.x / 16)
// const chunkZ = Math.floor(bot.entity.position.z / 16)
// const loadedColumns = bot.world.getColumns()
// if (loadedColumns.some((c) => c.chunkX === chunkX && c.chunkZ === chunkZ)) {
// sendAllPackets('position', data)
// } else {
// waitingPackets['position'] = [...(waitingPackets['position'] || []), { name, data }]
// return
// }
// }
if (name === 'settings') {
data['viewDistance'] = Math.min(data['viewDistance'], 3)
}
return clientWrite(name, data)
}

// PATCH INTERACTIONS
}
14 changes: 0 additions & 14 deletions src/packetsPatcher.ts

This file was deleted.

5 changes: 3 additions & 2 deletions src/packetsReplay/replayPackets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ export const startLocalReplayServer = (contents: string) => {
}

// time based packets
const FLATTEN_CLIENT_PACKETS = new Set(['position', 'position_look'])
// const FLATTEN_CLIENT_PACKETS = new Set(['position', 'position_look'])
const FLATTEN_CLIENT_PACKETS = new Set([] as string[])

const positions = {
client: 0,
Expand All @@ -97,7 +98,7 @@ const addPacketToReplayer = (name: string, data, isFromClient: boolean, wasUpcom
const side = isFromClient ? 'client' : 'server'

if (wasUpcoming) {
const lastUpcoming = packetsReplayState.packetsPlayback.findLast(p => p.isUpcoming && p.name === name)
const lastUpcoming = packetsReplayState.packetsPlayback.find(p => p.isUpcoming && p.name === name)
if (lastUpcoming) {
lastUpcoming.isUpcoming = false
}
Expand Down
5 changes: 4 additions & 1 deletion src/react/AppStatusProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { guessProblem } from '../errorLoadingScreenHelpers'
import type { ConnectOptions } from '../connect'
import { downloadPacketsReplay, packetsReplaceSessionState, replayLogger } from '../packetsReplay/packetsReplayLegacy'
import { getProxyDetails } from '../microsoftAuthflow'
import { downloadAutoCapturedPackets, getLastAutoCapturedPackets } from '../mineflayer/plugins/localRelay'
import AppStatus from './AppStatus'
import DiveTransition from './DiveTransition'
import { useDidUpdateEffect } from './utils'
Expand Down Expand Up @@ -114,10 +115,11 @@ export default () => {
reconnect()
}

const lastAutoCapturedPackets = getLastAutoCapturedPackets()
return <DiveTransition open={isOpen}>
<AppStatus
status={status}
isError={isError || status === ''} // display back button if status is empty as probably our app is errored
isError={isError || status === ''} // display back button if status is empty as probably our app is errored // display back button if status is empty as probably our app is errored
hideDots={hideDots}
lastStatus={lastStatus}
showReconnect={showReconnect}
Expand Down Expand Up @@ -146,6 +148,7 @@ export default () => {
{displayAuthButton && <Button label='Authenticate' onClick={authReconnectAction} />}
{displayVpnButton && <PossiblyVpnBypassProxyButton reconnect={reconnect} />}
{replayActive && <Button label={`Download Packets Replay ${replayLogger.contents.split('\n').length}L`} onClick={downloadPacketsReplay} />}
{lastAutoCapturedPackets && <Button label={`Inspect Last ${lastAutoCapturedPackets} Packets`} onClick={() => downloadAutoCapturedPackets()} />}
</>
}
>
Expand Down
1 change: 1 addition & 0 deletions src/react/ReplayPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export default function ReplayPanel ({
color: DARK_COLORS.text
}}>
<div style={{ fontSize: '12px', fontWeight: 'bold' }}>{replayName || 'Unnamed Replay'}</div>
<div style={{ fontSize: '8px', color: '#888888', marginTop: '-8px' }}>Integrated server emulation. Testing client...</div>

<FilterInput
value={filter}
Expand Down
1 change: 1 addition & 0 deletions src/worldInteractions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ class WorldInteraction {
if (this.swingTimeout) {
clearTimeout(this.swingTimeout)
}
bot.swingArm('right')
viewer.world.changeHandSwingingState(true, false)
this.swingTimeout = setTimeout(() => {
viewer.world.changeHandSwingingState(false, false)
Expand Down

0 comments on commit 334e8a5

Please sign in to comment.