minecraft-renderer 0.1.79 → 0.1.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -26
- package/dist/mesher.js +36 -36
- package/dist/mesher.js.map +4 -4
- package/dist/mesherWasm.js +217 -217
- package/dist/minecraft-renderer.js +66 -66
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +450 -450
- package/package.json +5 -2
- package/src/bundler/bundlePrepare.ts +3 -8
- package/src/graphicsBackend/appViewer.ts +10 -7
- package/src/graphicsBackend/config.ts +1 -5
- package/src/graphicsBackend/playerState.ts +35 -34
- package/src/graphicsBackend/preloadWorkers.ts +43 -41
- package/src/graphicsBackend/rendererDefaultOptions.ts +68 -70
- package/src/graphicsBackend/rendererOptionsSync.ts +24 -50
- package/src/graphicsBackend/types.ts +2 -2
- package/src/index.ts +6 -27
- package/src/lib/DebugGui.ts +34 -31
- package/src/lib/animationController.ts +9 -9
- package/src/lib/bakeLegacyLight.ts +1 -6
- package/src/lib/bindAbortableListener.test.ts +32 -12
- package/src/lib/bindAbortableListener.ts +14 -6
- package/src/lib/blockEntityLightRegistry.ts +11 -20
- package/src/lib/blockEntityLighting.test.ts +1 -6
- package/src/lib/blockEntityLighting.ts +5 -5
- package/src/lib/buildSharedConfig.mjs +4 -4
- package/src/lib/buildWorkerMcDataIndexes.test.ts +4 -4
- package/src/lib/buildWorkerMcDataIndexes.ts +11 -19
- package/src/lib/cameraBobbing.ts +1 -1
- package/src/lib/canvas2DOverlay.example.ts +13 -33
- package/src/lib/canvas2DOverlay.quickstart.ts +24 -54
- package/src/lib/canvas2DOverlay.ts +28 -47
- package/src/lib/cleanupDecorator.ts +2 -2
- package/src/lib/createPlayerObject.test.ts +2 -7
- package/src/lib/createPlayerObject.ts +18 -25
- package/src/lib/frameTimingCollector.ts +2 -5
- package/src/lib/guiRenderer.ts +57 -42
- package/src/lib/items.ts +15 -9
- package/src/lib/mesherlogReader.ts +5 -6
- package/src/lib/simpleUtils.ts +5 -5
- package/src/lib/skyLight.ts +3 -3
- package/src/lib/smoothSwitcher.ts +11 -18
- package/src/lib/ui/newStats.ts +10 -12
- package/src/lib/utils/proxy.ts +7 -1
- package/src/lib/utils/skins.ts +4 -4
- package/src/lib/utils.ts +1 -1
- package/src/lib/workerMessageSanitize.ts +5 -12
- package/src/lib/workerProxy.ts +52 -42
- package/src/lib/workerSyncOps.test.ts +58 -41
- package/src/lib/worldrendererCommon.reconfigure.test.ts +24 -21
- package/src/lib/worldrendererCommon.removeColumn.test.ts +11 -13
- package/src/lib/worldrendererCommon.ts +349 -211
- package/src/mesher-legacy/mesher.ts +9 -4
- package/src/mesher-legacy/test/a.ts +1 -1
- package/src/mesher-legacy/test/mesherTester.ts +2 -2
- package/src/mesher-legacy/test/playground.ts +1 -1
- package/src/mesher-legacy/test/run/test-js.ts +1 -1
- package/src/mesher-legacy/test/snapshotUtils.ts +3 -8
- package/src/mesher-legacy/test/test-perf.ts +1 -1
- package/src/mesher-legacy/test/tests.test.ts +2 -2
- package/src/mesher-shared/blockEntityMetadata.test.ts +7 -5
- package/src/mesher-shared/blockEntityMetadata.ts +28 -19
- package/src/mesher-shared/blockPropertiesForMeshing.ts +2 -2
- package/src/mesher-shared/computeHeightmap.ts +2 -4
- package/src/mesher-shared/exportedGeometryTypes.ts +3 -3
- package/src/mesher-shared/faceOcclusion.ts +324 -0
- package/src/mesher-shared/models.ts +80 -131
- package/src/mesher-shared/modelsGeometryCommon.ts +30 -15
- package/src/mesher-shared/shared.ts +46 -46
- package/src/mesher-shared/standaloneRenderer.ts +40 -44
- package/src/mesher-shared/tests/faceOcclusion.test.ts +179 -0
- package/src/mesher-shared/tests/liquidQuadInvariant.test.ts +12 -8
- package/src/mesher-shared/vertexShading.ts +2 -11
- package/src/mesher-shared/world.ts +19 -19
- package/src/mesher-shared/worldLighting.test.ts +2 -2
- package/src/performanceMonitor/PerformanceMonitor.ts +4 -13
- package/src/performanceMonitor/formatPerformanceFactorsDebug.ts +2 -2
- package/src/performanceMonitor/index.ts +1 -5
- package/src/performanceMonitor/types.ts +1 -1
- package/src/playerState/playerState.ts +55 -50
- package/src/playerState/types.ts +2 -8
- package/src/playground/allEntitiesDebug.ts +19 -16
- package/src/playground/baseScene.ts +29 -32
- package/src/playground/mobileControls.tsx +133 -129
- package/src/playground/playground.html +76 -73
- package/src/playground/playground.ts +14 -1
- package/src/playground/playgroundUi.tsx +100 -74
- package/src/playground/reactUtils.ts +3 -7
- package/src/playground/scenes/entities.ts +10 -7
- package/src/playground/scenes/frequentUpdates.ts +5 -5
- package/src/playground/scenes/geometryExport.ts +6 -20
- package/src/playground/scenes/highPosEntityUpdates.ts +2 -10
- package/src/playground/scenes/index.ts +1 -1
- package/src/playground/scenes/lightingStarfield.ts +18 -12
- package/src/playground/scenes/main.ts +15 -11
- package/src/playground/scenes/partialBlockCulling.ts +31 -0
- package/src/playground/scenes/railsCobweb.ts +1 -1
- package/src/playground/scenes/rotationIssue.ts +1 -1
- package/src/playground/scenes/slabsOptimization.ts +1 -2
- package/src/playground/scenes/transparencyIssue.ts +1 -1
- package/src/playground/shared.ts +2 -2
- package/src/resourcesManager/resourcesManager.ts +29 -54
- package/src/resourcesManager/resourcesManager.worker.test.ts +6 -10
- package/src/shims/minecraftData.ts +70 -24
- package/src/sign-renderer/index.html +10 -12
- package/src/sign-renderer/index.ts +29 -29
- package/src/sign-renderer/playground.ts +22 -15
- package/src/sign-renderer/tests.test.ts +16 -13
- package/src/sign-renderer/vite.config.ts +2 -2
- package/src/three/appShared.ts +46 -25
- package/src/three/bannerRenderer.ts +33 -61
- package/src/three/cameraCollisionBlockCache.ts +156 -0
- package/src/three/cameraCollisionSolidity.ts +50 -0
- package/src/three/cameraShake.ts +15 -6
- package/src/three/chunkMeshManager.ts +223 -390
- package/src/three/cinimaticScript.ts +26 -15
- package/src/three/cubeDrawSpans.ts +27 -37
- package/src/three/cubeMultiDraw.ts +9 -22
- package/src/three/documentRenderer.ts +15 -18
- package/src/three/entities.ts +175 -150
- package/src/three/entity/EntityMesh.ts +114 -108
- package/src/three/entity/animations.js +3 -3
- package/src/three/entity/armorModels.ts +15 -15
- package/src/three/entity/gltfAnimationUtils.ts +2 -5
- package/src/three/fireworks.ts +34 -32
- package/src/three/fireworksRenderer.ts +32 -29
- package/src/three/globalBlockBuffer.ts +167 -100
- package/src/three/globalLegacyBuffer.ts +248 -264
- package/src/three/graphicsBackendBase.ts +19 -25
- package/src/three/graphicsBackendOffThread.ts +12 -15
- package/src/three/hand.ts +21 -21
- package/src/three/handLegacy.ts +3 -13
- package/src/three/holdingBlock.ts +116 -79
- package/src/three/holdingBlockFactory.ts +1 -4
- package/src/three/holdingBlockItemIdentity.test.ts +25 -17
- package/src/three/holdingBlockItemIdentity.ts +9 -6
- package/src/three/holdingBlockLegacy.ts +113 -132
- package/src/three/itemMesh.ts +20 -29
- package/src/three/legacyMultiDraw.ts +10 -16
- package/src/three/legacySectionCull.ts +8 -14
- package/src/three/menuBackground/activeView.ts +1 -4
- package/src/three/menuBackground/assetUrl.ts +1 -1
- package/src/three/menuBackground/classic.ts +4 -12
- package/src/three/menuBackground/gpuPreference.ts +1 -3
- package/src/three/menuBackground/index.ts +2 -11
- package/src/three/menuBackground/renderer.ts +1 -5
- package/src/three/menuBackground/types.ts +1 -4
- package/src/three/menuBackground/v2.ts +196 -96
- package/src/three/menuBackground/v2Meta.ts +3 -3
- package/src/three/menuBackground/worldBlocks.ts +37 -35
- package/src/three/modules/blockBreakParticles.ts +59 -28
- package/src/three/modules/cameraBobbing.ts +3 -6
- package/src/three/modules/index.ts +1 -1
- package/src/three/modules/rain.ts +10 -23
- package/src/three/modules/sciFiWorldReveal.ts +11 -25
- package/src/three/modules/starfield.ts +7 -13
- package/src/three/renderSlot.ts +28 -16
- package/src/three/rendererModuleSystem.ts +1 -3
- package/src/three/sceneOrigin.ts +96 -33
- package/src/three/sectionRaycastAabb.ts +24 -110
- package/src/three/shaderCubeMesh.ts +6 -17
- package/src/three/shaders/cubeBlockShader.ts +85 -96
- package/src/three/shaders/legacyBlockShader.ts +21 -43
- package/src/three/shaders/textureIndexMapping.ts +89 -95
- package/src/three/shaders/tintPalette.ts +156 -170
- package/src/three/signTextureCache.ts +9 -12
- package/src/three/skyboxRenderer.ts +62 -70
- package/src/three/tests/chunkMeshManagerLegacy.test.ts +34 -64
- package/src/three/tests/cubeDrawSpans.test.ts +55 -25
- package/src/three/tests/globalBlockBuffer.test.ts +217 -0
- package/src/three/tests/globalLegacyBuffer.test.ts +300 -41
- package/src/three/tests/legacyMultiDraw.test.ts +8 -29
- package/src/three/tests/pr3PerFrameCpuCuts.test.ts +106 -29
- package/src/three/tests/signTextureCache.test.ts +4 -4
- package/src/three/thirdPersonVoxelRaycast.ts +120 -0
- package/src/three/threeJsMedia.ts +55 -72
- package/src/three/threeJsParticles.ts +32 -41
- package/src/three/threeJsSound.ts +3 -3
- package/src/three/threeJsUtils.ts +3 -3
- package/src/three/threeWorker.ts +2 -2
- package/src/three/waypointSprite.ts +55 -82
- package/src/three/waypoints.ts +20 -23
- package/src/three/world/cursorBlock.ts +25 -12
- package/src/three/world/vr.ts +11 -17
- package/src/three/worldGeometryExport.ts +15 -34
- package/src/three/worldRendererThree.ts +144 -166
- package/src/wasm-mesher/bridge/convertChunk.ts +3 -9
- package/src/wasm-mesher/bridge/render-from-wasm.ts +204 -229
- package/src/wasm-mesher/bridge/shaderCubeBridge.ts +26 -67
- package/src/wasm-mesher/tests/cameraCollisionBlockCache.test.ts +82 -0
- package/src/wasm-mesher/tests/cullingRegression.test.ts +307 -0
- package/src/wasm-mesher/tests/heightmapParity.test.ts +8 -18
- package/src/wasm-mesher/tests/mesherWasmConversionCache.test.ts +2 -2
- package/src/wasm-mesher/tests/sectionRaycastAabb.test.ts +1 -93
- package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +103 -141
- package/src/wasm-mesher/tests/splitColumnWasmOutput.test.ts +14 -22
- package/src/wasm-mesher/tests/thirdPersonVoxelRaycast.test.ts +63 -0
- package/src/wasm-mesher/worker/mesherWasm.ts +150 -141
- package/src/wasm-mesher/worker/mesherWasmConversionCache.ts +2 -8
- package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +1 -3
- package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +1 -5
- package/src/wasm-mesher/worker/mesherWasmRequestTracker.ts +42 -42
- package/src/worldView/worldView.spiral.test.ts +1 -1
- package/src/worldView/worldView.ts +34 -39
- package/src/worldView/worldViewWorkerBridge.test.ts +4 -4
|
@@ -9,7 +9,15 @@ import { proxy, subscribe } from 'valtio'
|
|
|
9
9
|
import type { ResourcesManagerTransferred } from '../resourcesManager/resourcesManager'
|
|
10
10
|
import { dynamicMcDataFiles } from './buildSharedConfig.mjs'
|
|
11
11
|
import { DisplayWorldOptions, GraphicsInitOptions, RendererReactiveState, SoundSystem } from '../graphicsBackend/types'
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
HighestBlockInfo,
|
|
14
|
+
CustomBlockModels,
|
|
15
|
+
BlockStateModelInfo,
|
|
16
|
+
getBlockAssetsCacheKey,
|
|
17
|
+
MesherConfig,
|
|
18
|
+
MesherMainEvent,
|
|
19
|
+
SECTION_HEIGHT
|
|
20
|
+
} from '../mesher-shared/shared'
|
|
13
21
|
import { chunkPos } from './simpleUtils'
|
|
14
22
|
import { addNewStat, MC_RENDERER_DEBUG_OVERLAY_CLASS, removeAllStats, updatePanesVisibility, updateStatText } from './ui/newStats'
|
|
15
23
|
import { getPlayerStateUtils } from '../graphicsBackend/playerState'
|
|
@@ -24,6 +32,7 @@ import { generateSpiralMatrix } from './spiral'
|
|
|
24
32
|
import { PlayerStateReactive } from '../playerState/playerState'
|
|
25
33
|
import { IndexedData } from 'minecraft-data'
|
|
26
34
|
import { WorldRendererConfig } from '../graphicsBackend/config'
|
|
35
|
+
import { CameraCollisionBlockCache } from '../three/cameraCollisionBlockCache'
|
|
27
36
|
|
|
28
37
|
function mod(x, n) {
|
|
29
38
|
return ((x % n) + n) % n
|
|
@@ -35,6 +44,8 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
35
44
|
timeOfTheDay = 0
|
|
36
45
|
lastMesherSkyLight = 15
|
|
37
46
|
worldSizeParams = { minY: 0, worldHeight: 256 }
|
|
47
|
+
/** Block columns for third-person voxel DDA (renderer thread). */
|
|
48
|
+
cameraCollisionBlockCache: CameraCollisionBlockCache
|
|
38
49
|
reactiveDebugParams = proxy({
|
|
39
50
|
stopRendering: false,
|
|
40
51
|
chunksRenderAboveOverride: undefined as number | undefined,
|
|
@@ -43,7 +54,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
43
54
|
chunksRenderBelowEnabled: false,
|
|
44
55
|
chunksRenderDistanceOverride: undefined as number | undefined,
|
|
45
56
|
chunksRenderDistanceEnabled: false,
|
|
46
|
-
disableEntities: false
|
|
57
|
+
disableEntities: false
|
|
47
58
|
// disableParticles: false
|
|
48
59
|
})
|
|
49
60
|
|
|
@@ -90,7 +101,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
90
101
|
isProcessingQueue = false
|
|
91
102
|
ONMESSAGE_TIME_LIMIT = 30 // ms
|
|
92
103
|
|
|
93
|
-
handleResize = () => {
|
|
104
|
+
handleResize = () => {}
|
|
94
105
|
highestBlocksByChunks = new Map<string, { [chunkKey: string]: HighestBlockInfo }>()
|
|
95
106
|
blockEntities = {}
|
|
96
107
|
|
|
@@ -131,7 +142,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
131
142
|
private mesherPoolSnapshot = {
|
|
132
143
|
mesherWorkers: -1,
|
|
133
144
|
wasmMesher: false,
|
|
134
|
-
dedicatedChangeWorker: false
|
|
145
|
+
dedicatedChangeWorker: false
|
|
135
146
|
}
|
|
136
147
|
private mesherReconfigureQueue: Promise<void> = Promise.resolve()
|
|
137
148
|
private heightmapDebounceTimers = new Map<string, ReturnType<typeof setTimeout>>()
|
|
@@ -203,7 +214,12 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
203
214
|
return (this.initOptions.config.statsVisible ?? 0) > 1
|
|
204
215
|
}
|
|
205
216
|
|
|
206
|
-
constructor(
|
|
217
|
+
constructor(
|
|
218
|
+
public readonly resourcesManager: ResourcesManagerTransferred,
|
|
219
|
+
public displayOptions: DisplayWorldOptions,
|
|
220
|
+
public initOptions: GraphicsInitOptions
|
|
221
|
+
) {
|
|
222
|
+
this.cameraCollisionBlockCache = new CameraCollisionBlockCache(this.displayOptions.version)
|
|
207
223
|
this.snapshotInitialValues()
|
|
208
224
|
this.worldRendererConfig = displayOptions.inWorldRenderingConfig
|
|
209
225
|
this.playerStateReactive = displayOptions.playerStateReactive!
|
|
@@ -270,12 +286,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
270
286
|
if (!this.active) return
|
|
271
287
|
await this.updateAssetsData()
|
|
272
288
|
}
|
|
273
|
-
bindAbortableEmitterListener(
|
|
274
|
-
this.resourcesManager,
|
|
275
|
-
'assetsTexturesUpdated',
|
|
276
|
-
onAssetsTexturesUpdated,
|
|
277
|
-
this.abortController.signal
|
|
278
|
-
)
|
|
289
|
+
bindAbortableEmitterListener(this.resourcesManager, 'assetsTexturesUpdated', onAssetsTexturesUpdated, this.abortController.signal)
|
|
279
290
|
|
|
280
291
|
this.watchReactivePlayerState()
|
|
281
292
|
this.watchReactiveConfig()
|
|
@@ -283,7 +294,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
283
294
|
this.worldReadyResolvers.resolve()
|
|
284
295
|
}
|
|
285
296
|
|
|
286
|
-
snapshotInitialValues() {
|
|
297
|
+
snapshotInitialValues() {}
|
|
287
298
|
|
|
288
299
|
wasChunkSentToWorker(chunkKey: string) {
|
|
289
300
|
return this.loadedChunks[chunkKey]
|
|
@@ -305,7 +316,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
305
316
|
}
|
|
306
317
|
}
|
|
307
318
|
|
|
308
|
-
async getBlockInfo(blockPos: { x: number
|
|
319
|
+
async getBlockInfo(blockPos: { x: number; y: number; z: number }, stateId: number) {
|
|
309
320
|
const CHUNK_SIZE = 16
|
|
310
321
|
const chunkKey = `${Math.floor(blockPos.x / CHUNK_SIZE) * CHUNK_SIZE},${Math.floor(blockPos.z / CHUNK_SIZE) * CHUNK_SIZE}`
|
|
311
322
|
const customBlockName = this.protocolCustomBlocks.get(chunkKey)?.[`${blockPos.x},${blockPos.y},${blockPos.z}`]
|
|
@@ -323,14 +334,17 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
323
334
|
|
|
324
335
|
private createMesherWorker() {
|
|
325
336
|
const script = this.getMesherWorkerScript()
|
|
326
|
-
return initMesherWorker(
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
337
|
+
return initMesherWorker(
|
|
338
|
+
data => {
|
|
339
|
+
if (Array.isArray(data)) {
|
|
340
|
+
this.messageQueue.push(...data)
|
|
341
|
+
} else {
|
|
342
|
+
this.messageQueue.push(data)
|
|
343
|
+
}
|
|
344
|
+
void this.processMessageQueue('worker')
|
|
345
|
+
},
|
|
346
|
+
script === 'wasm' ? 'mesherWasm.js' : 'mesher.js'
|
|
347
|
+
)
|
|
334
348
|
}
|
|
335
349
|
|
|
336
350
|
initWorkers(numWorkers = this.worldRendererConfig.mesherWorkers) {
|
|
@@ -343,7 +357,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
343
357
|
this.mesherPoolSnapshot = {
|
|
344
358
|
mesherWorkers: this.worldRendererConfig.mesherWorkers,
|
|
345
359
|
wasmMesher: this.worldRendererConfig.wasmMesher,
|
|
346
|
-
dedicatedChangeWorker: this.worldRendererConfig.dedicatedChangeWorker
|
|
360
|
+
dedicatedChangeWorker: this.worldRendererConfig.dedicatedChangeWorker
|
|
347
361
|
}
|
|
348
362
|
}
|
|
349
363
|
|
|
@@ -353,11 +367,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
353
367
|
const tryReconfigure = () => {
|
|
354
368
|
const cfg = this.worldRendererConfig
|
|
355
369
|
const snap = this.mesherPoolSnapshot
|
|
356
|
-
if (
|
|
357
|
-
cfg.mesherWorkers === snap.mesherWorkers &&
|
|
358
|
-
cfg.wasmMesher === snap.wasmMesher &&
|
|
359
|
-
cfg.dedicatedChangeWorker === snap.dedicatedChangeWorker
|
|
360
|
-
) {
|
|
370
|
+
if (cfg.mesherWorkers === snap.mesherWorkers && cfg.wasmMesher === snap.wasmMesher && cfg.dedicatedChangeWorker === snap.dedicatedChangeWorker) {
|
|
361
371
|
return
|
|
362
372
|
}
|
|
363
373
|
this.syncMesherPoolSnapshot()
|
|
@@ -365,16 +375,14 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
365
375
|
}
|
|
366
376
|
|
|
367
377
|
for (const key of ['mesherWorkers', 'wasmMesher', 'dedicatedChangeWorker'] as const) {
|
|
368
|
-
this.valtioUnsubs.push(
|
|
369
|
-
this.onReactiveConfigUpdated(key, tryReconfigure, false)
|
|
370
|
-
)
|
|
378
|
+
this.valtioUnsubs.push(this.onReactiveConfigUpdated(key, tryReconfigure, false))
|
|
371
379
|
}
|
|
372
380
|
}
|
|
373
381
|
|
|
374
382
|
private enqueueMesherWorkersReconfigure() {
|
|
375
383
|
this.mesherReconfigureQueue = this.mesherReconfigureQueue
|
|
376
384
|
.then(() => this.reconfigureMesherWorkers())
|
|
377
|
-
.catch(
|
|
385
|
+
.catch(err => {
|
|
378
386
|
console.error('[Mesher] Failed to reconfigure workers:', err)
|
|
379
387
|
})
|
|
380
388
|
}
|
|
@@ -450,7 +458,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
450
458
|
|
|
451
459
|
onReactiveConfigUpdated<T extends keyof typeof this.worldRendererConfig>(
|
|
452
460
|
key: T,
|
|
453
|
-
callback: (value: typeof this.worldRendererConfig[T]) => void,
|
|
461
|
+
callback: (value: (typeof this.worldRendererConfig)[T]) => void,
|
|
454
462
|
initial = true
|
|
455
463
|
) {
|
|
456
464
|
if (initial) {
|
|
@@ -462,19 +470,19 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
462
470
|
return subscribeKey(this.worldRendererConfig, key, callback)
|
|
463
471
|
}
|
|
464
472
|
|
|
465
|
-
onReactiveDebugUpdated<T extends keyof typeof this.reactiveDebugParams>(key: T, callback: (value: typeof this.reactiveDebugParams[T]) => void) {
|
|
473
|
+
onReactiveDebugUpdated<T extends keyof typeof this.reactiveDebugParams>(key: T, callback: (value: (typeof this.reactiveDebugParams)[T]) => void) {
|
|
466
474
|
callback(this.reactiveDebugParams[key])
|
|
467
475
|
subscribeKey(this.reactiveDebugParams, key, callback)
|
|
468
476
|
}
|
|
469
477
|
|
|
470
478
|
watchReactivePlayerState() {
|
|
471
479
|
this.valtioUnsubs.push(
|
|
472
|
-
this.onReactivePlayerStateUpdated('backgroundColor',
|
|
480
|
+
this.onReactivePlayerStateUpdated('backgroundColor', value => {
|
|
473
481
|
this.changeBackgroundColor(value)
|
|
474
482
|
})
|
|
475
483
|
)
|
|
476
484
|
this.valtioUnsubs.push(
|
|
477
|
-
this.onReactivePlayerStateUpdated('cardinalLight',
|
|
485
|
+
this.onReactivePlayerStateUpdated('cardinalLight', value => {
|
|
478
486
|
this.changeCardinalLight(value)
|
|
479
487
|
})
|
|
480
488
|
)
|
|
@@ -482,7 +490,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
482
490
|
|
|
483
491
|
watchReactiveConfig() {
|
|
484
492
|
this.valtioUnsubs.push(
|
|
485
|
-
this.onReactiveConfigUpdated('fetchPlayerSkins',
|
|
493
|
+
this.onReactiveConfigUpdated('fetchPlayerSkins', value => {
|
|
486
494
|
setSkinsConfig({ apiEnabled: value })
|
|
487
495
|
})
|
|
488
496
|
)
|
|
@@ -491,7 +499,12 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
491
499
|
async processMessageQueue(source: string) {
|
|
492
500
|
if (this.isProcessingQueue || this.messageQueue.length === 0) return
|
|
493
501
|
this.logWorkerWork(`# ${source} processing queue`)
|
|
494
|
-
if (
|
|
502
|
+
if (
|
|
503
|
+
this.lastRendered &&
|
|
504
|
+
performance.now() - this.lastRendered > this.ONMESSAGE_TIME_LIMIT &&
|
|
505
|
+
this.worldRendererConfig._experimentalSmoothChunkLoading &&
|
|
506
|
+
this.renderingActive
|
|
507
|
+
) {
|
|
495
508
|
const start = performance.now()
|
|
496
509
|
await new Promise(resolve => {
|
|
497
510
|
requestAnimationFrame(resolve)
|
|
@@ -512,7 +525,10 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
512
525
|
}
|
|
513
526
|
|
|
514
527
|
// Check if we've exceeded the time limit
|
|
515
|
-
if (
|
|
528
|
+
if (
|
|
529
|
+
processingStopped ||
|
|
530
|
+
(performance.now() - startTime > this.ONMESSAGE_TIME_LIMIT && this.renderingActive && this.worldRendererConfig._experimentalSmoothChunkLoading)
|
|
531
|
+
) {
|
|
516
532
|
// If we have more messages and exceeded time limit, schedule next batch
|
|
517
533
|
if (this.messageQueue.length > 0) {
|
|
518
534
|
requestAnimationFrame(async () => {
|
|
@@ -544,7 +560,8 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
544
560
|
const chunkCoords = data.key.split(',').map(Number)
|
|
545
561
|
this.lastChunkDistance = Math.max(...this.getDistance(new Vec3(chunkCoords[0], 0, chunkCoords[2])))
|
|
546
562
|
}
|
|
547
|
-
if (data.type === 'sectionFinished') {
|
|
563
|
+
if (data.type === 'sectionFinished') {
|
|
564
|
+
// on after load & unload section
|
|
548
565
|
this.logWorkerWork(`<- ${data.workerIndex} sectionFinished ${data.key} ${JSON.stringify({ processTime: data.processTime })}`)
|
|
549
566
|
if (!this.sectionsWaiting.has(data.key)) {
|
|
550
567
|
console.debug(`sectionFinished for non-outstanding section ${data.key} (viewDistance=${this.viewDistance})`)
|
|
@@ -558,7 +575,8 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
558
575
|
|
|
559
576
|
const chunkCoords = data.key.split(',').map(Number)
|
|
560
577
|
const chunkKey = `${chunkCoords[0]},${chunkCoords[2]}`
|
|
561
|
-
if (this.loadedChunks[chunkKey]) {
|
|
578
|
+
if (this.loadedChunks[chunkKey]) {
|
|
579
|
+
// ensure chunk data was added, not a neighbor chunk update
|
|
562
580
|
let loaded = true
|
|
563
581
|
const sectionHeight = this.getSectionHeight()
|
|
564
582
|
for (let y = this.worldMinYRender; y < this.worldSizeParams.worldHeight; y += sectionHeight) {
|
|
@@ -601,15 +619,15 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
601
619
|
this.renderUpdateEmitter.emit('update')
|
|
602
620
|
if (data.processTime) {
|
|
603
621
|
this.workersProcessAverageTimeCount++
|
|
604
|
-
this.workersProcessAverageTime =
|
|
622
|
+
this.workersProcessAverageTime =
|
|
623
|
+
(this.workersProcessAverageTime * (this.workersProcessAverageTimeCount - 1) + data.processTime) / this.workersProcessAverageTimeCount
|
|
605
624
|
this.maxWorkersProcessTime = Math.max(this.maxWorkersProcessTime, data.processTime)
|
|
606
625
|
}
|
|
607
|
-
if (typeof data.pre === 'number' && typeof data.wasm === 'number' && typeof data.post === 'number'
|
|
608
|
-
&& (data.pre > 0 || data.wasm > 0 || data.post > 0)) {
|
|
626
|
+
if (typeof data.pre === 'number' && typeof data.wasm === 'number' && typeof data.post === 'number' && (data.pre > 0 || data.wasm > 0 || data.post > 0)) {
|
|
609
627
|
const n = ++this.workersPhaseSampleCount
|
|
610
|
-
this.workersPreAverageTime = (
|
|
611
|
-
this.workersWasmAverageTime = (
|
|
612
|
-
this.workersPostAverageTime = (
|
|
628
|
+
this.workersPreAverageTime = (this.workersPreAverageTime * (n - 1) + data.pre) / n
|
|
629
|
+
this.workersWasmAverageTime = (this.workersWasmAverageTime * (n - 1) + data.wasm) / n
|
|
630
|
+
this.workersPostAverageTime = (this.workersPostAverageTime * (n - 1) + data.post) / n
|
|
613
631
|
// Pre-stage substages — additive schema; treat undefined as 0 so
|
|
614
632
|
// events from older mesher builds don't poison the running mean.
|
|
615
633
|
const ptc = typeof data.preTargetConvert === 'number' ? data.preTargetConvert : 0
|
|
@@ -619,11 +637,11 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
619
637
|
const po = typeof data.preOther === 'number' ? data.preOther : 0
|
|
620
638
|
const pch = typeof data.preCacheHits === 'number' ? data.preCacheHits : 0
|
|
621
639
|
const pcm = typeof data.preCacheMisses === 'number' ? data.preCacheMisses : 0
|
|
622
|
-
this.workersPreTargetConvertAverageTime = (
|
|
623
|
-
this.workersPreNeighborConvertAverageTime = (
|
|
624
|
-
this.workersPreNeighborCountAverage = (
|
|
625
|
-
this.workersPreTypedArrayBuildAverageTime = (
|
|
626
|
-
this.workersPreOtherAverageTime = (
|
|
640
|
+
this.workersPreTargetConvertAverageTime = (this.workersPreTargetConvertAverageTime * (n - 1) + ptc) / n
|
|
641
|
+
this.workersPreNeighborConvertAverageTime = (this.workersPreNeighborConvertAverageTime * (n - 1) + pnc) / n
|
|
642
|
+
this.workersPreNeighborCountAverage = (this.workersPreNeighborCountAverage * (n - 1) + pncn) / n
|
|
643
|
+
this.workersPreTypedArrayBuildAverageTime = (this.workersPreTypedArrayBuildAverageTime * (n - 1) + ptab) / n
|
|
644
|
+
this.workersPreOtherAverageTime = (this.workersPreOtherAverageTime * (n - 1) + po) / n
|
|
627
645
|
this.workersPreCacheHitsTotal += pch
|
|
628
646
|
this.workersPreCacheMissesTotal += pcm
|
|
629
647
|
if (this.worldRendererConfig.debugWasmPerf && n % WorldRendererCommon.PHASE_PERF_LOG_INTERVAL === 0) {
|
|
@@ -641,7 +659,9 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
641
659
|
const cacheTotal = this.workersPreCacheHitsTotal + this.workersPreCacheMissesTotal
|
|
642
660
|
const cacheHitPct = cacheTotal > 0 ? (this.workersPreCacheHitsTotal / cacheTotal) * 100 : 0
|
|
643
661
|
// eslint-disable-next-line no-console
|
|
644
|
-
console.log(
|
|
662
|
+
console.log(
|
|
663
|
+
`[wasm-mesher perf] n=${n} pre=${this.workersPreAverageTime.toFixed(2)}ms (${prePct.toFixed(1)}%) wasm=${this.workersWasmAverageTime.toFixed(2)}ms (${wasmPct.toFixed(1)}%) post=${this.workersPostAverageTime.toFixed(2)}ms (${postPct.toFixed(1)}%) | pre.targetConvert=${this.workersPreTargetConvertAverageTime.toFixed(2)}ms (${tgtPct.toFixed(1)}%) pre.neighborConvert=${this.workersPreNeighborConvertAverageTime.toFixed(2)}ms (${nbrPct.toFixed(1)}%) [n̄=${nbrCnt.toFixed(2)}, per-nbr=${nbrPerAvg.toFixed(2)}ms] pre.typedArrayBuild=${this.workersPreTypedArrayBuildAverageTime.toFixed(2)}ms (${tabPct.toFixed(1)}%) pre.other=${this.workersPreOtherAverageTime.toFixed(2)}ms (${othPct.toFixed(1)}%) | pre.cache hits=${this.workersPreCacheHitsTotal} misses=${this.workersPreCacheMissesTotal} (${cacheHitPct.toFixed(1)}% hit)`
|
|
664
|
+
)
|
|
645
665
|
}
|
|
646
666
|
}
|
|
647
667
|
}
|
|
@@ -679,7 +699,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
679
699
|
this.updateChunksStats()
|
|
680
700
|
}
|
|
681
701
|
|
|
682
|
-
changeHandSwingingState(isAnimationPlaying: boolean, isLeftHand: boolean): void {
|
|
702
|
+
changeHandSwingingState(isAnimationPlaying: boolean, isLeftHand: boolean): void {}
|
|
683
703
|
|
|
684
704
|
abstract handleWorkerMessage(data: WorkerReceive): void
|
|
685
705
|
|
|
@@ -769,7 +789,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
769
789
|
|
|
770
790
|
getMesherConfig(): MesherConfig {
|
|
771
791
|
const timeOfDay = this.timeOfTheDay
|
|
772
|
-
const skyLight =
|
|
792
|
+
const skyLight = timeOfDay < 0 || timeOfDay > 24_000 ? 15 : calculateSkyLightSimple(timeOfDay)
|
|
773
793
|
return {
|
|
774
794
|
version: this.version,
|
|
775
795
|
enableLighting: this.worldRendererConfig.enableLighting,
|
|
@@ -786,7 +806,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
786
806
|
worldMaxY: this.worldMinYRender + this.worldSizeParams.worldHeight,
|
|
787
807
|
disableConversionCache: this.worldRendererConfig.disableMesherConversionCache,
|
|
788
808
|
computeWireframeEdges: this.worldRendererConfig.futuristicReveal === true,
|
|
789
|
-
shaderCubeBlocks: this.isShaderCubeBlocksEnabled()
|
|
809
|
+
shaderCubeBlocks: this.isShaderCubeBlocksEnabled()
|
|
790
810
|
}
|
|
791
811
|
}
|
|
792
812
|
|
|
@@ -810,7 +830,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
810
830
|
latest: resources.blocksAtlasJson
|
|
811
831
|
},
|
|
812
832
|
blockstatesModels,
|
|
813
|
-
config: this.getMesherConfig()
|
|
833
|
+
config: this.getMesherConfig()
|
|
814
834
|
})
|
|
815
835
|
}
|
|
816
836
|
|
|
@@ -868,11 +888,15 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
868
888
|
this.workers[0].postMessage({
|
|
869
889
|
type: 'getHeightmap',
|
|
870
890
|
x,
|
|
871
|
-
z
|
|
891
|
+
z
|
|
872
892
|
})
|
|
873
893
|
}
|
|
874
|
-
this.logWorkerWork(
|
|
894
|
+
this.logWorkerWork(
|
|
895
|
+
() =>
|
|
896
|
+
`-> chunk ${JSON.stringify({ x, z, chunkLength: chunk.length, customBlockModelsLength: customBlockModels ? Object.keys(customBlockModels).length : 0 })}`
|
|
897
|
+
)
|
|
875
898
|
this.mesherLogReader?.chunkReceived(x, z, chunk.length)
|
|
899
|
+
this.cameraCollisionBlockCache.ingestColumn(x, z, chunk)
|
|
876
900
|
const sectionHeight = this.getSectionHeight()
|
|
877
901
|
const CHUNK_SIZE = 16
|
|
878
902
|
|
|
@@ -933,12 +957,15 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
933
957
|
const sectionKey = `${x},${y},${z}`
|
|
934
958
|
const waitingCount = this.sectionsWaiting.get(sectionKey)
|
|
935
959
|
if (waitingCount !== undefined && waitingCount > 0) {
|
|
936
|
-
console.debug(
|
|
960
|
+
console.debug(
|
|
961
|
+
`[removeColumn] clearing non-zero sectionsWaiting for ${sectionKey}: ${waitingCount} (chunk ${x},${z}, viewDistance=${this.viewDistance})`
|
|
962
|
+
)
|
|
937
963
|
}
|
|
938
964
|
this.sectionsWaiting.delete(sectionKey)
|
|
939
965
|
delete this.finishedSections[sectionKey]
|
|
940
966
|
}
|
|
941
967
|
this.highestBlocksByChunks.delete(`${x},${z}`)
|
|
968
|
+
this.cameraCollisionBlockCache.removeColumn(x, z)
|
|
942
969
|
const heightmapKey = `${Math.floor(x / 16)},${Math.floor(z / 16)}`
|
|
943
970
|
delete this.reactiveState.world.heightmaps[heightmapKey]
|
|
944
971
|
|
|
@@ -971,126 +998,208 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
971
998
|
void set()
|
|
972
999
|
}
|
|
973
1000
|
|
|
974
|
-
updateEntity(e: any, isUpdate = false) {
|
|
1001
|
+
updateEntity(e: any, isUpdate = false) {}
|
|
975
1002
|
|
|
976
1003
|
abstract updatePlayerEntity?(e: any): void
|
|
977
1004
|
|
|
978
|
-
lightUpdate(chunkX: number, chunkZ: number) {
|
|
1005
|
+
lightUpdate(chunkX: number, chunkZ: number) {}
|
|
979
1006
|
|
|
980
1007
|
connect(worldView: WorldViewWorker) {
|
|
981
1008
|
const worldEmitter = worldView
|
|
982
1009
|
const signal = this.abortController.signal
|
|
983
1010
|
|
|
984
|
-
bindAbortableListener(
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1011
|
+
bindAbortableListener(
|
|
1012
|
+
worldEmitter,
|
|
1013
|
+
'entity',
|
|
1014
|
+
e => {
|
|
1015
|
+
this.updateEntity(e, false)
|
|
1016
|
+
},
|
|
1017
|
+
signal
|
|
1018
|
+
)
|
|
1019
|
+
bindAbortableListener(
|
|
1020
|
+
worldEmitter,
|
|
1021
|
+
'entityMoved',
|
|
1022
|
+
e => {
|
|
1023
|
+
this.updateEntity(e, true)
|
|
1024
|
+
},
|
|
1025
|
+
signal
|
|
1026
|
+
)
|
|
1027
|
+
bindAbortableListener(
|
|
1028
|
+
worldEmitter,
|
|
1029
|
+
'playerEntity',
|
|
1030
|
+
e => {
|
|
1031
|
+
this.updatePlayerEntity?.(e)
|
|
1032
|
+
},
|
|
1033
|
+
signal
|
|
1034
|
+
)
|
|
993
1035
|
|
|
994
1036
|
let currentLoadChunkBatch = null as {
|
|
995
1037
|
timeout
|
|
996
1038
|
data
|
|
997
1039
|
} | null
|
|
998
|
-
bindAbortableListener(
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1040
|
+
bindAbortableListener(
|
|
1041
|
+
worldEmitter,
|
|
1042
|
+
'loadChunk',
|
|
1043
|
+
({ x, z, chunk, worldConfig, isLightUpdate }) => {
|
|
1044
|
+
this.worldSizeParams = worldConfig
|
|
1045
|
+
this.cameraCollisionBlockCache.setWorldBounds(worldConfig.minY, worldConfig.worldHeight)
|
|
1046
|
+
this.queuedChunks.add(`${x},${z}`)
|
|
1047
|
+
const args = [x, z, chunk, isLightUpdate]
|
|
1048
|
+
if (!currentLoadChunkBatch) {
|
|
1049
|
+
// add a setting to use debounce instead
|
|
1050
|
+
currentLoadChunkBatch = {
|
|
1051
|
+
data: [],
|
|
1052
|
+
timeout: setTimeout(() => {
|
|
1053
|
+
for (const args of currentLoadChunkBatch!.data) {
|
|
1054
|
+
this.queuedChunks.delete(`${args[0]},${args[1]}`)
|
|
1055
|
+
this.addColumn(...(args as Parameters<typeof this.addColumn>))
|
|
1056
|
+
}
|
|
1057
|
+
for (const fn of this.queuedFunctions) {
|
|
1058
|
+
fn()
|
|
1059
|
+
}
|
|
1060
|
+
this.queuedFunctions = []
|
|
1061
|
+
currentLoadChunkBatch = null
|
|
1062
|
+
}, this.worldRendererConfig.addChunksBatchWaitTime)
|
|
1063
|
+
}
|
|
1017
1064
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1065
|
+
currentLoadChunkBatch.data.push(args)
|
|
1066
|
+
},
|
|
1067
|
+
signal
|
|
1068
|
+
)
|
|
1021
1069
|
// todo remove and use other architecture instead so data flow is clear
|
|
1022
|
-
bindAbortableListener(
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
bindAbortableListener(
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1070
|
+
bindAbortableListener(
|
|
1071
|
+
worldEmitter,
|
|
1072
|
+
'blockEntities',
|
|
1073
|
+
blockEntities => {
|
|
1074
|
+
this.blockEntities = blockEntities
|
|
1075
|
+
},
|
|
1076
|
+
signal
|
|
1077
|
+
)
|
|
1078
|
+
|
|
1079
|
+
bindAbortableListener(
|
|
1080
|
+
worldEmitter,
|
|
1081
|
+
'unloadChunk',
|
|
1082
|
+
({ x, z }) => {
|
|
1083
|
+
this.removeColumn(x, z)
|
|
1084
|
+
},
|
|
1085
|
+
signal
|
|
1086
|
+
)
|
|
1087
|
+
|
|
1088
|
+
bindAbortableListener(
|
|
1089
|
+
worldEmitter,
|
|
1090
|
+
'blockUpdate',
|
|
1091
|
+
({ pos, stateId }) => {
|
|
1092
|
+
this.setBlockStateId(new Vec3(pos.x, pos.y, pos.z), stateId)
|
|
1093
|
+
},
|
|
1094
|
+
signal
|
|
1095
|
+
)
|
|
1096
|
+
|
|
1097
|
+
bindAbortableListener(
|
|
1098
|
+
worldEmitter,
|
|
1099
|
+
'chunkPosUpdate',
|
|
1100
|
+
({ pos }) => {
|
|
1101
|
+
this.updateViewerPosition(pos)
|
|
1102
|
+
},
|
|
1103
|
+
signal
|
|
1104
|
+
)
|
|
1105
|
+
|
|
1106
|
+
bindAbortableListener(
|
|
1107
|
+
worldEmitter,
|
|
1108
|
+
'end',
|
|
1109
|
+
() => {
|
|
1110
|
+
this.worldStop?.()
|
|
1111
|
+
},
|
|
1112
|
+
signal
|
|
1113
|
+
)
|
|
1114
|
+
|
|
1115
|
+
bindAbortableListener(
|
|
1116
|
+
worldEmitter,
|
|
1117
|
+
'renderDistance',
|
|
1118
|
+
d => {
|
|
1119
|
+
this.viewDistance = d
|
|
1120
|
+
this.chunksLength = d === 0 ? 1 : generateSpiralMatrix(d).length
|
|
1121
|
+
this.allChunksFinished = Object.keys(this.finishedChunks).length === this.chunksLength
|
|
1122
|
+
this.onRenderDistanceChanged?.(d)
|
|
1123
|
+
},
|
|
1124
|
+
signal
|
|
1125
|
+
)
|
|
1126
|
+
|
|
1127
|
+
bindAbortableListener(
|
|
1128
|
+
worldEmitter,
|
|
1129
|
+
'markAsLoaded',
|
|
1130
|
+
({ x, z }) => {
|
|
1131
|
+
this.markAsLoaded(x, z)
|
|
1132
|
+
},
|
|
1133
|
+
signal
|
|
1134
|
+
)
|
|
1135
|
+
|
|
1136
|
+
bindAbortableListener(
|
|
1137
|
+
worldEmitter,
|
|
1138
|
+
'updateLight',
|
|
1139
|
+
({ pos }) => {
|
|
1140
|
+
this.lightUpdate(pos.x, pos.z)
|
|
1141
|
+
},
|
|
1142
|
+
signal
|
|
1143
|
+
)
|
|
1144
|
+
|
|
1145
|
+
bindAbortableListener(
|
|
1146
|
+
worldEmitter,
|
|
1147
|
+
'onWorldSwitch',
|
|
1148
|
+
() => {
|
|
1149
|
+
this.cameraCollisionBlockCache.clear()
|
|
1150
|
+
for (const fn of this.onWorldSwitched) {
|
|
1151
|
+
try {
|
|
1152
|
+
fn()
|
|
1153
|
+
} catch (e) {
|
|
1154
|
+
setTimeout(() => {
|
|
1155
|
+
console.log('[Renderer Backend] Error in onWorldSwitched:')
|
|
1156
|
+
throw e
|
|
1157
|
+
}, 0)
|
|
1158
|
+
}
|
|
1066
1159
|
}
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1160
|
+
},
|
|
1161
|
+
signal
|
|
1162
|
+
)
|
|
1069
1163
|
|
|
1070
|
-
bindAbortableListener(
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1164
|
+
bindAbortableListener(
|
|
1165
|
+
worldEmitter,
|
|
1166
|
+
'time',
|
|
1167
|
+
timeOfDay => {
|
|
1168
|
+
if (!this.worldRendererConfig.dayCycle) {
|
|
1169
|
+
return
|
|
1170
|
+
}
|
|
1171
|
+
this.timeUpdated?.(timeOfDay)
|
|
1075
1172
|
|
|
1076
|
-
|
|
1173
|
+
this.timeOfTheDay = timeOfDay
|
|
1077
1174
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1175
|
+
const skyLight = timeOfDay < 0 || timeOfDay > 24_000 ? 15 : calculateSkyLightSimple(timeOfDay)
|
|
1176
|
+
if (this.lastMesherSkyLight === skyLight) return
|
|
1177
|
+
this.lastMesherSkyLight = skyLight
|
|
1178
|
+
if (this.workers.length > 0) {
|
|
1179
|
+
this.sendWorkers({ config: { skyLight } } as WorkerSend)
|
|
1180
|
+
}
|
|
1181
|
+
this.onDayCycleSkyLightChanged?.(skyLight)
|
|
1182
|
+
},
|
|
1183
|
+
signal
|
|
1184
|
+
)
|
|
1086
1185
|
|
|
1087
|
-
bindAbortableListener(
|
|
1088
|
-
|
|
1089
|
-
|
|
1186
|
+
bindAbortableListener(
|
|
1187
|
+
worldEmitter,
|
|
1188
|
+
'biomeUpdate',
|
|
1189
|
+
({ biome }) => {
|
|
1190
|
+
this.biomeUpdated?.(biome)
|
|
1191
|
+
},
|
|
1192
|
+
signal
|
|
1193
|
+
)
|
|
1090
1194
|
|
|
1091
|
-
bindAbortableListener(
|
|
1092
|
-
|
|
1093
|
-
|
|
1195
|
+
bindAbortableListener(
|
|
1196
|
+
worldEmitter,
|
|
1197
|
+
'biomeReset',
|
|
1198
|
+
() => {
|
|
1199
|
+
this.biomeReset?.()
|
|
1200
|
+
},
|
|
1201
|
+
signal
|
|
1202
|
+
)
|
|
1094
1203
|
}
|
|
1095
1204
|
|
|
1096
1205
|
setBlockStateIdInner(pos: Vec3, stateId: number | undefined, needAoRecalculation = true) {
|
|
@@ -1118,13 +1227,19 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
1118
1227
|
if (!this.worldRendererConfig.wasmMesher) {
|
|
1119
1228
|
const existing = this.heightmapDebounceTimers.get(chunkKey2)
|
|
1120
1229
|
if (existing) clearTimeout(existing)
|
|
1121
|
-
this.heightmapDebounceTimers.set(
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1230
|
+
this.heightmapDebounceTimers.set(
|
|
1231
|
+
chunkKey2,
|
|
1232
|
+
setTimeout(() => {
|
|
1233
|
+
this.heightmapDebounceTimers.delete(chunkKey2)
|
|
1234
|
+
this.workers[0]?.postMessage({ type: 'getHeightmap', x: chunkCornerX, z: chunkCornerZ })
|
|
1235
|
+
}, 100)
|
|
1236
|
+
)
|
|
1125
1237
|
}
|
|
1126
1238
|
}
|
|
1127
1239
|
this.logWorkerWork(`-> blockUpdate ${JSON.stringify({ pos, stateId, customBlockModels })}`)
|
|
1240
|
+
if (stateId !== undefined) {
|
|
1241
|
+
this.cameraCollisionBlockCache.setBlockStateId(pos.x, pos.y, pos.z, stateId)
|
|
1242
|
+
}
|
|
1128
1243
|
this.setSectionDirty(pos, true, true)
|
|
1129
1244
|
if (this.neighborChunkUpdates) {
|
|
1130
1245
|
const CHUNK_SIZE = 16
|
|
@@ -1132,7 +1247,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
1132
1247
|
if ((pos.x & 15) === 0) this.setSectionDirty(pos.offset(-CHUNK_SIZE, 0, 0), true, true)
|
|
1133
1248
|
if ((pos.x & 15) === 15) this.setSectionDirty(pos.offset(CHUNK_SIZE, 0, 0), true, true)
|
|
1134
1249
|
if ((pos.y & (sectionHeight - 1)) === 0) this.setSectionDirty(pos.offset(0, -sectionHeight, 0), true, true)
|
|
1135
|
-
if ((pos.y & (sectionHeight - 1)) ===
|
|
1250
|
+
if ((pos.y & (sectionHeight - 1)) === sectionHeight - 1) this.setSectionDirty(pos.offset(0, sectionHeight, 0), true, true)
|
|
1136
1251
|
if ((pos.z & 15) === 0) this.setSectionDirty(pos.offset(0, 0, -CHUNK_SIZE), true, true)
|
|
1137
1252
|
if ((pos.z & 15) === 15) this.setSectionDirty(pos.offset(0, 0, CHUNK_SIZE), true, true)
|
|
1138
1253
|
|
|
@@ -1153,10 +1268,14 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
1153
1268
|
if ((pos.z & 15) === 15 && (pos.y & (sectionHeight - 1)) === 0) this.setSectionDirty(pos.offset(0, -sectionHeight, CHUNK_SIZE), true, true)
|
|
1154
1269
|
|
|
1155
1270
|
// x & z neighbors
|
|
1156
|
-
if ((pos.y & (sectionHeight - 1)) === 0 && (pos.x & 15) === 0 && (pos.z & 15) === 0)
|
|
1157
|
-
|
|
1158
|
-
if ((pos.y & (sectionHeight - 1)) === 0 && (pos.x & 15) ===
|
|
1159
|
-
|
|
1271
|
+
if ((pos.y & (sectionHeight - 1)) === 0 && (pos.x & 15) === 0 && (pos.z & 15) === 0)
|
|
1272
|
+
this.setSectionDirty(pos.offset(-CHUNK_SIZE, -sectionHeight, -CHUNK_SIZE), true, true)
|
|
1273
|
+
if ((pos.y & (sectionHeight - 1)) === 0 && (pos.x & 15) === 15 && (pos.z & 15) === 0)
|
|
1274
|
+
this.setSectionDirty(pos.offset(CHUNK_SIZE, -sectionHeight, -CHUNK_SIZE), true, true)
|
|
1275
|
+
if ((pos.y & (sectionHeight - 1)) === 0 && (pos.x & 15) === 0 && (pos.z & 15) === 15)
|
|
1276
|
+
this.setSectionDirty(pos.offset(-CHUNK_SIZE, -sectionHeight, CHUNK_SIZE), true, true)
|
|
1277
|
+
if ((pos.y & (sectionHeight - 1)) === 0 && (pos.x & 15) === 15 && (pos.z & 15) === 15)
|
|
1278
|
+
this.setSectionDirty(pos.offset(CHUNK_SIZE, -sectionHeight, CHUNK_SIZE), true, true)
|
|
1160
1279
|
}
|
|
1161
1280
|
}
|
|
1162
1281
|
}
|
|
@@ -1211,13 +1330,15 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
1211
1330
|
async debugGetWorkerCustomBlockModel(pos: Vec3) {
|
|
1212
1331
|
const data = [] as Array<Promise<string>>
|
|
1213
1332
|
for (const worker of this.workers) {
|
|
1214
|
-
data.push(
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1333
|
+
data.push(
|
|
1334
|
+
new Promise(resolve => {
|
|
1335
|
+
worker.addEventListener('message', e => {
|
|
1336
|
+
if (e.data.type === 'customBlockModel') {
|
|
1337
|
+
resolve(e.data.customBlockModel)
|
|
1338
|
+
}
|
|
1339
|
+
})
|
|
1219
1340
|
})
|
|
1220
|
-
|
|
1341
|
+
)
|
|
1221
1342
|
worker.postMessage({
|
|
1222
1343
|
type: 'getCustomBlockModel',
|
|
1223
1344
|
pos
|
|
@@ -1226,7 +1347,8 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
1226
1347
|
return Promise.all(data)
|
|
1227
1348
|
}
|
|
1228
1349
|
|
|
1229
|
-
setSectionDirty(pos: Vec3, value = true, useChangeWorker = false) {
|
|
1350
|
+
setSectionDirty(pos: Vec3, value = true, useChangeWorker = false) {
|
|
1351
|
+
// value false is used for unloading chunks
|
|
1230
1352
|
if (!this.forceCallFromMesherReplayer && this.mesherLogReader) return
|
|
1231
1353
|
|
|
1232
1354
|
if (this.viewDistance === -1) throw new Error('viewDistance not set')
|
|
@@ -1254,30 +1376,36 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
1254
1376
|
|
|
1255
1377
|
// Schedule trailing dispatch after throttle window
|
|
1256
1378
|
if (!this.sectionDirtyTimers.has(key)) {
|
|
1257
|
-
this.sectionDirtyTimers.set(
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
this.
|
|
1264
|
-
|
|
1265
|
-
|
|
1379
|
+
this.sectionDirtyTimers.set(
|
|
1380
|
+
key,
|
|
1381
|
+
setTimeout(() => {
|
|
1382
|
+
const args = this.sectionDirtyPendingArgs.get(key)
|
|
1383
|
+
this.sectionDirtyCount.delete(key)
|
|
1384
|
+
this.sectionDirtyTimers.delete(key)
|
|
1385
|
+
this.sectionDirtyPendingArgs.delete(key)
|
|
1386
|
+
if (args) {
|
|
1387
|
+
this._dispatchDirtyImmediate(args.pos, args.value, args.useChangeWorker)
|
|
1388
|
+
}
|
|
1389
|
+
}, WorldRendererCommon.GEOMETRY_THROTTLE_DELAY)
|
|
1390
|
+
)
|
|
1266
1391
|
}
|
|
1267
1392
|
} else {
|
|
1268
1393
|
// Subsequent requests — throttle: store latest args, existing timer will dispatch
|
|
1269
1394
|
this.sectionDirtyPendingArgs.set(key, { pos, value, useChangeWorker })
|
|
1270
1395
|
|
|
1271
1396
|
if (!this.sectionDirtyTimers.has(key)) {
|
|
1272
|
-
this.sectionDirtyTimers.set(
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
this.
|
|
1279
|
-
|
|
1280
|
-
|
|
1397
|
+
this.sectionDirtyTimers.set(
|
|
1398
|
+
key,
|
|
1399
|
+
setTimeout(() => {
|
|
1400
|
+
const args = this.sectionDirtyPendingArgs.get(key)
|
|
1401
|
+
this.sectionDirtyCount.delete(key)
|
|
1402
|
+
this.sectionDirtyTimers.delete(key)
|
|
1403
|
+
this.sectionDirtyPendingArgs.delete(key)
|
|
1404
|
+
if (args) {
|
|
1405
|
+
this._dispatchDirtyImmediate(args.pos, args.value, args.useChangeWorker)
|
|
1406
|
+
}
|
|
1407
|
+
}, WorldRendererCommon.GEOMETRY_THROTTLE_DELAY)
|
|
1408
|
+
)
|
|
1281
1409
|
}
|
|
1282
1410
|
}
|
|
1283
1411
|
}
|
|
@@ -1302,7 +1430,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
1302
1430
|
y: pos.y,
|
|
1303
1431
|
z: pos.z,
|
|
1304
1432
|
value,
|
|
1305
|
-
config: this.getMesherConfig()
|
|
1433
|
+
config: this.getMesherConfig()
|
|
1306
1434
|
})
|
|
1307
1435
|
} else {
|
|
1308
1436
|
this.toWorkerMessagesQueue[hash] ??= []
|
|
@@ -1312,7 +1440,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
1312
1440
|
y: pos.y,
|
|
1313
1441
|
z: pos.z,
|
|
1314
1442
|
value,
|
|
1315
|
-
config: this.getMesherConfig()
|
|
1443
|
+
config: this.getMesherConfig()
|
|
1316
1444
|
})
|
|
1317
1445
|
this.dispatchMessages()
|
|
1318
1446
|
}
|
|
@@ -1328,7 +1456,9 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
1328
1456
|
const messages = this.toWorkerMessagesQueue[workerIndex]
|
|
1329
1457
|
worker.postMessage(messages)
|
|
1330
1458
|
for (const message of messages) {
|
|
1331
|
-
this.logWorkerWork(
|
|
1459
|
+
this.logWorkerWork(
|
|
1460
|
+
`-> ${workerIndex} dispatchMessages ${message.type} ${JSON.stringify({ x: message.x, y: message.y, z: message.z, value: message.value })}`
|
|
1461
|
+
)
|
|
1332
1462
|
}
|
|
1333
1463
|
}
|
|
1334
1464
|
this.toWorkerMessagesQueue = {}
|
|
@@ -1436,7 +1566,10 @@ export const initMesherWorker = (onGotMessage: (data: any) => void, workerName =
|
|
|
1436
1566
|
worker.onmessage = ({ data }) => {
|
|
1437
1567
|
onGotMessage(data)
|
|
1438
1568
|
}
|
|
1439
|
-
if (worker.on)
|
|
1569
|
+
if (worker.on)
|
|
1570
|
+
worker.on('message', data => {
|
|
1571
|
+
worker.onmessage({ data })
|
|
1572
|
+
})
|
|
1440
1573
|
return worker
|
|
1441
1574
|
}
|
|
1442
1575
|
|
|
@@ -1467,19 +1600,24 @@ export const meshersSendMcDataAwait = (
|
|
|
1467
1600
|
mcDataFull: IndexedData,
|
|
1468
1601
|
timeoutMs = 10_000
|
|
1469
1602
|
): Promise<void> => {
|
|
1470
|
-
return Promise.all(
|
|
1471
|
-
|
|
1472
|
-
worker
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1603
|
+
return Promise.all(
|
|
1604
|
+
workers.map(
|
|
1605
|
+
worker =>
|
|
1606
|
+
new Promise<void>((resolve, reject) => {
|
|
1607
|
+
const timeout = setTimeout(() => {
|
|
1608
|
+
worker.removeEventListener('message', handler as EventListener)
|
|
1609
|
+
reject(new Error(`mcData transfer timeout (${timeoutMs}ms)`))
|
|
1610
|
+
}, timeoutMs)
|
|
1611
|
+
const handler = ({ data }: MessageEvent) => {
|
|
1612
|
+
if (data?.type === 'mcDataApplied') {
|
|
1613
|
+
clearTimeout(timeout)
|
|
1614
|
+
worker.removeEventListener('message', handler as EventListener)
|
|
1615
|
+
resolve()
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
worker.addEventListener('message', handler as EventListener)
|
|
1619
|
+
meshersSendMcData([worker], version, mcDataKeys, mcDataFull)
|
|
1620
|
+
})
|
|
1621
|
+
)
|
|
1622
|
+
).then(() => undefined)
|
|
1485
1623
|
}
|