minecraft-renderer 0.1.78 → 0.1.79

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.
@@ -0,0 +1,293 @@
1
+ //@ts-nocheck
2
+ import { test, expect, vi, afterEach } from 'vitest'
3
+ import * as THREE from 'three'
4
+
5
+ vi.mock('../entity/EntityMesh', () => ({
6
+ getMesh: vi.fn(),
7
+ }))
8
+
9
+ import { ChunkMeshManager } from '../chunkMeshManager'
10
+ import type { GlobalLegacyBuffer } from '../globalLegacyBuffer'
11
+ import type { WorldRendererThree } from '../worldRendererThree'
12
+ import type { MesherGeometryOutput } from '../../mesher-shared/shared'
13
+
14
+ function makeQuadArrays () {
15
+ const positions = new Float32Array([
16
+ -1, -1, -1,
17
+ -1, 1, -1,
18
+ -1, 1, 1,
19
+ -1, -1, 1,
20
+ ])
21
+ const colors = new Float32Array(12).fill(1)
22
+ const skyLights = new Float32Array(4).fill(1)
23
+ const blockLights = new Float32Array(4).fill(0)
24
+ const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1])
25
+ const indices = new Uint32Array([0, 1, 2, 0, 2, 3])
26
+ return { positions, colors, skyLights, blockLights, uvs, indices }
27
+ }
28
+
29
+ function makeBlendOnlyGeometry (): MesherGeometryOutput {
30
+ const blend = makeQuadArrays()
31
+ return {
32
+ sectionYNumber: 0,
33
+ chunkKey: '0,0',
34
+ sectionStartY: 0,
35
+ sectionEndY: 16,
36
+ sectionStartX: 0,
37
+ sectionEndX: 16,
38
+ sectionStartZ: 0,
39
+ sectionEndZ: 16,
40
+ sx: 8,
41
+ sy: 8,
42
+ sz: 8,
43
+ positions: new Float32Array(0),
44
+ normals: new Float32Array(0),
45
+ colors: new Float32Array(0),
46
+ skyLights: new Float32Array(0),
47
+ blockLights: new Float32Array(0),
48
+ uvs: new Float32Array(0),
49
+ indices: new Uint32Array(0),
50
+ indicesCount: 0,
51
+ using32Array: true,
52
+ tiles: {},
53
+ heads: {},
54
+ signs: {},
55
+ banners: {},
56
+ hadErrors: false,
57
+ blocksCount: 1,
58
+ blend: {
59
+ positions: blend.positions,
60
+ normals: new Float32Array(12),
61
+ colors: blend.colors,
62
+ skyLights: blend.skyLights,
63
+ blockLights: blend.blockLights,
64
+ uvs: blend.uvs,
65
+ indices: blend.indices,
66
+ },
67
+ }
68
+ }
69
+
70
+ function makeOpaqueOnlyGeometry (sx = 8, sy = 8, sz = 8): MesherGeometryOutput {
71
+ const opaque = makeQuadArrays()
72
+ return {
73
+ sectionYNumber: 0,
74
+ chunkKey: '0,0',
75
+ sectionStartY: 0,
76
+ sectionEndY: 16,
77
+ sectionStartX: 0,
78
+ sectionEndX: 16,
79
+ sectionStartZ: 0,
80
+ sectionEndZ: 16,
81
+ sx,
82
+ sy,
83
+ sz,
84
+ positions: opaque.positions,
85
+ normals: new Float32Array(12),
86
+ colors: opaque.colors,
87
+ skyLights: opaque.skyLights,
88
+ blockLights: opaque.blockLights,
89
+ uvs: opaque.uvs,
90
+ indices: opaque.indices,
91
+ indicesCount: 6,
92
+ using32Array: true,
93
+ tiles: {},
94
+ heads: {},
95
+ signs: {},
96
+ banners: {},
97
+ hadErrors: false,
98
+ blocksCount: 1,
99
+ }
100
+ }
101
+
102
+ function makeMixedGeometry (): MesherGeometryOutput {
103
+ const opaque = makeQuadArrays()
104
+ const blend = makeQuadArrays()
105
+ return {
106
+ sectionYNumber: 0,
107
+ chunkKey: '0,0',
108
+ sectionStartY: 0,
109
+ sectionEndY: 16,
110
+ sectionStartX: 0,
111
+ sectionEndX: 16,
112
+ sectionStartZ: 0,
113
+ sectionEndZ: 16,
114
+ sx: 8,
115
+ sy: 8,
116
+ sz: 8,
117
+ positions: opaque.positions,
118
+ normals: new Float32Array(12),
119
+ colors: opaque.colors,
120
+ skyLights: opaque.skyLights,
121
+ blockLights: opaque.blockLights,
122
+ uvs: opaque.uvs,
123
+ indices: opaque.indices,
124
+ indicesCount: 6,
125
+ using32Array: true,
126
+ tiles: {},
127
+ heads: {},
128
+ signs: {},
129
+ banners: {},
130
+ hadErrors: false,
131
+ blocksCount: 2,
132
+ blend: {
133
+ positions: blend.positions,
134
+ normals: new Float32Array(12),
135
+ colors: blend.colors,
136
+ skyLights: blend.skyLights,
137
+ blockLights: blend.blockLights,
138
+ uvs: blend.uvs,
139
+ indices: blend.indices,
140
+ },
141
+ }
142
+ }
143
+
144
+ function createManager (): ChunkMeshManager {
145
+ const scene = new THREE.Scene()
146
+ const material = new THREE.MeshBasicMaterial()
147
+ const worldRenderer = {
148
+ shaderCubeBlocksEnabled: () => false,
149
+ getModule: () => undefined,
150
+ sceneOrigin: {
151
+ track: () => {},
152
+ removeAndUntrack: () => {},
153
+ removeAndUntrackAll: () => {},
154
+ },
155
+ blockEntities: {},
156
+ worldRendererConfig: {},
157
+ } as unknown as WorldRendererThree
158
+ return new ChunkMeshManager(worldRenderer, scene, material, 256, 1)
159
+ }
160
+
161
+ type ManagerInternals = {
162
+ legacyCullSections: Map<string, { worldX: number, worldY: number, worldZ: number }>
163
+ registerLegacyCullSection: (key: string, wx: number, wy: number, wz: number) => void
164
+ maybeUnregisterLegacyCullSection: (key: string) => void
165
+ }
166
+
167
+ function getLegacyCullSections (manager: ChunkMeshManager): Map<string, { worldX: number, worldY: number, worldZ: number }> {
168
+ return (manager as unknown as ManagerInternals).legacyCullSections
169
+ }
170
+
171
+ function makeCamera (x: number, y: number, z: number): THREE.PerspectiveCamera {
172
+ const camera = new THREE.PerspectiveCamera(60, 1, 0.1, 1000)
173
+ camera.position.set(x, y, z)
174
+ camera.lookAt(8, 8, 8)
175
+ camera.updateMatrixWorld()
176
+ return camera
177
+ }
178
+
179
+ afterEach(() => {
180
+ vi.restoreAllMocks()
181
+ })
182
+
183
+ test('legacyCullSections: gains key on blend add, removed after cleanup', () => {
184
+ const manager = createManager()
185
+ const key = '0,0,0'
186
+
187
+ manager.updateSection(key, makeBlendOnlyGeometry())
188
+ expect(getLegacyCullSections(manager).has(key)).toBe(true)
189
+
190
+ manager.cleanupSection(key)
191
+ expect(getLegacyCullSections(manager).has(key)).toBe(false)
192
+
193
+ manager.dispose()
194
+ })
195
+
196
+ test('legacyCullSections: mixed opaque+blend keeps key until both buffers cleared', () => {
197
+ const manager = createManager()
198
+ const key = '0,0,0'
199
+
200
+ manager.updateSection(key, makeMixedGeometry())
201
+ expect(getLegacyCullSections(manager).has(key)).toBe(true)
202
+ expect(manager.globalLegacyBuffer?.hasSection(key)).toBe(true)
203
+ expect(manager.globalLegacyBlendBuffer?.hasSection(key)).toBe(true)
204
+
205
+ manager.globalLegacyBuffer?.removeSection(key)
206
+ expect(getLegacyCullSections(manager).has(key)).toBe(true)
207
+
208
+ manager.globalLegacyBlendBuffer?.removeSection(key)
209
+ ;(manager as unknown as ManagerInternals).maybeUnregisterLegacyCullSection(key)
210
+ expect(getLegacyCullSections(manager).has(key)).toBe(false)
211
+
212
+ manager.cleanupSection(key)
213
+ manager.dispose()
214
+ })
215
+
216
+ test('updateSectionCullAndSort: same visible set skips span rebuild on camera move', () => {
217
+ const manager = createManager()
218
+ const key = '0,0,0'
219
+ manager.updateSection(key, makeBlendOnlyGeometry())
220
+
221
+ const blendBuffer = manager.globalLegacyBlendBuffer!
222
+ const updateDrawSpansSpy = vi.spyOn(blendBuffer, 'updateDrawSpans')
223
+
224
+ const camera1 = makeCamera(8, 8, 20)
225
+ manager.updateSectionCullAndSort(camera1, 8, 8, 20)
226
+ expect(updateDrawSpansSpy).toHaveBeenCalledTimes(1)
227
+
228
+ const camera2 = makeCamera(8, 8, 18)
229
+ manager.updateSectionCullAndSort(camera2, 8, 8, 18)
230
+ expect(updateDrawSpansSpy).toHaveBeenCalledTimes(1)
231
+
232
+ manager.cleanupSection(key)
233
+ manager.dispose()
234
+ })
235
+
236
+ test('updateSectionCullAndSort: layoutVersion change forces span rebuild', () => {
237
+ const manager = createManager()
238
+ const key = '0,0,0'
239
+ manager.updateSection(key, makeBlendOnlyGeometry())
240
+
241
+ const blendBuffer = manager.globalLegacyBlendBuffer!
242
+ const updateDrawSpansSpy = vi.spyOn(blendBuffer, 'updateDrawSpans')
243
+
244
+ const camera = makeCamera(8, 8, 20)
245
+ manager.updateSectionCullAndSort(camera, 8, 8, 20)
246
+ expect(updateDrawSpansSpy).toHaveBeenCalledTimes(1)
247
+
248
+ blendBuffer.removeSection(key)
249
+ blendBuffer.addSection(
250
+ key,
251
+ makeBlendOnlyGeometry().blend!,
252
+ 8, 8, 8,
253
+ )
254
+ ;(manager as unknown as ManagerInternals).registerLegacyCullSection(key, 8, 8, 8)
255
+
256
+ manager.updateSectionCullAndSort(camera, 8, 8, 20)
257
+ expect(updateDrawSpansSpy).toHaveBeenCalledTimes(2)
258
+
259
+ manager.cleanupSection(key)
260
+ manager.dispose()
261
+ })
262
+
263
+ function drainLegacyUploads (buffer: GlobalLegacyBuffer): void {
264
+ while (buffer.hasPendingUploads()) buffer.uploadDirtyRange()
265
+ }
266
+
267
+ test('updateSectionCullAndSort: defrag finalize forces span rebuild with static camera', () => {
268
+ const manager = createManager()
269
+ const keys = ['0,0,0', '1,0,0', '2,0,0'] as const
270
+
271
+ for (let i = 0; i < keys.length; i++) {
272
+ manager.updateSection(keys[i]!, makeOpaqueOnlyGeometry(8, 8, 8 + i * 8))
273
+ }
274
+
275
+ const opaqueBuf = manager.globalLegacyBuffer!
276
+ const updateDrawSpansSpy = vi.spyOn(opaqueBuf, 'updateDrawSpans')
277
+ const camera = makeCamera(8, 8, 20)
278
+
279
+ manager.updateSectionCullAndSort(camera, 8, 8, 20)
280
+ expect(updateDrawSpansSpy).toHaveBeenCalledTimes(1)
281
+
282
+ opaqueBuf.removeSection('1,0,0')
283
+ drainLegacyUploads(opaqueBuf)
284
+ opaqueBuf.compactStep()
285
+ drainLegacyUploads(opaqueBuf)
286
+ opaqueBuf.compactStep()
287
+
288
+ manager.updateSectionCullAndSort(camera, 8, 8, 20)
289
+ expect(updateDrawSpansSpy).toHaveBeenCalledTimes(2)
290
+
291
+ for (const key of keys) manager.cleanupSection(key)
292
+ manager.dispose()
293
+ })
@@ -1330,12 +1330,22 @@ export class WorldRendererThree extends WorldRendererCommon {
1330
1330
  globalBuffer.suppressThreeDraw()
1331
1331
  }
