minecraft-renderer 0.1.34 → 0.1.36

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.
@@ -149,43 +149,49 @@ const addNametag = (entity, options: { fontFamily: string }, mesh, version: stri
149
149
  c.removeFromParent()
150
150
  }
151
151
  }
152
- if (entity.username !== undefined && !entity.username.startsWith('EMPTY')) {
153
- const canvas = getUsernameTexture(entity, options, version)
154
- if (!canvas) return
155
- const tex = new THREE.Texture(canvas)
156
- tex.needsUpdate = true
157
- let nameTag: THREE.Object3D
158
- if (entity.nameTagFixed) {
159
- const geometry = new THREE.PlaneGeometry()
160
- const material = new THREE.MeshBasicMaterial({ map: tex })
161
- material.transparent = true
162
- nameTag = new THREE.Mesh(geometry, material)
163
- nameTag.rotation.set(entity.pitch, THREE.MathUtils.degToRad(entity.yaw + 180), 0)
164
- nameTag.position.y += entity.height + 0.3
165
- } else {
166
- const spriteMat = new THREE.SpriteMaterial({ map: tex })
167
- nameTag = new THREE.Sprite(spriteMat)
168
- nameTag.position.y += entity.height + 0.6
169
- }
170
- nameTag.renderOrder = 1000
171
- nameTag.scale.set(canvas.width * 0.005, canvas.height * 0.005, 1)
172
- if (entity.nameTagRotationRight) {
173
- nameTag.applyQuaternion(entity.nameTagRotationRight)
174
- }
175
- if (entity.nameTagScale) {
176
- nameTag.scale.multiply(entity.nameTagScale)
177
- }
178
- if (entity.nameTagRotationLeft) {
179
- nameTag.applyQuaternion(entity.nameTagRotationLeft)
180
- }
181
- if (entity.nameTagTranslation) {
182
- nameTag.position.add(entity.nameTagTranslation)
183
- }
184
- nameTag.name = 'nametag'
185
-
186
- mesh.add(nameTag)
187
- return nameTag
152
+ if (entity.username === undefined || entity.username === null) return
153
+
154
+ const plainUsername =
155
+ typeof entity.username === 'string'
156
+ ? entity.username
157
+ : new (PrismarineChatLoader(version))(entity.username).toString()
158
+ if (plainUsername.startsWith('EMPTY')) return
159
+
160
+ const canvas = getUsernameTexture(entity, options, version)
161
+ if (!canvas) return
162
+ const tex = new THREE.Texture(canvas)
163
+ tex.needsUpdate = true
164
+ let nameTag: THREE.Object3D
165
+ if (entity.nameTagFixed) {
166
+ const geometry = new THREE.PlaneGeometry()
167
+ const material = new THREE.MeshBasicMaterial({ map: tex })
168
+ material.transparent = true
169
+ nameTag = new THREE.Mesh(geometry, material)
170
+ nameTag.rotation.set(entity.pitch, THREE.MathUtils.degToRad(entity.yaw + 180), 0)
171
+ nameTag.position.y += entity.height + 0.3
172
+ } else {
173
+ const spriteMat = new THREE.SpriteMaterial({ map: tex })
174
+ nameTag = new THREE.Sprite(spriteMat)
175
+ nameTag.position.y += entity.height + 0.6
176
+ }
177
+ nameTag.renderOrder = 1000
178
+ nameTag.scale.set(canvas.width * 0.005, canvas.height * 0.005, 1)
179
+ if (entity.nameTagRotationRight) {
180
+ nameTag.applyQuaternion(entity.nameTagRotationRight)
181
+ }
182
+ if (entity.nameTagScale) {
183
+ nameTag.scale.multiply(entity.nameTagScale)
188
184
  }
185
+ if (entity.nameTagRotationLeft) {
186
+ nameTag.applyQuaternion(entity.nameTagRotationLeft)
187
+ }
188
+ if (entity.nameTagTranslation) {
189
+ nameTag.position.add(entity.nameTagTranslation)
190
+ }
191
+ nameTag.name = 'nametag'
192
+
193
+ mesh.add(nameTag)
194
+ return nameTag
189
195
  }
190
196
 
191
197
  // todo cleanup
@@ -225,7 +225,7 @@ export const createGraphicsBackendBase = () => {
225
225
  },
226
226
  get left() {
227
227
  return {
228
- 'Geo Memory': worldRenderer?.worldBlockGeometry.getEstimatedMemoryUsage().readable ?? '-'
228
+ 'Geo Memory': worldRenderer?.chunkMeshManager.getEstimatedMemoryUsage().total ?? '-'
229
229
  }
230
230
  },
231
231
  }),
@@ -58,11 +58,9 @@ export class SciFiWorldRevealModule implements RendererModuleController {
58
58
  // Store original methods for patching
59
59
  private originalFinishChunk: ((chunkKey: string) => void) | null = null
60
60
  private originalDestroy: (() => void) | null = null
61
- private originalSceneAdd: ((...object: THREE.Object3D[]) => THREE.Scene) | null = null
61
+ private originalSceneAdd: ((...object: THREE.Object3D[]) => THREE.Group) | null = null
62
62
  private originalHandleWorkerMessage: ((data: { geometry: MesherGeometryOutput; key: string; type: string }) => void) | null = null
63
63
 
64
- private originalWbgHandle: ((data: any) => void) | null = null
65
-
66
64
  private configEnabled = true
67
65
 
68
66
  constructor(private readonly worldRenderer: WorldRendererThree) {
@@ -146,12 +144,10 @@ export class SciFiWorldRevealModule implements RendererModuleController {
146
144
  this.originalDestroy!()
147
145
  }
148
146
 
149
- // Patch handleWorkerMessage
150
- const wbg = wr.worldBlockGeometry
151
- this.originalWbgHandle = wbg.handleWorkerGeometryMessage.bind(wbg)
152
-
153
- wbg.handleWorkerGeometryMessage = (data: any) => {
154
- const result = this.originalWbgHandle!(data)
147
+ // Patch handleWorkerMessage to intercept geometry
148
+ this.originalHandleWorkerMessage = wr.handleWorkerMessage.bind(wr)
149
+ wr.handleWorkerMessage = (data: any) => {
150
+ this.originalHandleWorkerMessage!(data)
155
151
 
156
152
  if (this.enabled && data?.type === 'geometry') {
157
153
  Promise.resolve().then(() => {
@@ -162,14 +158,12 @@ export class SciFiWorldRevealModule implements RendererModuleController {
162
158
  }
163
159
  })
164
160
  }
165
-
166
- return result
167
161
  }
168
162
 
169
163
 
170
164
  // Patch scene.add to intercept mesh additions
171
165
  this.originalSceneAdd = wr.scene.add.bind(wr.scene)
172
- wr.scene.add = (...objects: THREE.Object3D[]): THREE.Scene => {
166
+ wr.scene.add = (...objects: THREE.Object3D[]): THREE.Group => {
173
167
  // Call original add first
174
168
  const result = this.originalSceneAdd!(...objects)
175
169
 
@@ -208,11 +202,6 @@ export class SciFiWorldRevealModule implements RendererModuleController {
208
202
  this.originalSceneAdd = null
209
203
  }
210
204
 
211
- if (this.originalWbgHandle) {
212
- wr.worldBlockGeometry.handleWorkerGeometryMessage = this.originalWbgHandle as any
213
- this.originalWbgHandle = null
214
- }
215
-
216
205
  if (this.onWorldSwitchedCb) {
217
206
  const i = wr.onWorldSwitched.indexOf(this.onWorldSwitchedCb)
218
207
  if (i !== -1) wr.onWorldSwitched.splice(i, 1)
@@ -249,7 +238,7 @@ export class SciFiWorldRevealModule implements RendererModuleController {
249
238
  let current: THREE.Object3D | null = mesh
250
239
  while (current) {
251
240
  const { sectionKey } = (current as any)
252
- if (sectionKey && this.worldRenderer.worldBlockGeometry.sectionObjects[sectionKey] === current) {
241
+ if (sectionKey && this.worldRenderer.chunkMeshManager.sectionObjects[sectionKey] === current) {
253
242
  return sectionKey
254
243
  }
255
244
  current = current.parent
@@ -270,7 +259,7 @@ export class SciFiWorldRevealModule implements RendererModuleController {
270
259
  const derivedKey = `${sectionX},${sectionY},${sectionZ}`
271
260
 
272
261
  // Verify this key exists in sectionObjects
273
- if (this.worldRenderer.worldBlockGeometry.sectionObjects[derivedKey]) {
262
+ if (this.worldRenderer.chunkMeshManager.sectionObjects[derivedKey]) {
274
263
  return derivedKey
275
264
  }
276
265
 
@@ -281,7 +270,7 @@ export class SciFiWorldRevealModule implements RendererModuleController {
281
270
  * Get the scene from world renderer
282
271
  */
283
272
  private get scene(): THREE.Scene {
284
- return this.worldRenderer.scene
273
+ return this.worldRenderer.realScene
285
274
  }
286
275
 
287
276
  /**
@@ -295,7 +284,7 @@ export class SciFiWorldRevealModule implements RendererModuleController {
295
284
  * Get original mesh for a section key
296
285
  */
297
286
  private getOriginalMesh(key: string): THREE.Mesh | null {
298
- const sectionObject = this.worldRenderer.worldBlockGeometry.sectionObjects[key]
287
+ const sectionObject = this.worldRenderer.chunkMeshManager.sectionObjects[key]
299
288
  if (!sectionObject) return null
300
289
  return sectionObject.children.find(child => child.name === 'mesh') as THREE.Mesh | null
301
290
  }
@@ -214,7 +214,7 @@ export class PanoramaRenderer {
214
214
  }
215
215
  )
216
216
  if (this.worldRenderer instanceof WorldRendererThree) {
217
- this.scene = this.worldRenderer.scene
217
+ this.scene = this.worldRenderer.realScene
218
218
  }
219
219
  void worldView.init(initPos)
220
220
 
@@ -13,7 +13,6 @@ import { addNewStat } from '../lib/ui/newStats'
13
13
  import { MesherGeometryOutput } from '../mesher/shared'
14
14
  import { ItemSpecificContextProperties } from '../playerState/types'
15
15
  import { setBlockPosition } from '../mesher/standaloneRenderer'
16
- import { getBannerTexture, createBannerMesh, releaseBannerTexture } from './bannerRenderer'
17
16
  import { getMyHand } from './hand'
18
17
  import { createHoldingBlock } from './holdingBlockFactory'
19
18
  import type { IHoldingBlock } from './holdingBlockTypes'
@@ -34,7 +33,7 @@ import { DEFAULT_TEMPERATURE, SkyboxRenderer } from './skyboxRenderer'
34
33
  import { FireworksManager } from './fireworks'
35
34
  import { SceneOrigin } from './sceneOrigin'
36
35
  import { downloadWorldGeometry } from './worldGeometryExport'
37
- import { WorldBlockGeometry } from './worldBlockGeometry'
36
+ import { ChunkMeshManager } from './chunkMeshManager'
38
37
  import type { RendererModuleManifest, RegisteredModule, RendererModuleController } from './rendererModuleSystem'
39
38
  import { BUILTIN_MODULES } from './modules/index'
40
39
 
@@ -42,21 +41,22 @@ type SectionKey = string
42
41
 
43
42
  export class WorldRendererThree extends WorldRendererCommon {
44
43
  outputFormat = 'threeJs' as const
45
- worldBlockGeometry: WorldBlockGeometry
44
+ chunkMeshManager: ChunkMeshManager
46
45
  get sectionObjects() {
47
- return this.worldBlockGeometry.sectionObjects
46
+ return this.chunkMeshManager.sectionObjects
48
47
  }
49
48
  chunkTextures = new Map<string, { [pos: string]: THREE.Texture }>()
50
49
  signsCache = new Map<string, any>()
51
50
  cameraSectionPos: Vec3 = new Vec3(0, 0, 0)
52
51
  holdingBlock: IHoldingBlock
53
52
  holdingBlockLeft: IHoldingBlock
54
- scene = new THREE.Scene()
53
+ realScene = new THREE.Scene()
54
+ scene = new THREE.Group()
55
55
  ambientLight = new THREE.AmbientLight(0xcc_cc_cc)
56
56
  directionalLight = new THREE.DirectionalLight(0xff_ff_ff, 0.5)
57
57
  entities = new Entities(this, (globalThis as any).mcData)
58
58
  cameraGroupVr?: THREE.Object3D
59
- material = new THREE.MeshLambertMaterial({ vertexColors: true, transparent: true, alphaTest: 0.1 })
59
+ material = new THREE.MeshBasicMaterial({ vertexColors: true, transparent: true, alphaTest: 0.1 })
60
60
  itemsTexture!: THREE.Texture
61
61
  cursorBlock: CursorBlock
62
62
  onRender: Array<(deltaTime: number) => void> = []
@@ -65,7 +65,7 @@ export class WorldRendererThree extends WorldRendererCommon {
65
65
  cameraContainer!: THREE.Object3D
66
66
  media: ThreeJsMedia
67
67
  get waitingChunksToDisplay() {
68
- return this.worldBlockGeometry.waitingChunksToDisplay
68
+ return {} as { [chunkKey: string]: string[] }
69
69
  }
70
70
  waypoints: WaypointsRenderer
71
71
  cinimaticScript: CinimaticScriptRunner
@@ -81,7 +81,7 @@ export class WorldRendererThree extends WorldRendererCommon {
81
81
  renderTimeAvg = 0
82
82
  // Memory usage tracking (in bytes)
83
83
  get estimatedMemoryUsage() {
84
- return this.worldBlockGeometry.estimatedMemoryUsage
84
+ return this.chunkMeshManager.getEstimatedMemoryUsage().total
85
85
  }
86
86
  // Module system
87
87
  private modules = {} as Record<string, RegisteredModule>
@@ -107,7 +107,7 @@ export class WorldRendererThree extends WorldRendererCommon {
107
107
  DEBUG_RAYCAST = false
108
108
  skyboxRenderer: SkyboxRenderer
109
109
  fireworks: FireworksManager
110
- sceneOrigin = new SceneOrigin(this.scene)
110
+ sceneOrigin = new SceneOrigin(this.realScene)
111
111
  /** Camera world position stored in float64 (JS number) for precision */
112
112
  cameraWorldPos = { x: 0, y: 0, z: 0 }
113
113
 
@@ -131,11 +131,11 @@ export class WorldRendererThree extends WorldRendererCommon {
131
131
  private readonly _tpChunkWorldPos = new THREE.Vector3()
132
132
 
133
133
  get tilesRendered() {
134
- return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj as any).tilesCount, 0)
134
+ return this.chunkMeshManager.getTotalTiles()
135
135
  }
136
136
 
137
137
  get blocksRendered() {
138
- return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj as any).blocksCount, 0)
138
+ return this.chunkMeshManager.getTotalBlocks()
139
139
  }
140
140
 
141
141
  constructor(public renderer: THREE.WebGLRenderer, public initOptions: GraphicsInitOptions, public displayOptions: DisplayWorldOptions) {
@@ -145,8 +145,11 @@ export class WorldRendererThree extends WorldRendererCommon {
145
145
  this.renderer = renderer
146
146
  displayOptions.rendererState.renderer = WorldRendererThree.getRendererInfo(renderer) ?? '...'
147
147
 
148
- // Initialize world block geometry handler
149
- this.worldBlockGeometry = new WorldBlockGeometry(this, this.scene, this.material, displayOptions)
148
+ // Initialize chunk mesh manager
149
+ this.chunkMeshManager = new ChunkMeshManager(this, this.scene, this.material, this.worldSizeParams.worldHeight, this.viewDistance)
150
+ this.onRenderDistanceChanged = (viewDistance) => {
151
+ this.chunkMeshManager.updateViewDistance(viewDistance)
152
+ }
150
153
 
151
154
  this.cursorBlock = new CursorBlock(this)
152
155
  this.holdingBlock = createHoldingBlock(this)
@@ -158,7 +161,7 @@ export class WorldRendererThree extends WorldRendererCommon {
158
161
  }
159
162
 
160
163
  // Initialize skybox renderer
161
- this.skyboxRenderer = new SkyboxRenderer(this.scene, false, null)
164
+ this.skyboxRenderer = new SkyboxRenderer(this.realScene, false, null)
162
165
  void this.skyboxRenderer.init()
163
166
 
164
167
  this.addDebugOverlay()
@@ -181,7 +184,7 @@ export class WorldRendererThree extends WorldRendererCommon {
181
184
  fov: this.camera.fov
182
185
  })
183
186
  )
184
- this.fireworks = new FireworksManager(this.scene, this.sceneOrigin)
187
+ this.fireworks = new FireworksManager(this.realScene, this.sceneOrigin)
185
188
 
186
189
  // this.fountain = new Fountain(this.scene, this.scene, {
187
190
  // position: new THREE.Vector3(0, 10, 0),
@@ -447,19 +450,20 @@ export class WorldRendererThree extends WorldRendererCommon {
447
450
  this.cameraWorldPos.y = 0
448
451
  this.cameraWorldPos.z = 0
449
452
 
450
- this.scene.matrixAutoUpdate = false // for perf
451
- this.scene.background = new THREE.Color(this.initOptions.config.sceneBackground)
452
- this.scene.add(this.ambientLight)
453
+ this.realScene.matrixAutoUpdate = false // for perf
454
+ this.realScene.background = new THREE.Color(this.initOptions.config.sceneBackground)
455
+ this.realScene.add(this.ambientLight)
453
456
  this.directionalLight.position.set(1, 1, 0.5).normalize()
454
457
  this.directionalLight.castShadow = true
455
- this.scene.add(this.directionalLight)
458
+ this.realScene.add(this.directionalLight)
456
459
 
457
460
  const size = this.renderer.getSize(new THREE.Vector2())
458
461
  this.camera = new THREE.PerspectiveCamera(75, size.x / size.y, 0.1, 1000)
459
462
  this._wrapCameraPositionWithWarning()
460
463
  this.cameraContainer = new THREE.Object3D()
461
464
  this.cameraContainer.add(this.camera)
462
- this.scene.add(this.cameraContainer)
465
+ this.realScene.add(this.cameraContainer)
466
+ this.realScene.add(this.scene)
463
467
  }
464
468
 
465
469
  override watchReactivePlayerState() {
@@ -625,7 +629,11 @@ export class WorldRendererThree extends WorldRendererCommon {
625
629
  }
626
630
 
627
631
  changeBackgroundColor(color: [number, number, number]): void {
628
- this.scene.background = new THREE.Color(color[0], color[1], color[2])
632
+ this.realScene.background = new THREE.Color(color[0], color[1], color[2])
633
+ }
634
+
635
+ changeCardinalLight(cardinalLight: string): void {
636
+ this.worldRendererConfig.cardinalLight = cardinalLight
629
637
  }
630
638
 
631
639
  timeUpdated(newTime: number): void {
@@ -662,7 +670,7 @@ export class WorldRendererThree extends WorldRendererCommon {
662
670
  setBlockPosition(mesh, pos)
663
671
  const helper = new THREE.BoxHelper(mesh, 0xff_ff_00)
664
672
  mesh.add(helper)
665
- this.scene.add(mesh)
673
+ this.realScene.add(mesh)
666
674
  }
667
675
 
668
676
  demoItem() {
@@ -675,7 +683,7 @@ export class WorldRendererThree extends WorldRendererCommon {
675
683
  // mesh.scale.set(0.5, 0.5, 0.5)
676
684
  const helper = new THREE.BoxHelper(mesh, 0xff_ff_00)
677
685
  mesh.add(helper)
678
- this.scene.add(mesh)
686
+ this.realScene.add(mesh)
679
687
  }
680
688
 
681
689
  debugOverlayAdded = false
@@ -695,7 +703,9 @@ export class WorldRendererThree extends WorldRendererCommon {
695
703
  text += `TE: ${formatBigNumber(this.renderer.info.memory.textures)} `
696
704
  text += `F: ${formatBigNumber(this.tilesRendered)} `
697
705
  text += `B: ${formatBigNumber(this.blocksRendered)} `
698
- text += `MEM: ${this.worldBlockGeometry.getEstimatedMemoryUsage().readable}`
706
+ text += `MEM: ${this.chunkMeshManager.getEstimatedMemoryUsage().total} `
707
+ const poolStats = this.chunkMeshManager.getStats()
708
+ text += `POOL: ${poolStats.activeCount}/${poolStats.poolSize} HR: ${poolStats.hitRate}`
699
709
  pane.updateText(text)
700
710
  this.backendInfoReport = text
701
711
  }
@@ -709,7 +719,8 @@ export class WorldRendererThree extends WorldRendererCommon {
709
719
  const [x, y, z] = key.split(',').map(x => Math.floor(+x / 16))
710
720
  // sum of distances: x + y + z
711
721
  const chunkDistance = Math.abs(x - this.cameraSectionPos.x) + Math.abs(y - this.cameraSectionPos.y) + Math.abs(z - this.cameraSectionPos.z)
712
- const section = this.sectionObjects[key].children.find(child => child.name === 'mesh')!
722
+ const sectionObj = this.sectionObjects[key]
723
+ const section = (sectionObj as any).mesh ?? sectionObj.children.find(child => child.name === 'mesh')!
713
724
  section.renderOrder = 500 - chunkDistance
714
725
  }
715
726
 
@@ -732,12 +743,15 @@ export class WorldRendererThree extends WorldRendererCommon {
732
743
  }
733
744
 
734
745
  finishChunk(chunkKey: string) {
735
- this.worldBlockGeometry.finishChunk(chunkKey)
746
+ // ChunkMeshManager applies updates immediately, no buffering needed
736
747
  }
737
748
 
738
749
  handleWorkerMessage(data: { geometry: MesherGeometryOutput, key, type }): void {
739
750
  if (data.type === 'geometry') {
740
- this.worldBlockGeometry.handleWorkerGeometryMessage(data)
751
+ const chunkCoords = data.key.split(',')
752
+ if (!this.loadedChunks[chunkCoords[0] + ',' + chunkCoords[2]] || !data.geometry.positions.length || !this.active) return
753
+ this.chunkMeshManager.updateSection(data.key, data.geometry)
754
+ this.updatePosDataChunk(data.key)
741
755
  }
742
756
  }
743
757
 
@@ -883,11 +897,11 @@ export class WorldRendererThree extends WorldRendererCommon {
883
897
  private debugRaycast(pos: THREE.Vector3, direction: THREE.Vector3, distance: number) {
884
898
  // Remove existing debug objects
885
899
  if (this.debugRaycastHelper) {
886
- this.scene.remove(this.debugRaycastHelper)
900
+ this.realScene.remove(this.debugRaycastHelper)
887
901
  this.debugRaycastHelper = undefined
888
902
  }
889
903
  if (this.debugHitPoint) {
890
- this.scene.remove(this.debugHitPoint)
904
+ this.realScene.remove(this.debugHitPoint)
891
905
  this.debugHitPoint = undefined
892
906
  }
893
907
 
@@ -907,14 +921,14 @@ export class WorldRendererThree extends WorldRendererCommon {
907
921
  distance * 0.1,
908
922
  distance * 0.05
909
923
  )
910
- this.scene.add(this.debugRaycastHelper)
924
+ this.realScene.add(this.debugRaycastHelper)
911
925
 
912
926
  // Create hit point indicator
913
927
  const hitGeometry = new THREE.SphereGeometry(0.2, 8, 8)
914
928
  const hitMaterial = new THREE.MeshBasicMaterial({ color: 0x00_ff_00 })
915
929
  this.debugHitPoint = new THREE.Mesh(hitGeometry, hitMaterial)
916
930
  this.debugHitPoint.position.copy(scenePos).add(direction.clone().multiplyScalar(distance))
917
- this.scene.add(this.debugHitPoint)
931
+ this.realScene.add(this.debugHitPoint)
918
932
  }
919
933
 
920
934
  prevFramePerspective = null as string | null
@@ -1012,11 +1026,11 @@ export class WorldRendererThree extends WorldRendererCommon {
1012
1026
 
1013
1027
  // remove any debug raycasting
1014
1028
  if (this.debugRaycastHelper) {
1015
- this.scene.remove(this.debugRaycastHelper)
1029
+ this.realScene.remove(this.debugRaycastHelper)
1016
1030
  this.debugRaycastHelper = undefined
1017
1031
  }
1018
1032
  if (this.debugHitPoint) {
1019
- this.scene.remove(this.debugHitPoint)
1033
+ this.realScene.remove(this.debugHitPoint)
1020
1034
  this.debugHitPoint = undefined
1021
1035
  }
1022
1036
  }
@@ -1087,9 +1101,8 @@ export class WorldRendererThree extends WorldRendererCommon {
1087
1101
 
1088
1102
  // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
1089
1103
  const cam = this.cameraGroupVr instanceof THREE.Group ? this.cameraGroupVr.children.find(child => child instanceof THREE.PerspectiveCamera) as THREE.PerspectiveCamera : this.camera
1090
- // Flush buffered geometry updates atomically before rendering
1091
- this.worldBlockGeometry.applyPendingUpdates()
1092
- this.renderer.render(this.scene, cam)
1104
+ // ChunkMeshManager applies updates immediately, no pending updates to flush
1105
+ this.renderer.render(this.realScene, cam)
1093
1106
 
1094
1107
  if (
1095
1108
  this.displayOptions.inWorldRenderingConfig.showHand &&
@@ -1118,6 +1131,9 @@ export class WorldRendererThree extends WorldRendererCommon {
1118
1131
  }
1119
1132
  const end = performance.now()
1120
1133
  const totalTime = end - start
1134
+ if (this.worldRendererConfig.autoLowerRenderDistance) {
1135
+ this.chunkMeshManager.recordRenderTime(totalTime)
1136
+ }
1121
1137
  this.renderTimeAvgCount++
1122
1138
  this.renderTimeAvg = ((this.renderTimeAvg * (this.renderTimeAvgCount - 1)) + totalTime) / this.renderTimeAvgCount
1123
1139
  this.renderTimeMax = Math.max(this.renderTimeMax, totalTime)
@@ -1233,15 +1249,16 @@ export class WorldRendererThree extends WorldRendererCommon {
1233
1249
  resetWorld() {
1234
1250
  super.resetWorld()
1235
1251
 
1236
- this.worldBlockGeometry.resetWorld()
1252
+ this.chunkMeshManager.dispose()
1253
+ this.chunkMeshManager = new ChunkMeshManager(this, this.scene, this.material, this.worldSizeParams.worldHeight, this.viewDistance)
1237
1254
 
1238
1255
  // Clean up debug objects
1239
1256
  if (this.debugRaycastHelper) {
1240
- this.scene.remove(this.debugRaycastHelper)
1257
+ this.realScene.remove(this.debugRaycastHelper)
1241
1258
  this.debugRaycastHelper = undefined
1242
1259
  }
1243
1260
  if (this.debugHitPoint) {
1244
- this.scene.remove(this.debugHitPoint)
1261
+ this.realScene.remove(this.debugHitPoint)
1245
1262
  this.debugHitPoint = undefined
1246
1263
  }
1247
1264
  }
@@ -1286,7 +1303,14 @@ export class WorldRendererThree extends WorldRendererCommon {
1286
1303
  super.removeColumn(x, z)
1287
1304
 
1288
1305
  this.cleanChunkTextures(x, z)
1289
- this.worldBlockGeometry.removeColumn(x, z)
1306
+ const sectionHeight = this.getSectionHeight()
1307
+ const worldMinY = this.worldMinYRender
1308
+ for (let y = worldMinY; y < this.worldSizeParams.worldHeight; y += sectionHeight) {
1309
+ const key = `${x},${y},${z}`
1310
+ if (this.chunkMeshManager.sectionObjects[key]) {
1311
+ this.chunkMeshManager.releaseSection(key)
1312
+ }
1313
+ }
1290
1314
  }
1291
1315
 
1292
1316
  setSectionDirty(...args: Parameters<WorldRendererCommon['setSectionDirty']>) {
@@ -1309,6 +1333,7 @@ export class WorldRendererThree extends WorldRendererCommon {
1309
1333
  }
1310
1334
 
1311
1335
  destroy(): void {
1336
+ this.chunkMeshManager.dispose()
1312
1337
  this.disposeModules()
1313
1338
  this.fireworksLegacy.destroy()
1314
1339
  super.destroy()