minecraft-renderer 0.1.35 → 0.1.37

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.
@@ -50,13 +50,15 @@ export class WorldRendererThree extends WorldRendererCommon {
50
50
  cameraSectionPos: Vec3 = new Vec3(0, 0, 0)
51
51
  holdingBlock: IHoldingBlock
52
52
  holdingBlockLeft: IHoldingBlock
53
- realScene = new THREE.Scene()
54
- scene = new THREE.Group()
53
+ scene = new THREE.Scene()
54
+ get realScene() {
55
+ return this.scene
56
+ }
55
57
  ambientLight = new THREE.AmbientLight(0xcc_cc_cc)
56
58
  directionalLight = new THREE.DirectionalLight(0xff_ff_ff, 0.5)
57
59
  entities = new Entities(this, (globalThis as any).mcData)
58
60
  cameraGroupVr?: THREE.Object3D
59
- material = new THREE.MeshLambertMaterial({ vertexColors: true, transparent: true, alphaTest: 0.1 })
61
+ material = new THREE.MeshBasicMaterial({ vertexColors: true, transparent: true, alphaTest: 0.1 })
60
62
  itemsTexture!: THREE.Texture
61
63
  cursorBlock: CursorBlock
62
64
  onRender: Array<(deltaTime: number) => void> = []
@@ -79,6 +81,9 @@ export class WorldRendererThree extends WorldRendererCommon {
79
81
  */
80
82
  camera!: THREE.PerspectiveCamera
81
83
  renderTimeAvg = 0
84
+ private pendingSectionUpdates = new Map<string, { geometry: MesherGeometryOutput, key: string, type: string }>()
85
+ private pendingSectionBufferStartTime: number | null = null
86
+ private static readonly MAX_SECTION_UPDATE_BUFFER_MS = 500
82
87
  // Memory usage tracking (in bytes)
83
88
  get estimatedMemoryUsage() {
84
89
  return this.chunkMeshManager.getEstimatedMemoryUsage().total
@@ -107,7 +112,7 @@ export class WorldRendererThree extends WorldRendererCommon {
107
112
  DEBUG_RAYCAST = false
108
113
  skyboxRenderer: SkyboxRenderer
109
114
  fireworks: FireworksManager
110
- sceneOrigin = new SceneOrigin(this.realScene)
115
+ sceneOrigin = new SceneOrigin(this.scene)
111
116
  /** Camera world position stored in float64 (JS number) for precision */
112
117
  cameraWorldPos = { x: 0, y: 0, z: 0 }
113
118
 
@@ -450,20 +455,19 @@ export class WorldRendererThree extends WorldRendererCommon {
450
455
  this.cameraWorldPos.y = 0
451
456
  this.cameraWorldPos.z = 0
452
457
 
453
- this.realScene.matrixAutoUpdate = false // for perf
454
- this.realScene.background = new THREE.Color(this.initOptions.config.sceneBackground)
455
- this.realScene.add(this.ambientLight)
458
+ this.scene.matrixAutoUpdate = false // for perf
459
+ this.scene.background = new THREE.Color(this.initOptions.config.sceneBackground)
460
+ this.scene.add(this.ambientLight)
456
461
  this.directionalLight.position.set(1, 1, 0.5).normalize()
457
462
  this.directionalLight.castShadow = true
458
- this.realScene.add(this.directionalLight)
463
+ this.scene.add(this.directionalLight)
459
464
 
460
465
  const size = this.renderer.getSize(new THREE.Vector2())
461
466
  this.camera = new THREE.PerspectiveCamera(75, size.x / size.y, 0.1, 1000)
462
467
  this._wrapCameraPositionWithWarning()
463
468
  this.cameraContainer = new THREE.Object3D()
464
469
  this.cameraContainer.add(this.camera)
465
- this.realScene.add(this.cameraContainer)
466
- this.realScene.add(this.scene)
470
+ this.scene.add(this.cameraContainer)
467
471
  }
468
472
 
469
473
  override watchReactivePlayerState() {
@@ -632,6 +636,10 @@ export class WorldRendererThree extends WorldRendererCommon {
632
636
  this.realScene.background = new THREE.Color(color[0], color[1], color[2])
633
637
  }
634
638
 
639
+ changeCardinalLight(cardinalLight: string): void {
640
+ this.worldRendererConfig.cardinalLight = cardinalLight
641
+ }
642
+
635
643
  timeUpdated(newTime: number): void {
636
644
  // Update starfield module with time
637
645
  const starfieldModule = this.getModule<any>('starfield')
@@ -739,13 +747,94 @@ export class WorldRendererThree extends WorldRendererCommon {
739
747
  }
740
748
 
741
749
  finishChunk(chunkKey: string) {
742
- // ChunkMeshManager applies updates immediately, no buffering needed
750
+ // Existing sections are buffered and flushed from applyPendingSectionUpdates().
751
+ }
752
+
753
+ private applyPendingSectionUpdates() {
754
+ if (this.pendingSectionUpdates.size === 0) return
755
+
756
+ const now = performance.now()
757
+ const sinceFirst = now - (this.pendingSectionBufferStartTime ?? now)
758
+
759
+ if (sinceFirst < WorldRendererThree.MAX_SECTION_UPDATE_BUFFER_MS) {
760
+ const sectionHeight = this.getSectionHeight()
761
+ for (const key of this.pendingSectionUpdates.keys()) {
762
+ const [sx, sy, sz] = key.split(',').map(Number)
763
+ const neighborKeys = [
764
+ `${sx - 16},${sy},${sz}`, `${sx + 16},${sy},${sz}`,
765
+ `${sx},${sy - sectionHeight},${sz}`, `${sx},${sy + sectionHeight},${sz}`,
766
+ `${sx},${sy},${sz - 16}`, `${sx},${sy},${sz + 16}`,
767
+ ]
768
+
769
+ for (const neighborKey of neighborKeys) {
770
+ if (
771
+ this.sectionsWaiting.has(neighborKey) &&
772
+ !this.pendingSectionUpdates.has(neighborKey) &&
773
+ this.sectionObjects[neighborKey]
774
+ ) {
775
+ return
776
+ }
777
+ }
778
+ }
779
+ }
780
+
781
+ const updates = [...this.pendingSectionUpdates.values()]
782
+ this.pendingSectionUpdates.clear()
783
+ this.pendingSectionBufferStartTime = null
784
+
785
+ for (const update of updates) {
786
+ const chunkCoords = update.key.split(',')
787
+ const chunkKey = `${chunkCoords[0]},${chunkCoords[2]}`
788
+
789
+ if (!this.loadedChunks[chunkKey] || !this.active) {
790
+ this.chunkMeshManager.releaseSection(update.key)
791
+ continue
792
+ }
793
+
794
+ if (!update.geometry.positions.length) {
795
+ this.chunkMeshManager.releaseSection(update.key)
796
+ continue
797
+ }
798
+
799
+ this.chunkMeshManager.updateSection(update.key, update.geometry)
800
+ this.updatePosDataChunk(update.key)
801
+ }
802
+ }
803
+
804
+ private clearPendingSectionUpdatesForChunk(x: number, z: number) {
805
+ for (const key of [...this.pendingSectionUpdates.keys()]) {
806
+ if (key.startsWith(`${x},`) && key.endsWith(`,${z}`)) {
807
+ this.pendingSectionUpdates.delete(key)
808
+ }
809
+ }
810
+
811
+ if (this.pendingSectionUpdates.size === 0) {
812
+ this.pendingSectionBufferStartTime = null
813
+ }
743
814
  }
744
815
 
745
816
  handleWorkerMessage(data: { geometry: MesherGeometryOutput, key, type }): void {
746
817
  if (data.type === 'geometry') {
747
818
  const chunkCoords = data.key.split(',')
748
- if (!this.loadedChunks[chunkCoords[0] + ',' + chunkCoords[2]] || !data.geometry.positions.length || !this.active) return
819
+ const chunkKey = `${chunkCoords[0]},${chunkCoords[2]}`
820
+ if (!this.loadedChunks[chunkKey] || !this.active) {
821
+ this.pendingSectionUpdates.delete(data.key)
822
+ if (this.pendingSectionUpdates.size === 0) {
823
+ this.pendingSectionBufferStartTime = null
824
+ }
825
+ return
826
+ }
827
+
828
+ if (this.sectionObjects[data.key]) {
829
+ this.pendingSectionUpdates.set(data.key, data)
830
+ this.pendingSectionBufferStartTime ??= performance.now()
831
+ return
832
+ }
833
+
834
+ if (!data.geometry.positions.length) {
835
+ this.chunkMeshManager.releaseSection(data.key)
836
+ return
837
+ }
749
838
  this.chunkMeshManager.updateSection(data.key, data.geometry)
750
839
  this.updatePosDataChunk(data.key)
751
840
  }
@@ -1097,8 +1186,8 @@ export class WorldRendererThree extends WorldRendererCommon {
1097
1186
 
1098
1187
  // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
1099
1188
  const cam = this.cameraGroupVr instanceof THREE.Group ? this.cameraGroupVr.children.find(child => child instanceof THREE.PerspectiveCamera) as THREE.PerspectiveCamera : this.camera
1100
- // ChunkMeshManager applies updates immediately, no pending updates to flush
1101
- this.renderer.render(this.realScene, cam)
1189
+ this.applyPendingSectionUpdates()
1190
+ this.renderer.render(this.scene, cam)
1102
1191
 
1103
1192
  if (
1104
1193
  this.displayOptions.inWorldRenderingConfig.showHand &&
@@ -1245,6 +1334,8 @@ export class WorldRendererThree extends WorldRendererCommon {
1245
1334
  resetWorld() {
1246
1335
  super.resetWorld()
1247
1336
 
1337
+ this.pendingSectionUpdates.clear()
1338
+ this.pendingSectionBufferStartTime = null
1248
1339
  this.chunkMeshManager.dispose()
1249
1340
  this.chunkMeshManager = new ChunkMeshManager(this, this.scene, this.material, this.worldSizeParams.worldHeight, this.viewDistance)
1250
1341
 
@@ -1299,6 +1390,7 @@ export class WorldRendererThree extends WorldRendererCommon {
1299
1390
  super.removeColumn(x, z)
1300
1391
 
1301
1392
  this.cleanChunkTextures(x, z)
1393
+ this.clearPendingSectionUpdatesForChunk(x, z)
1302
1394
  const sectionHeight = this.getSectionHeight()
1303
1395
  const worldMinY = this.worldMinYRender
1304
1396
  for (let y = worldMinY; y < this.worldSizeParams.worldHeight; y += sectionHeight) {
@@ -1329,6 +1421,8 @@ export class WorldRendererThree extends WorldRendererCommon {
1329
1421
  }
1330
1422
 
1331
1423
  destroy(): void {
1424
+ this.pendingSectionUpdates.clear()
1425
+ this.pendingSectionBufferStartTime = null
1332
1426
  this.chunkMeshManager.dispose()
1333
1427
  this.disposeModules()
1334
1428
  this.fireworksLegacy.destroy()