1332
1332
  const globalLegacyBuffer = this.chunkMeshManager.globalLegacyBuffer
1333
- if (globalLegacyBuffer?.hasPendingUploads()) {
1334
- globalLegacyBuffer.uploadDirtyRange()
1333
+ if (globalLegacyBuffer) {
1334
+ globalLegacyBuffer.setDebugOverlay(this.displayOptions.inWorldRenderingConfig.enableDebugOverlay)
1335
+ globalLegacyBuffer.compactStep()
1336
+ if (globalLegacyBuffer.hasPendingUploads()) {
1337
+ globalLegacyBuffer.uploadDirtyRange()
1338
+ }
1339
+ globalLegacyBuffer.suppressThreeDraw()
1335
1340
  }
1336
1341
  const globalLegacyBlendBuffer = this.chunkMeshManager.globalLegacyBlendBuffer
1337
- if (globalLegacyBlendBuffer?.hasPendingUploads()) {
1338
- globalLegacyBlendBuffer.uploadDirtyRange()
1342
+ if (globalLegacyBlendBuffer) {
1343
+ globalLegacyBlendBuffer.setDebugOverlay(this.displayOptions.inWorldRenderingConfig.enableDebugOverlay)
1344
+ globalLegacyBlendBuffer.compactStep()
1345
+ if (globalLegacyBlendBuffer.hasPendingUploads()) {
1346
+ globalLegacyBlendBuffer.uploadDirtyRange()
1347
+ }
1348
+ globalLegacyBlendBuffer.suppressThreeDraw()
1339
1349
  }
1340
1350
  this.chunkMeshManager.setLegacyCameraOrigin(camX, camY, camZ)
1341
1351
  this.chunkMeshManager.updateCullDirtyFromCamera(cam, camX, camY, camZ)