fix: fix crashes on packets logging recording
fix: make replay panel minmizable
This commit is contained in:
parent
10f17063c0
commit
b0da1e41d6
9 changed files with 114 additions and 57 deletions
|
|
@ -81,7 +81,7 @@
|
|||
"mojangson": "^2.0.4",
|
||||
"net-browserify": "github:zardoy/prismarinejs-net-browserify",
|
||||
"node-gzip": "^1.1.2",
|
||||
"mcraft-fun-mineflayer": "^0.1.7",
|
||||
"mcraft-fun-mineflayer": "^0.1.8",
|
||||
"peerjs": "^1.5.0",
|
||||
"pixelarticons": "^1.8.1",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
|
|
@ -145,7 +145,7 @@
|
|||
"http-browserify": "^1.7.0",
|
||||
"http-server": "^14.1.1",
|
||||
"https-browserify": "^1.0.0",
|
||||
"mineflayer-mouse": "^0.0.4",
|
||||
"mineflayer-mouse": "^0.0.5",
|
||||
"mc-assets": "^0.2.37",
|
||||
"minecraft-inventory-gui": "github:zardoy/minecraft-inventory-gui#next",
|
||||
"mineflayer": "github:zardoy/mineflayer",
|
||||
|
|
|
|||
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
|
|
@ -135,8 +135,8 @@ importers:
|
|||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
mcraft-fun-mineflayer:
|
||||
specifier: ^0.1.7
|
||||
version: 0.1.7(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/748163e536abe94f3dc8ada7a542bcd689bbbf49(encoding@0.1.13))
|
||||
specifier: ^0.1.8
|
||||
version: 0.1.8(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/748163e536abe94f3dc8ada7a542bcd689bbbf49(encoding@0.1.13))
|
||||
minecraft-data:
|
||||
specifier: 3.83.1
|
||||
version: 3.83.1
|
||||
|
|
@ -359,8 +359,8 @@ importers:
|
|||
specifier: github:zardoy/mineflayer
|
||||
version: https://codeload.github.com/zardoy/mineflayer/tar.gz/748163e536abe94f3dc8ada7a542bcd689bbbf49(encoding@0.1.13)
|
||||
mineflayer-mouse:
|
||||
specifier: ^0.0.4
|
||||
version: 0.0.4(@types/debug@4.1.12)(@types/node@22.8.1)(terser@5.31.3)(tsx@4.7.0)(yaml@2.4.1)
|
||||
specifier: ^0.0.5
|
||||
version: 0.0.5(@types/debug@4.1.12)(@types/node@22.8.1)(terser@5.31.3)(tsx@4.7.0)(yaml@2.4.1)
|
||||
mineflayer-pathfinder:
|
||||
specifier: ^2.4.4
|
||||
version: 2.4.4
|
||||
|
|
@ -6575,9 +6575,9 @@ packages:
|
|||
resolution: {integrity: sha512-49tk3shwxsDoV0PrrbORZEKg613vUQPULgusWjXNl8JEma5y41LEo57D6q4aHliXsV3Gb9ThrkFf6hIb0WlY1Q==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
mcraft-fun-mineflayer@0.1.7:
|
||||
resolution: {integrity: sha512-DJPpp1YFwztoscdIOwfqBV9lbotva621F9GEep3BlqG3l06UdTzX2ElkvwyTR0IurFFBX/YKsNfxwL5WtLytgw==}
|
||||
version: 0.1.7
|
||||
mcraft-fun-mineflayer@0.1.8:
|
||||
resolution: {integrity: sha512-jyJTihNHfeToBPwVs3QMKBlVcaCABJ25YN2eoIBQEVTRVFzaXh13XRpElphLzTMj1Q5XFYqufHtMoR4tsb08qQ==}
|
||||
version: 0.1.8
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
peerDependencies:
|
||||
'@roamhq/wrtc': '*'
|
||||
|
|
@ -6801,8 +6801,8 @@ packages:
|
|||
resolution: {tarball: https://codeload.github.com/zardoy/mineflayer-item-map-downloader/tar.gz/a8d210ecdcf78dd082fa149a96e1612cc9747824}
|
||||
version: 1.2.0
|
||||
|
||||
mineflayer-mouse@0.0.4:
|
||||
resolution: {integrity: sha512-55GqQhJWCXnOnm30uOjtI7nsawPb0kA3cAv6a5n1NJjTWFR6hzMkiRT6xGLYrvYhdf6Er3nsE2Ok/Aysa/jtFQ==}
|
||||
mineflayer-mouse@0.0.5:
|
||||
resolution: {integrity: sha512-0r/AOGTq+wZH9vrBcW93jH2dGRSlwlO6xc1Z67VJUFlZZ8oBefAOpiZq7LIGc7ROVbpcKEKjROdNv/iCFmzXYA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
mineflayer-pathfinder@2.4.4:
|
||||
|
|
@ -17372,7 +17372,7 @@ snapshots:
|
|||
apl-image-packer: 1.1.0
|
||||
zod: 3.24.1
|
||||
|
||||
mcraft-fun-mineflayer@0.1.7(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/748163e536abe94f3dc8ada7a542bcd689bbbf49(encoding@0.1.13)):
|
||||
mcraft-fun-mineflayer@0.1.8(encoding@0.1.13)(mineflayer@https://codeload.github.com/zardoy/mineflayer/tar.gz/748163e536abe94f3dc8ada7a542bcd689bbbf49(encoding@0.1.13)):
|
||||
dependencies:
|
||||
'@zardoy/flying-squid': 0.0.49(encoding@0.1.13)
|
||||
exit-hook: 2.2.1
|
||||
|
|
@ -17742,7 +17742,7 @@ snapshots:
|
|||
- encoding
|
||||
- supports-color
|
||||
|
||||
mineflayer-mouse@0.0.4(@types/debug@4.1.12)(@types/node@22.8.1)(terser@5.31.3)(tsx@4.7.0)(yaml@2.4.1):
|
||||
mineflayer-mouse@0.0.5(@types/debug@4.1.12)(@types/node@22.8.1)(terser@5.31.3)(tsx@4.7.0)(yaml@2.4.1):
|
||||
dependencies:
|
||||
change-case: 5.4.4
|
||||
debug: 4.4.0(supports-color@8.1.1)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ type AppQsParamsArrayTransformed = {
|
|||
[k in keyof AppQsParamsArray]: string[]
|
||||
}
|
||||
|
||||
const initialAppConfig = process.env.INLINED_APP_CONFIG as AppConfig ?? {}
|
||||
globalThis.process ??= {} as any
|
||||
const initialAppConfig = process?.env?.INLINED_APP_CONFIG as AppConfig ?? {}
|
||||
|
||||
export const appQueryParams = new Proxy<AppQsParams>({} as AppQsParams, {
|
||||
get (target, property) {
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ export const createFullScreenProgressReporter = (): ProgressReporter => {
|
|||
setLoadingScreenStatus(message)
|
||||
},
|
||||
end () {
|
||||
if (appStatusState.isError) return
|
||||
fullScreenReporters.splice(fullScreenReporters.indexOf(reporter), 1)
|
||||
if (fullScreenReporters.length === 0) {
|
||||
setLoadingScreenStatus(undefined)
|
||||
|
|
|
|||
|
|
@ -322,6 +322,7 @@ export async function connect (connectOptions: ConnectOptions) {
|
|||
if (ended) return
|
||||
ended = true
|
||||
viewer.resetAll()
|
||||
progress.end()
|
||||
localServer = window.localServer = window.server = undefined
|
||||
gameAdditionalState.viewerConnection = false
|
||||
|
||||
|
|
@ -692,6 +693,7 @@ export async function connect (connectOptions: ConnectOptions) {
|
|||
} catch (err) {
|
||||
handleError(err)
|
||||
}
|
||||
if (!bot) return
|
||||
|
||||
if (connectOptions.server) {
|
||||
bot.loadPlugin(ping)
|
||||
|
|
@ -700,7 +702,6 @@ export async function connect (connectOptions: ConnectOptions) {
|
|||
if (!localReplaySession) {
|
||||
bot.loadPlugin(localRelayServerPlugin)
|
||||
}
|
||||
if (!bot) return
|
||||
|
||||
const p2pConnectTimeout = p2pMultiplayer ? setTimeout(() => { throw new UserError('Spawn timeout. There might be error on the other side, check console.') }, 20_000) : undefined
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { appQueryParamsArray } from './appParams'
|
|||
import type { AppConfig } from './globalState'
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
const initialAppConfig = process.env.INLINED_APP_CONFIG as AppConfig ?? {}
|
||||
const initialAppConfig = process.env?.INLINED_APP_CONFIG as AppConfig ?? {}
|
||||
const defaultOptions = {
|
||||
renderDistance: 3,
|
||||
keepChunksDistance: 1,
|
||||
|
|
|
|||
|
|
@ -232,14 +232,15 @@ export default () => {
|
|||
if (pauseLinksConfig) {
|
||||
for (const [i, row] of pauseLinksConfig.entries()) {
|
||||
const rowButtons: React.ReactNode[] = []
|
||||
for (const button of row) {
|
||||
for (const [k, button] of row.entries()) {
|
||||
const key = `${i}-${k}`
|
||||
const style = { width: (204 / row.length - (row.length > 1 ? 4 : 0)) + 'px' }
|
||||
if (button.type === 'discord') {
|
||||
rowButtons.push(<DiscordButton key={i} style={style} text={button.text}/>)
|
||||
rowButtons.push(<DiscordButton key={key} style={style} text={button.text}/>)
|
||||
} else if (button.type === 'github') {
|
||||
rowButtons.push(<Button key={i} className="button" style={style} onClick={() => openGithub()}>{button.text ?? 'GitHub'}</Button>)
|
||||
rowButtons.push(<Button key={key} className="button" style={style} onClick={() => openGithub()}>{button.text ?? 'GitHub'}</Button>)
|
||||
} else if (button.type === 'url' && button.text) {
|
||||
rowButtons.push(<Button key={i} className="button" style={style} onClick={() => openURL(button.url)}>{button.text}</Button>)
|
||||
rowButtons.push(<Button key={key} className="button" style={style} onClick={() => openURL(button.url)}>{button.text}</Button>)
|
||||
}
|
||||
}
|
||||
pauseLinks.push(<div className={styles.row}>{rowButtons}</div>)
|
||||
|
|
|
|||
|
|
@ -41,31 +41,100 @@ export default function ReplayPanel ({
|
|||
style
|
||||
}: Props) {
|
||||
const [filter, setFilter] = useState(defaultFilter)
|
||||
const [isMinimized, setIsMinimized] = useState(false)
|
||||
const { filtered: filteredPackets, hiddenCount } = filterPackets(packets.slice(-500), filter)
|
||||
|
||||
useEffect(() => {
|
||||
onFilterChange(filter)
|
||||
}, [filter, onFilterChange])
|
||||
|
||||
const handlePlayPauseClick = () => {
|
||||
if (isMinimized) {
|
||||
setIsMinimized(false)
|
||||
} else {
|
||||
onPlayPause?.(!isPlaying)
|
||||
}
|
||||
}
|
||||
|
||||
const playPauseButton = (
|
||||
<button
|
||||
onClick={handlePlayPauseClick}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
cursor: 'pointer',
|
||||
padding: '4px',
|
||||
color: DARK_COLORS.text
|
||||
}}
|
||||
>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
||||
{isPlaying ? (
|
||||
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
|
||||
) : (
|
||||
<path d="M8 5v14l11-7z"/>
|
||||
)}
|
||||
</svg>
|
||||
</button>
|
||||
)
|
||||
|
||||
const baseContainerStyle = {
|
||||
position: 'fixed',
|
||||
top: 18,
|
||||
right: 0,
|
||||
zIndex: 1000,
|
||||
background: DARK_COLORS.bg,
|
||||
padding: '16px',
|
||||
borderRadius: '0 0 8px 0',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '12px',
|
||||
color: DARK_COLORS.text,
|
||||
...style
|
||||
} as const
|
||||
|
||||
if (isMinimized) {
|
||||
return (
|
||||
<div style={{
|
||||
...baseContainerStyle,
|
||||
width: 'auto'
|
||||
}}>
|
||||
{playPauseButton}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
position: 'fixed',
|
||||
top: 18,
|
||||
right: 0,
|
||||
zIndex: 1000,
|
||||
background: DARK_COLORS.bg,
|
||||
padding: '16px',
|
||||
borderRadius: '0 0 8px 0',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
|
||||
...baseContainerStyle,
|
||||
width: '400px',
|
||||
maxHeight: '80vh',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '12px',
|
||||
color: DARK_COLORS.text,
|
||||
...style
|
||||
maxHeight: '80vh'
|
||||
}}>
|
||||
<div style={{ fontSize: '12px', fontWeight: 'bold' }}>{replayName || 'Unnamed Replay'}</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<div style={{ fontSize: '12px', fontWeight: 'bold' }}>{replayName || 'Unnamed Replay'}</div>
|
||||
<button
|
||||
onClick={() => setIsMinimized(true)}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
color: DARK_COLORS.text,
|
||||
cursor: 'pointer',
|
||||
padding: '4px',
|
||||
fontSize: '14px',
|
||||
opacity: 0.7,
|
||||
transition: 'opacity 0.2s'
|
||||
}}
|
||||
onMouseEnter={e => {
|
||||
e.currentTarget.style.opacity = '1'
|
||||
}}
|
||||
onMouseLeave={e => {
|
||||
e.currentTarget.style.opacity = '0.7'
|
||||
}}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style={{ fontSize: '8px', color: '#888888', marginTop: '-8px' }}>Integrated server emulation. Testing client...</div>
|
||||
|
||||
<FilterInput
|
||||
|
|
@ -85,25 +154,7 @@ export default function ReplayPanel ({
|
|||
/>
|
||||
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
||||
<button
|
||||
onClick={() => onPlayPause?.(!isPlaying)}
|
||||
style={{
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
cursor: 'pointer',
|
||||
padding: '4px',
|
||||
color: DARK_COLORS.text
|
||||
}}
|
||||
>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
||||
{isPlaying ? (
|
||||
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
|
||||
) : (
|
||||
<path d="M8 5v14l11-7z"/>
|
||||
)}
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{playPauseButton}
|
||||
<ProgressBar current={progress.current} total={progress.total} />
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useRef, useState } from 'react'
|
||||
import { processPacketDataForLogging } from 'mcraft-fun-mineflayer/build/packetsLogger'
|
||||
import { PacketData } from '../../ReplayPanel'
|
||||
import { useScrollBehavior } from '../../hooks/useScrollBehavior'
|
||||
import { ClientOnMap } from '../../../generatedServerPackets'
|
||||
|
|
@ -12,6 +13,7 @@ const formatters: Record<string, (data: any) => string> = {
|
|||
const blockEntitiesCount = data.blockEntities?.length
|
||||
return `x:${data.x} z:${data.z} C:${sizeOfChunk} E:${blockEntitiesCount}`
|
||||
},
|
||||
default: (data) => processPacketDataForLogging(data)
|
||||
}
|
||||
|
||||
const getPacketIcon = (name: string): string => {
|
||||
|
|
@ -115,7 +117,7 @@ export default function PacketList ({ packets, filter, maxHeight = 300 }: Props)
|
|||
{packet.name}
|
||||
</span>
|
||||
<span style={{ color: DARK_COLORS.textDim, flex: 1, overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
{formatters[packet.name]?.(packet.data) ?? JSON.stringify(packet.data)}
|
||||
{formatters[packet.name]?.(packet.data) ?? formatters.default(packet.data)}
|
||||
</span>
|
||||
</div>
|
||||
{expandedPacket === packet.position && (
|
||||
|
|
@ -123,14 +125,14 @@ export default function PacketList ({ packets, filter, maxHeight = 300 }: Props)
|
|||
<div style={{ marginBottom: '8px' }}>
|
||||
<strong>Data:</strong>
|
||||
<pre style={{ margin: '4px 0', color: DARK_COLORS.textDim }}>
|
||||
{JSON.stringify(packet.data, null, 2)}
|
||||
{JSON.stringify(JSON.parse(formatters.default(packet.data)), null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
{packet.actualVersion && (
|
||||
<div>
|
||||
<strong>Actual Version:</strong>
|
||||
<pre style={{ margin: '4px 0', color: DARK_COLORS.textDim }}>
|
||||
{JSON.stringify(packet.actualVersion, null, 2)}
|
||||
{JSON.stringify(JSON.parse(formatters.default(packet.actualVersion)), null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue