From 96a6b790dbebb85a78435670ecb46fa4f5b6b71c Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 6 May 2025 16:15:42 +0300 Subject: [PATCH 1/3] renderer debug --- renderer/viewer/lib/worldrendererCommon.ts | 17 +++ renderer/viewer/three/worldrendererThree.ts | 30 +++++- src/controls.ts | 6 ++ src/react/RendererDebugMenu.tsx | 109 ++++++++++++++++++++ src/react/rendererDebugMenu.module.css | 34 ++++++ src/react/rendererDebugMenu.module.css.d.ts | 9 ++ src/reactUi.tsx | 2 + 7 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 src/react/RendererDebugMenu.tsx create mode 100644 src/react/rendererDebugMenu.module.css create mode 100644 src/react/rendererDebugMenu.module.css.d.ts diff --git a/renderer/viewer/lib/worldrendererCommon.ts b/renderer/viewer/lib/worldrendererCommon.ts index 516e4264..29332690 100644 --- a/renderer/viewer/lib/worldrendererCommon.ts +++ b/renderer/viewer/lib/worldrendererCommon.ts @@ -8,6 +8,7 @@ import { ItemsRenderer } from 'mc-assets/dist/itemsRenderer' import { WorldBlockProvider } from 'mc-assets/dist/worldBlockProvider' import { generateSpiralMatrix } from 'flying-squid/dist/utils' import { subscribeKey } from 'valtio/utils' +import { proxy } from 'valtio' import { dynamicMcDataFiles } from '../../buildMesherConfig.mjs' import { toMajorVersion } from '../../../src/utils' import { ResourcesManager } from '../../../src/resourcesManager' @@ -59,6 +60,17 @@ export abstract class WorldRendererCommon worldReadyPromise = this.worldReadyResolvers.promise timeOfTheDay = 0 worldSizeParams = { minY: 0, worldHeight: 256 } + reactiveDebugParams = proxy({ + stopRendering: false, + chunksRenderAboveOverride: undefined as number | undefined, + chunksRenderAboveEnabled: false, + chunksRenderBelowOverride: undefined as number | undefined, + chunksRenderBelowEnabled: false, + chunksRenderDistanceOverride: undefined as number | undefined, + chunksRenderDistanceEnabled: false, + disableEntities: false, + // disableParticles: false + }) active = false @@ -313,6 +325,11 @@ export abstract class WorldRendererCommon subscribeKey(this.worldRendererConfig, key, callback) } + onReactiveDebugUpdated(key: T, callback: (value: typeof this.reactiveDebugParams[T]) => void) { + callback(this.reactiveDebugParams[key]) + subscribeKey(this.reactiveDebugParams, key, callback) + } + watchReactivePlayerState () { this.onReactiveValueUpdated('backgroundColor', (value) => { this.changeBackgroundColor(value) diff --git a/renderer/viewer/three/worldrendererThree.ts b/renderer/viewer/three/worldrendererThree.ts index 088f0ee7..8f1ddcca 100644 --- a/renderer/viewer/three/worldrendererThree.ts +++ b/renderer/viewer/three/worldrendererThree.ts @@ -451,7 +451,33 @@ export class WorldRendererThree extends WorldRendererCommon { this.cameraShake.setBaseRotation(pitch, yaw) } + debugChunksVisibilityOverride () { + const { chunksRenderAboveOverride, chunksRenderBelowOverride, chunksRenderDistanceOverride, chunksRenderAboveEnabled, chunksRenderBelowEnabled, chunksRenderDistanceEnabled } = this.reactiveDebugParams + + const baseY = this.cameraSectionPos.y + + if ( + chunksRenderAboveOverride !== undefined || + chunksRenderBelowOverride !== undefined || + chunksRenderDistanceOverride !== undefined + ) { + for (const [key, object] of Object.entries(this.sectionObjects)) { + const [x, y, z] = key.split(',').map(Number) + const isVisible = + // eslint-disable-next-line no-constant-binary-expression, sonarjs/no-redundant-boolean + chunksRenderAboveEnabled && chunksRenderAboveOverride !== undefined ? y >= (baseY + chunksRenderAboveOverride) : true && + // eslint-disable-next-line @stylistic/indent-binary-ops, no-constant-binary-expression, sonarjs/no-redundant-boolean + chunksRenderBelowEnabled && chunksRenderBelowOverride !== undefined ? y <= (baseY + chunksRenderBelowOverride) : true && + // eslint-disable-next-line @stylistic/indent-binary-ops + chunksRenderDistanceEnabled && chunksRenderDistanceOverride !== undefined ? Math.abs(y - baseY) <= chunksRenderDistanceOverride : true + + object.visible = isVisible + } + } + } + render (sizeChanged = false) { + if (this.reactiveDebugParams.stopRendering) return const start = performance.now() this.lastRendered = performance.now() this.cursorBlock.render() @@ -464,7 +490,9 @@ export class WorldRendererThree extends WorldRendererCommon { this.camera.updateProjectionMatrix() } - this.entities.render() + if (!this.reactiveDebugParams.disableEntities) { + this.entities.render() + } // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style const cam = this.camera instanceof THREE.Group ? this.camera.children.find(child => child instanceof THREE.PerspectiveCamera) as THREE.PerspectiveCamera : this.camera diff --git a/src/controls.ts b/src/controls.ts index f8160cfd..730bbbf5 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -632,6 +632,12 @@ export const f3Keybinds: Array<{ }, mobileTitle: 'Show Chunks Debug', }, + { + action () { + showModal({ reactType: 'renderer-debug' }) + }, + mobileTitle: 'Renderer Debug Menu', + }, { key: 'KeyY', async action () { diff --git a/src/react/RendererDebugMenu.tsx b/src/react/RendererDebugMenu.tsx new file mode 100644 index 00000000..415a8c93 --- /dev/null +++ b/src/react/RendererDebugMenu.tsx @@ -0,0 +1,109 @@ +import { WorldRendererCommon } from 'renderer/viewer/lib/worldrendererCommon' +import { useState } from 'react' +import { useSnapshot } from 'valtio' +import Screen from './Screen' +import Button from './Button' +import Slider from './Slider' +import styles from './rendererDebugMenu.module.css' + +export default () => { + const worldRenderer = window.world as WorldRendererCommon + const { reactiveDebugParams } = worldRenderer + const { chunksRenderAboveEnabled, chunksRenderBelowEnabled, chunksRenderDistanceEnabled, chunksRenderAboveOverride, chunksRenderBelowOverride, chunksRenderDistanceOverride, stopRendering, disableEntities } = useSnapshot(reactiveDebugParams) + + + + // Helper to round values to nearest step + const roundToStep = (value: number, step: number) => Math.round(value / step) * step + + return
+
+

Rendering Controls

+
+ +
+

Chunks Render Settings

+
+
+ +
+
+ +
+
+
+
+} diff --git a/src/react/rendererDebugMenu.module.css b/src/react/rendererDebugMenu.module.css new file mode 100644 index 00000000..6c49e04c --- /dev/null +++ b/src/react/rendererDebugMenu.module.css @@ -0,0 +1,34 @@ +.container { + display: flex; + flex-direction: row; + justify-content: space-between; + gap: 20px; + padding: 10px; + height: 100%; + padding-top: env(safe-area-inset-top, 10px); + padding-left: env(safe-area-inset-left, 10px); + padding-right: env(safe-area-inset-right, 10px); + padding-bottom: env(safe-area-inset-bottom, 10px); +} + +.column { + display: flex; + flex-direction: column; + gap: 10px; + min-width: 200px; +} + +.column h3 { + margin: 0; + padding: 0; + font-size: 16px; + color: white; + text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.8); +} + +.sliderGroup { + display: flex; + flex-direction: column; + gap: 5px; + margin-bottom: 10px; +} diff --git a/src/react/rendererDebugMenu.module.css.d.ts b/src/react/rendererDebugMenu.module.css.d.ts new file mode 100644 index 00000000..0f8f2163 --- /dev/null +++ b/src/react/rendererDebugMenu.module.css.d.ts @@ -0,0 +1,9 @@ +// This file is automatically generated. +// Please do not change this file! +interface CssExports { + column: string; + container: string; + sliderGroup: string; +} +declare const cssExports: CssExports; +export default cssExports; diff --git a/src/reactUi.tsx b/src/reactUi.tsx index c91c37d6..d2633708 100644 --- a/src/reactUi.tsx +++ b/src/reactUi.tsx @@ -61,6 +61,7 @@ import ControDebug from './react/ControDebug' import ChunksDebug from './react/ChunksDebug' import ChunksDebugScreen from './react/ChunksDebugScreen' import DebugResponseTimeIndicator from './react/debugs/DebugResponseTimeIndicator' +import RendererDebugMenu from './react/RendererDebugMenu' const isFirefox = ua.getBrowser().name === 'Firefox' if (isFirefox) { @@ -165,6 +166,7 @@ const InGameUi = () => { {!disabledUiParts.includes('bossbars') && displayBossBars && } + From eff87f42e54a19758438f2b609956eb246784aab Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 5 Jun 2025 17:04:18 +0300 Subject: [PATCH 2/3] finish! --- renderer/viewer/three/worldrendererThree.ts | 9 +++++---- src/optionsGuiScheme.tsx | 3 +++ src/optionsStorage.ts | 1 + src/react/RendererDebugMenu.tsx | 12 +++++++++--- src/react/button.module.css | 1 + 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/renderer/viewer/three/worldrendererThree.ts b/renderer/viewer/three/worldrendererThree.ts index 0634d536..0c84a030 100644 --- a/renderer/viewer/three/worldrendererThree.ts +++ b/renderer/viewer/three/worldrendererThree.ts @@ -458,7 +458,7 @@ export class WorldRendererThree extends WorldRendererCommon { debugChunksVisibilityOverride () { const { chunksRenderAboveOverride, chunksRenderBelowOverride, chunksRenderDistanceOverride, chunksRenderAboveEnabled, chunksRenderBelowEnabled, chunksRenderDistanceEnabled } = this.reactiveDebugParams - const baseY = this.cameraSectionPos.y + const baseY = this.cameraSectionPos.y * 16 if ( chunksRenderAboveOverride !== undefined || @@ -469,11 +469,11 @@ export class WorldRendererThree extends WorldRendererCommon { const [x, y, z] = key.split(',').map(Number) const isVisible = // eslint-disable-next-line no-constant-binary-expression, sonarjs/no-redundant-boolean - chunksRenderAboveEnabled && chunksRenderAboveOverride !== undefined ? y >= (baseY + chunksRenderAboveOverride) : true && + (chunksRenderAboveEnabled && chunksRenderAboveOverride !== undefined) ? y <= (baseY + chunksRenderAboveOverride) : true && // eslint-disable-next-line @stylistic/indent-binary-ops, no-constant-binary-expression, sonarjs/no-redundant-boolean - chunksRenderBelowEnabled && chunksRenderBelowOverride !== undefined ? y <= (baseY + chunksRenderBelowOverride) : true && + (chunksRenderBelowEnabled && chunksRenderBelowOverride !== undefined) ? y >= (baseY - chunksRenderBelowOverride) : true && // eslint-disable-next-line @stylistic/indent-binary-ops - chunksRenderDistanceEnabled && chunksRenderDistanceOverride !== undefined ? Math.abs(y - baseY) <= chunksRenderDistanceOverride : true + (chunksRenderDistanceEnabled && chunksRenderDistanceOverride !== undefined) ? Math.abs(y - baseY) <= chunksRenderDistanceOverride : true object.visible = isVisible } @@ -482,6 +482,7 @@ export class WorldRendererThree extends WorldRendererCommon { render (sizeChanged = false) { if (this.reactiveDebugParams.stopRendering) return + this.debugChunksVisibilityOverride() const start = performance.now() this.lastRendered = performance.now() this.cursorBlock.render() diff --git a/src/optionsGuiScheme.tsx b/src/optionsGuiScheme.tsx index 7f4c34ab..c74a72d8 100644 --- a/src/optionsGuiScheme.tsx +++ b/src/optionsGuiScheme.tsx @@ -109,6 +109,9 @@ export const guiOptionsScheme: { 'none' ], }, + rendererPerfDebugOverlay: { + text: 'Performance Debug', + } }, { custom () { diff --git a/src/optionsStorage.ts b/src/optionsStorage.ts index a0c995a0..88e86817 100644 --- a/src/optionsStorage.ts +++ b/src/optionsStorage.ts @@ -106,6 +106,7 @@ const defaultOptions = { vrSupport: true, // doesn't directly affect the VR mode, should only disable the button which is annoying to android users vrPageGameRendering: false, renderDebug: 'basic' as 'none' | 'advanced' | 'basic', + rendererPerfDebugOverlay: false, // advanced bot options autoRespawn: false, diff --git a/src/react/RendererDebugMenu.tsx b/src/react/RendererDebugMenu.tsx index 415a8c93..2e6030c1 100644 --- a/src/react/RendererDebugMenu.tsx +++ b/src/react/RendererDebugMenu.tsx @@ -1,6 +1,7 @@ import { WorldRendererCommon } from 'renderer/viewer/lib/worldrendererCommon' import { useState } from 'react' import { useSnapshot } from 'valtio' +import { options } from '../optionsStorage' import Screen from './Screen' import Button from './Button' import Slider from './Slider' @@ -11,11 +12,13 @@ export default () => { const { reactiveDebugParams } = worldRenderer const { chunksRenderAboveEnabled, chunksRenderBelowEnabled, chunksRenderDistanceEnabled, chunksRenderAboveOverride, chunksRenderBelowOverride, chunksRenderDistanceOverride, stopRendering, disableEntities } = useSnapshot(reactiveDebugParams) - + const { rendererPerfDebugOverlay } = useSnapshot(options) // Helper to round values to nearest step const roundToStep = (value: number, step: number) => Math.round(value / step) * step + if (!rendererPerfDebugOverlay) return null + return

