minecraft-renderer 0.1.22 → 0.1.23
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/dist/mesherWasm.js +5 -5
- package/dist/minecraft-renderer.js +15 -15
- package/dist/threeWorker.js +46 -46
- package/package.json +1 -1
- package/src/graphicsBackend/config.ts +5 -1
- package/src/lib/worldrendererCommon.ts +37 -6
- package/src/three/modules/rain.ts +4 -0
- package/src/three/rendererModuleSystem.ts +1 -0
- package/src/three/worldRendererThree.ts +61 -5
- package/wasm/wasm_mesher.d.ts +2 -2
- package/wasm/wasm_mesher.js +7 -4
package/package.json
CHANGED
|
@@ -59,7 +59,11 @@ export const defaultWorldRendererConfig = {
|
|
|
59
59
|
// World settings
|
|
60
60
|
clipWorldBelowY: undefined as undefined | number,
|
|
61
61
|
isPlayground: false,
|
|
62
|
-
instantCameraUpdate: false
|
|
62
|
+
instantCameraUpdate: false,
|
|
63
|
+
isRaining: false,
|
|
64
|
+
|
|
65
|
+
// Module states: 'enabled' = force on, 'disabled' = force off, 'auto' = use autoEnableCheck
|
|
66
|
+
moduleStates: {} as Record<string, 'enabled' | 'disabled' | 'auto'>
|
|
63
67
|
}
|
|
64
68
|
|
|
65
69
|
export type WorldRendererConfig = typeof defaultWorldRendererConfig
|
|
@@ -5,7 +5,7 @@ import { Vec3 } from 'vec3'
|
|
|
5
5
|
import TypedEmitter from 'typed-emitter'
|
|
6
6
|
import { WorldBlockProvider } from 'mc-assets/dist/worldBlockProvider'
|
|
7
7
|
import { subscribeKey } from 'valtio/utils'
|
|
8
|
-
import { proxy } from 'valtio'
|
|
8
|
+
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'
|
|
@@ -106,6 +106,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
106
106
|
debugStopGeometryUpdate = false
|
|
107
107
|
|
|
108
108
|
protocolCustomBlocks = new Map<string, CustomBlockModels>()
|
|
109
|
+
private heightmapDebounceTimers = new Map<string, ReturnType<typeof setTimeout>>()
|
|
109
110
|
|
|
110
111
|
blockStateModelInfo = new Map<string, BlockStateModelInfo>()
|
|
111
112
|
|
|
@@ -115,6 +116,11 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
115
116
|
|
|
116
117
|
abstract changeBackgroundColor(color: [number, number, number]): void
|
|
117
118
|
|
|
119
|
+
/** Override in subclass to check if any enabled module requires heightmap data */
|
|
120
|
+
protected anyModuleRequiresHeightmap(): boolean {
|
|
121
|
+
return false
|
|
122
|
+
}
|
|
123
|
+
|
|
118
124
|
worldRendererConfig: WorldRendererConfig
|
|
119
125
|
playerStateReactive: PlayerStateReactive
|
|
120
126
|
playerStateUtils: PlayerStateUtils
|
|
@@ -279,7 +285,11 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
279
285
|
|
|
280
286
|
onReactiveConfigUpdated<T extends keyof typeof this.worldRendererConfig>(key: T, callback: (value: typeof this.worldRendererConfig[T]) => void) {
|
|
281
287
|
callback(this.worldRendererConfig[key])
|
|
282
|
-
|
|
288
|
+
if ((key as any) === '*') {
|
|
289
|
+
subscribe(this.worldRendererConfig, callback as any)
|
|
290
|
+
} else {
|
|
291
|
+
subscribeKey(this.worldRendererConfig, key, callback)
|
|
292
|
+
}
|
|
283
293
|
}
|
|
284
294
|
|
|
285
295
|
onReactiveDebugUpdated<T extends keyof typeof this.reactiveDebugParams>(key: T, callback: (value: typeof this.reactiveDebugParams[T]) => void) {
|
|
@@ -665,6 +675,13 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
665
675
|
|
|
666
676
|
removeColumn(x, z) {
|
|
667
677
|
delete this.loadedChunks[`${x},${z}`]
|
|
678
|
+
// Cancel any pending heightmap debounce for this chunk
|
|
679
|
+
const debounceKey = `${x},${z}`
|
|
680
|
+
const pendingTimer = this.heightmapDebounceTimers.get(debounceKey)
|
|
681
|
+
if (pendingTimer) {
|
|
682
|
+
clearTimeout(pendingTimer)
|
|
683
|
+
this.heightmapDebounceTimers.delete(debounceKey)
|
|
684
|
+
}
|
|
668
685
|
for (const worker of this.workers) {
|
|
669
686
|
worker.postMessage({ type: 'unloadChunk', x, z })
|
|
670
687
|
}
|
|
@@ -849,10 +866,18 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
849
866
|
customBlockModels
|
|
850
867
|
})
|
|
851
868
|
}
|
|
852
|
-
// Re-request heightmap for the affected chunk after block change
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
869
|
+
// Re-request heightmap for the affected chunk after block change (debounced)
|
|
870
|
+
if (this.anyModuleRequiresHeightmap()) {
|
|
871
|
+
const chunkCornerX = Math.floor(pos.x / CHUNK_SIZE) * CHUNK_SIZE
|
|
872
|
+
const chunkCornerZ = Math.floor(pos.z / CHUNK_SIZE) * CHUNK_SIZE
|
|
873
|
+
const chunkKey2 = `${chunkCornerX},${chunkCornerZ}`
|
|
874
|
+
const existing = this.heightmapDebounceTimers.get(chunkKey2)
|
|
875
|
+
if (existing) clearTimeout(existing)
|
|
876
|
+
this.heightmapDebounceTimers.set(chunkKey2, setTimeout(() => {
|
|
877
|
+
this.heightmapDebounceTimers.delete(chunkKey2)
|
|
878
|
+
this.workers[0]?.postMessage({ type: 'getHeightmap', x: chunkCornerX, z: chunkCornerZ })
|
|
879
|
+
}, 100))
|
|
880
|
+
}
|
|
856
881
|
this.logWorkerWork(`-> blockUpdate ${JSON.stringify({ pos, stateId, customBlockModels })}`)
|
|
857
882
|
this.setSectionDirty(pos, true, true)
|
|
858
883
|
if (this.neighborChunkUpdates) {
|
|
@@ -1023,6 +1048,12 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
1023
1048
|
}
|
|
1024
1049
|
|
|
1025
1050
|
destroy() {
|
|
1051
|
+
// Cancel all pending heightmap debounce timers
|
|
1052
|
+
for (const timer of this.heightmapDebounceTimers.values()) {
|
|
1053
|
+
clearTimeout(timer)
|
|
1054
|
+
}
|
|
1055
|
+
this.heightmapDebounceTimers.clear()
|
|
1056
|
+
|
|
1026
1057
|
// Stop all workers
|
|
1027
1058
|
for (const worker of this.workers) {
|
|
1028
1059
|
worker.terminate()
|
|
@@ -48,6 +48,10 @@ export class RainModule implements RendererModuleController {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
autoEnableCheck(): boolean {
|
|
52
|
+
return this.worldRenderer.worldRendererConfig.isRaining === true
|
|
53
|
+
}
|
|
54
|
+
|
|
51
55
|
render?: () => void = () => {
|
|
52
56
|
if (!this.enabled || !this.instancedMesh) return
|
|
53
57
|
|
|
@@ -297,11 +297,8 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
297
297
|
* Initialize all registered modules
|
|
298
298
|
*/
|
|
299
299
|
private initializeModules(): void {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
this.enableModule(id)
|
|
303
|
-
}
|
|
304
|
-
}
|
|
300
|
+
// Use updateModulesFromConfig to handle initial state correctly (respects force states and auto-enable)
|
|
301
|
+
this.updateModulesFromConfig()
|
|
305
302
|
}
|
|
306
303
|
|
|
307
304
|
/**
|
|
@@ -311,6 +308,10 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
311
308
|
return this.modules[moduleId]?.controller as T | undefined
|
|
312
309
|
}
|
|
313
310
|
|
|
311
|
+
protected override anyModuleRequiresHeightmap(): boolean {
|
|
312
|
+
return Object.values(this.modules).some(m => m.enabled && m.manifest.requiresHeightmap)
|
|
313
|
+
}
|
|
314
|
+
|
|
314
315
|
get cameraObject() {
|
|
315
316
|
return this.cameraGroupVr ?? this.cameraContainer
|
|
316
317
|
}
|
|
@@ -408,6 +409,61 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
408
409
|
this.onReactiveConfigUpdated('defaultSkybox', (value) => {
|
|
409
410
|
this.skyboxRenderer.updateDefaultSkybox(value)
|
|
410
411
|
})
|
|
412
|
+
|
|
413
|
+
// Watch for config changes that affect modules
|
|
414
|
+
this.onReactiveConfigUpdated('*' as any, () => {
|
|
415
|
+
this.updateModulesFromConfig()
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
// Initial update
|
|
419
|
+
this.updateModulesFromConfig()
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Update module states based on config (force states and auto-enable checks)
|
|
424
|
+
*/
|
|
425
|
+
private updateModulesFromConfig(): void {
|
|
426
|
+
const { moduleStates } = this.worldRendererConfig
|
|
427
|
+
|
|
428
|
+
for (const [moduleId, module] of Object.entries(this.modules)) {
|
|
429
|
+
const forceState = moduleStates[moduleId]
|
|
430
|
+
|
|
431
|
+
// Check force states first
|
|
432
|
+
if (forceState === 'enabled') {
|
|
433
|
+
if (!module.enabled) {
|
|
434
|
+
this.toggleModule(moduleId, true)
|
|
435
|
+
}
|
|
436
|
+
continue
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (forceState === 'disabled') {
|
|
440
|
+
if (module.enabled && !module.manifest.cannotBeDisabled) {
|
|
441
|
+
this.toggleModule(moduleId, false)
|
|
442
|
+
}
|
|
443
|
+
continue
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Auto mode: use autoEnableCheck if available, otherwise use enabledDefault
|
|
447
|
+
if (forceState === 'auto' || forceState === undefined) {
|
|
448
|
+
if (module.controller.autoEnableCheck) {
|
|
449
|
+
const shouldEnable = module.controller.autoEnableCheck()
|
|
450
|
+
|
|
451
|
+
if (shouldEnable && !module.enabled) {
|
|
452
|
+
this.toggleModule(moduleId, true)
|
|
453
|
+
} else if (!shouldEnable && module.enabled && !module.manifest.cannotBeDisabled) {
|
|
454
|
+
this.toggleModule(moduleId, false)
|
|
455
|
+
}
|
|
456
|
+
} else {
|
|
457
|
+
// No autoEnableCheck: use enabledDefault
|
|
458
|
+
const shouldEnable = module.manifest.enabledDefault ?? false
|
|
459
|
+
if (shouldEnable && !module.enabled) {
|
|
460
|
+
this.toggleModule(moduleId, true)
|
|
461
|
+
} else if (!shouldEnable && module.enabled && !module.manifest.cannotBeDisabled) {
|
|
462
|
+
this.toggleModule(moduleId, false)
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
411
467
|
}
|
|
412
468
|
|
|
413
469
|
changeHandSwingingState(isAnimationPlaying: boolean, isLeft = false) {
|
package/wasm/wasm_mesher.d.ts
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* Input: Serialized chunk data as TypedArrays
|
|
8
8
|
* Output: Geometry data (positions, normals, colors, uvs, indices)
|
|
9
9
|
*/
|
|
10
|
-
export function generate_geometry(section_x: number, section_y: number, section_z: number, section_height: number, world_min_y: number, world_max_y: number, block_states: Uint16Array, block_light: Uint8Array, sky_light: Uint8Array, biomes: Uint8Array, invisible_blocks: Uint16Array, transparent_blocks: Uint16Array, no_ao_blocks: Uint16Array, cull_identical_blocks: Uint16Array, occluding_blocks: Uint16Array, enable_lighting: boolean, smooth_lighting: boolean, sky_light_value: number): any;
|
|
10
|
+
export function generate_geometry(section_x: number, section_y: number, section_z: number, section_height: number, world_min_y: number, world_max_y: number, section_data_start_y: number, block_states: Uint16Array, block_light: Uint8Array, sky_light: Uint8Array, biomes: Uint8Array, invisible_blocks: Uint16Array, transparent_blocks: Uint16Array, no_ao_blocks: Uint16Array, cull_identical_blocks: Uint16Array, occluding_blocks: Uint16Array, enable_lighting: boolean, smooth_lighting: boolean, sky_light_value: number): any;
|
|
11
11
|
|
|
12
|
-
export function generate_geometry_multi(section_x: number, section_y: number, section_z: number, section_height: number, world_min_y: number, world_max_y: number, chunk_xs: Int32Array, chunk_zs: Int32Array, block_states: Uint16Array, block_light: Uint8Array, sky_light: Uint8Array, biomes: Uint8Array, invisible_blocks: Uint16Array, transparent_blocks: Uint16Array, no_ao_blocks: Uint16Array, cull_identical_blocks: Uint16Array, occluding_blocks: Uint16Array, enable_lighting: boolean, smooth_lighting: boolean, sky_light_value: number): any;
|
|
12
|
+
export function generate_geometry_multi(section_x: number, section_y: number, section_z: number, section_height: number, world_min_y: number, world_max_y: number, section_data_start_y: number, chunk_xs: Int32Array, chunk_zs: Int32Array, block_states: Uint16Array, block_light: Uint8Array, sky_light: Uint8Array, biomes: Uint8Array, invisible_blocks: Uint16Array, transparent_blocks: Uint16Array, no_ao_blocks: Uint16Array, cull_identical_blocks: Uint16Array, occluding_blocks: Uint16Array, enable_lighting: boolean, smooth_lighting: boolean, sky_light_value: number): any;
|
|
13
13
|
|
|
14
14
|
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
15
15
|
|
package/wasm/wasm_mesher.js
CHANGED
|
@@ -227,6 +227,7 @@ let WASM_VECTOR_LEN = 0;
|
|
|
227
227
|
* @param {number} section_height
|
|
228
228
|
* @param {number} world_min_y
|
|
229
229
|
* @param {number} world_max_y
|
|
230
|
+
* @param {number} section_data_start_y
|
|
230
231
|
* @param {Uint16Array} block_states
|
|
231
232
|
* @param {Uint8Array} block_light
|
|
232
233
|
* @param {Uint8Array} sky_light
|
|
@@ -241,13 +242,14 @@ let WASM_VECTOR_LEN = 0;
|
|
|
241
242
|
* @param {number} sky_light_value
|
|
242
243
|
* @returns {any}
|
|
243
244
|
*/
|
|
244
|
-
export function generate_geometry(section_x, section_y, section_z, section_height, world_min_y, world_max_y, block_states, block_light, sky_light, biomes, invisible_blocks, transparent_blocks, no_ao_blocks, cull_identical_blocks, occluding_blocks, enable_lighting, smooth_lighting, sky_light_value) {
|
|
245
|
+
export function generate_geometry(section_x, section_y, section_z, section_height, world_min_y, world_max_y, section_data_start_y, block_states, block_light, sky_light, biomes, invisible_blocks, transparent_blocks, no_ao_blocks, cull_identical_blocks, occluding_blocks, enable_lighting, smooth_lighting, sky_light_value) {
|
|
245
246
|
_assertNum(section_x);
|
|
246
247
|
_assertNum(section_y);
|
|
247
248
|
_assertNum(section_z);
|
|
248
249
|
_assertNum(section_height);
|
|
249
250
|
_assertNum(world_min_y);
|
|
250
251
|
_assertNum(world_max_y);
|
|
252
|
+
_assertNum(section_data_start_y);
|
|
251
253
|
const ptr0 = passArray16ToWasm0(block_states, wasm.__wbindgen_malloc);
|
|
252
254
|
const len0 = WASM_VECTOR_LEN;
|
|
253
255
|
const ptr1 = passArray8ToWasm0(block_light, wasm.__wbindgen_malloc);
|
|
@@ -269,7 +271,7 @@ export function generate_geometry(section_x, section_y, section_z, section_heigh
|
|
|
269
271
|
_assertBoolean(enable_lighting);
|
|
270
272
|
_assertBoolean(smooth_lighting);
|
|
271
273
|
_assertNum(sky_light_value);
|
|
272
|
-
const ret = wasm.generate_geometry(section_x, section_y, section_z, section_height, world_min_y, world_max_y, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6, ptr7, len7, ptr8, len8, enable_lighting, smooth_lighting, sky_light_value);
|
|
274
|
+
const ret = wasm.generate_geometry(section_x, section_y, section_z, section_height, world_min_y, world_max_y, section_data_start_y, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6, ptr7, len7, ptr8, len8, enable_lighting, smooth_lighting, sky_light_value);
|
|
273
275
|
return ret;
|
|
274
276
|
}
|
|
275
277
|
|
|
@@ -296,13 +298,14 @@ export function generate_geometry(section_x, section_y, section_z, section_heigh
|
|
|
296
298
|
* @param {number} sky_light_value
|
|
297
299
|
* @returns {any}
|
|
298
300
|
*/
|
|
299
|
-
export function generate_geometry_multi(section_x, section_y, section_z, section_height, world_min_y, world_max_y, chunk_xs, chunk_zs, block_states, block_light, sky_light, biomes, invisible_blocks, transparent_blocks, no_ao_blocks, cull_identical_blocks, occluding_blocks, enable_lighting, smooth_lighting, sky_light_value) {
|
|
301
|
+
export function generate_geometry_multi(section_x, section_y, section_z, section_height, world_min_y, world_max_y, section_data_start_y, chunk_xs, chunk_zs, block_states, block_light, sky_light, biomes, invisible_blocks, transparent_blocks, no_ao_blocks, cull_identical_blocks, occluding_blocks, enable_lighting, smooth_lighting, sky_light_value) {
|
|
300
302
|
_assertNum(section_x);
|
|
301
303
|
_assertNum(section_y);
|
|
302
304
|
_assertNum(section_z);
|
|
303
305
|
_assertNum(section_height);
|
|
304
306
|
_assertNum(world_min_y);
|
|
305
307
|
_assertNum(world_max_y);
|
|
308
|
+
_assertNum(section_data_start_y);
|
|
306
309
|
const ptr0 = passArray32ToWasm0(chunk_xs, wasm.__wbindgen_malloc);
|
|
307
310
|
const len0 = WASM_VECTOR_LEN;
|
|
308
311
|
const ptr1 = passArray32ToWasm0(chunk_zs, wasm.__wbindgen_malloc);
|
|
@@ -328,7 +331,7 @@ export function generate_geometry_multi(section_x, section_y, section_z, section
|
|
|
328
331
|
_assertBoolean(enable_lighting);
|
|
329
332
|
_assertBoolean(smooth_lighting);
|
|
330
333
|
_assertNum(sky_light_value);
|
|
331
|
-
const ret = wasm.generate_geometry_multi(section_x, section_y, section_z, section_height, world_min_y, world_max_y, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6, ptr7, len7, ptr8, len8, ptr9, len9, ptr10, len10, enable_lighting, smooth_lighting, sky_light_value);
|
|
334
|
+
const ret = wasm.generate_geometry_multi(section_x, section_y, section_z, section_height, world_min_y, world_max_y, section_data_start_y, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6, ptr7, len7, ptr8, len8, ptr9, len9, ptr10, len10, enable_lighting, smooth_lighting, sky_light_value);
|
|
332
335
|
return ret;
|
|
333
336
|
}
|
|
334
337
|
|