Skip to content

Commit

Permalink
fix: fix crashes on packets logging recording
Browse files Browse the repository at this point in the history
fix: make replay panel minmizable
  • Loading branch information
zardoy committed Mar 3, 2025
1 parent 10f1706 commit b0da1e4
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 57 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
22 changes: 11 additions & 11 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src/appParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions src/core/progressReporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -692,6 +693,7 @@ export async function connect (connectOptions: ConnectOptions) {
} catch (err) {
handleError(err)
}
if (!bot) return

if (connectOptions.server) {
bot.loadPlugin(ping)
Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion src/optionsStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 5 additions & 4 deletions src/react/PauseScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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>)
Expand Down
119 changes: 85 additions & 34 deletions src/react/ReplayPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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>

Expand Down
8 changes: 5 additions & 3 deletions src/react/components/replay/PacketList.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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 => {
Expand Down Expand Up @@ -115,22 +117,22 @@ 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 && (
<div style={styles.expandedPacket}>
<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>
)}
Expand Down

0 comments on commit b0da1e4

Please sign in to comment.