Rendering Controls

@@ -47,6 +50,7 @@ export default () => { min={0} max={256} value={chunksRenderAboveOverride ?? 0} + style={{ width: '100%', }} updateValue={(value) => { const roundedValue = roundToStep(value, 16) reactiveDebugParams.chunksRenderAboveOverride = roundedValue @@ -70,6 +74,7 @@ export default () => { label="Chunks Below" min={0} max={256} + style={{ width: '100%', }} value={chunksRenderBelowOverride ?? 0} updateValue={(value) => { const roundedValue = roundToStep(value, 16) @@ -81,7 +86,7 @@ export default () => { />
-
+ {/*
+
*/}
} diff --git a/src/react/button.module.css b/src/react/button.module.css index 677a1b44..e940c224 100644 --- a/src/react/button.module.css +++ b/src/react/button.module.css @@ -4,6 +4,7 @@ position: relative; width: 200px; min-height: calc(20px * var(--scale)); + max-height: calc(20px * var(--scale)); font-family: minecraft, mojangles, monospace; font-size: 10px; color: white; From c139c9365dfc2a2174155ca863557a1825ced4f5 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 5 Jun 2025 18:33:44 +0300 Subject: [PATCH 3/3] finish --- renderer/viewer/lib/worldrendererCommon.ts | 1 + renderer/viewer/three/worldrendererThree.ts | 5 +++++ src/watchOptions.ts | 1 + 3 files changed, 7 insertions(+) diff --git a/renderer/viewer/lib/worldrendererCommon.ts b/renderer/viewer/lib/worldrendererCommon.ts index 88f36551..2b37742c 100644 --- a/renderer/viewer/lib/worldrendererCommon.ts +++ b/renderer/viewer/lib/worldrendererCommon.ts @@ -50,6 +50,7 @@ export const defaultWorldRendererConfig = { fetchPlayerSkins: true, highlightBlockColor: 'blue', foreground: true, + enableDebugOverlay: false, _experimentalSmoothChunkLoading: true, _renderByChunks: false } diff --git a/renderer/viewer/three/worldrendererThree.ts b/renderer/viewer/three/worldrendererThree.ts index 0c84a030..a8e08068 100644 --- a/renderer/viewer/three/worldrendererThree.ts +++ b/renderer/viewer/three/worldrendererThree.ts @@ -461,6 +461,7 @@ export class WorldRendererThree extends WorldRendererCommon { const baseY = this.cameraSectionPos.y * 16 if ( + this.displayOptions.inWorldRenderingConfig.enableDebugOverlay && chunksRenderAboveOverride !== undefined || chunksRenderBelowOverride !== undefined || chunksRenderDistanceOverride !== undefined @@ -477,6 +478,10 @@ export class WorldRendererThree extends WorldRendererCommon { object.visible = isVisible } + } else { + for (const object of Object.values(this.sectionObjects)) { + object.visible = true + } } } diff --git a/src/watchOptions.ts b/src/watchOptions.ts index 903d7da8..478da4fb 100644 --- a/src/watchOptions.ts +++ b/src/watchOptions.ts @@ -83,6 +83,7 @@ export const watchOptionsAfterViewerInit = () => { watchValue(options, o => { appViewer.inWorldRenderingConfig.vrSupport = o.vrSupport appViewer.inWorldRenderingConfig.vrPageGameRendering = o.vrPageGameRendering + appViewer.inWorldRenderingConfig.enableDebugOverlay = o.rendererPerfDebugOverlay }) watchValue(options, (o, isChanged) => {