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.
Files changed (205) hide show
  1. package/README.md +66 -26
  2. package/dist/mesher.js +36 -36
  3. package/dist/mesher.js.map +4 -4
  4. package/dist/mesherWasm.js +217 -217
  5. package/dist/minecraft-renderer.js +66 -66
  6. package/dist/minecraft-renderer.js.meta.json +1 -1
  7. package/dist/threeWorker.js +450 -450
  8. package/package.json +5 -2
  9. package/src/bundler/bundlePrepare.ts +3 -8
  10. package/src/graphicsBackend/appViewer.ts +10 -7
  11. package/src/graphicsBackend/config.ts +1 -5
  12. package/src/graphicsBackend/playerState.ts +35 -34
  13. package/src/graphicsBackend/preloadWorkers.ts +43 -41
  14. package/src/graphicsBackend/rendererDefaultOptions.ts +68 -70
  15. package/src/graphicsBackend/rendererOptionsSync.ts +24 -50
  16. package/src/graphicsBackend/types.ts +2 -2
  17. package/src/index.ts +6 -27
  18. package/src/lib/DebugGui.ts +34 -31
  19. package/src/lib/animationController.ts +9 -9
  20. package/src/lib/bakeLegacyLight.ts +1 -6
  21. package/src/lib/bindAbortableListener.test.ts +32 -12
  22. package/src/lib/bindAbortableListener.ts +14 -6
  23. package/src/lib/blockEntityLightRegistry.ts +11 -20
  24. package/src/lib/blockEntityLighting.test.ts +1 -6
  25. package/src/lib/blockEntityLighting.ts +5 -5
  26. package/src/lib/buildSharedConfig.mjs +4 -4
  27. package/src/lib/buildWorkerMcDataIndexes.test.ts +4 -4
  28. package/src/lib/buildWorkerMcDataIndexes.ts +11 -19
  29. package/src/lib/cameraBobbing.ts +1 -1
  30. package/src/lib/canvas2DOverlay.example.ts +13 -33
  31. package/src/lib/canvas2DOverlay.quickstart.ts +24 -54
  32. package/src/lib/canvas2DOverlay.ts +28 -47
  33. package/src/lib/cleanupDecorator.ts +2 -2
  34. package/src/lib/createPlayerObject.test.ts +2 -7
  35. package/src/lib/createPlayerObject.ts +18 -25
  36. package/src/lib/frameTimingCollector.ts +2 -5
  37. package/src/lib/guiRenderer.ts +57 -42
  38. package/src/lib/items.ts +15 -9
  39. package/src/lib/mesherlogReader.ts +5 -6
  40. package/src/lib/simpleUtils.ts +5 -5
  41. package/src/lib/skyLight.ts +3 -3
  42. package/src/lib/smoothSwitcher.ts +11 -18
  43. package/src/lib/ui/newStats.ts +10 -12
  44. package/src/lib/utils/proxy.ts +7 -1
  45. package/src/lib/utils/skins.ts +4 -4
  46. package/src/lib/utils.ts +1 -1
  47. package/src/lib/workerMessageSanitize.ts +5 -12
  48. package/src/lib/workerProxy.ts +52 -42
  49. package/src/lib/workerSyncOps.test.ts +58 -41
  50. package/src/lib/worldrendererCommon.reconfigure.test.ts +24 -21
  51. package/src/lib/worldrendererCommon.removeColumn.test.ts +11 -13
  52. package/src/lib/worldrendererCommon.ts +349 -211
  53. package/src/mesher-legacy/mesher.ts +9 -4
  54. package/src/mesher-legacy/test/a.ts +1 -1
  55. package/src/mesher-legacy/test/mesherTester.ts +2 -2
  56. package/src/mesher-legacy/test/playground.ts +1 -1
  57. package/src/mesher-legacy/test/run/test-js.ts +1 -1
  58. package/src/mesher-legacy/test/snapshotUtils.ts +3 -8
  59. package/src/mesher-legacy/test/test-perf.ts +1 -1
  60. package/src/mesher-legacy/test/tests.test.ts +2 -2
  61. package/src/mesher-shared/blockEntityMetadata.test.ts +7 -5
  62. package/src/mesher-shared/blockEntityMetadata.ts +28 -19
  63. package/src/mesher-shared/blockPropertiesForMeshing.ts +2 -2
  64. package/src/mesher-shared/computeHeightmap.ts +2 -4
  65. package/src/mesher-shared/exportedGeometryTypes.ts +3 -3
  66. package/src/mesher-shared/faceOcclusion.ts +324 -0
  67. package/src/mesher-shared/models.ts +80 -131
  68. package/src/mesher-shared/modelsGeometryCommon.ts +30 -15
  69. package/src/mesher-shared/shared.ts +46 -46
  70. package/src/mesher-shared/standaloneRenderer.ts +40 -44
  71. package/src/mesher-shared/tests/faceOcclusion.test.ts +179 -0
  72. package/src/mesher-shared/tests/liquidQuadInvariant.test.ts +12 -8
  73. package/src/mesher-shared/vertexShading.ts +2 -11
  74. package/src/mesher-shared/world.ts +19 -19
  75. package/src/mesher-shared/worldLighting.test.ts +2 -2
  76. package/src/performanceMonitor/PerformanceMonitor.ts +4 -13
  77. package/src/performanceMonitor/formatPerformanceFactorsDebug.ts +2 -2
  78. package/src/performanceMonitor/index.ts +1 -5
  79. package/src/performanceMonitor/types.ts +1 -1
  80. package/src/playerState/playerState.ts +55 -50
  81. package/src/playerState/types.ts +2 -8
  82. package/src/playground/allEntitiesDebug.ts +19 -16
  83. package/src/playground/baseScene.ts +29 -32
  84. package/src/playground/mobileControls.tsx +133 -129
  85. package/src/playground/playground.html +76 -73
  86. package/src/playground/playground.ts +14 -1
  87. package/src/playground/playgroundUi.tsx +100 -74
  88. package/src/playground/reactUtils.ts +3 -7
  89. package/src/playground/scenes/entities.ts +10 -7
  90. package/src/playground/scenes/frequentUpdates.ts +5 -5
  91. package/src/playground/scenes/geometryExport.ts +6 -20
  92. package/src/playground/scenes/highPosEntityUpdates.ts +2 -10
  93. package/src/playground/scenes/index.ts +1 -1
  94. package/src/playground/scenes/lightingStarfield.ts +18 -12
  95. package/src/playground/scenes/main.ts +15 -11
  96. package/src/playground/scenes/partialBlockCulling.ts +31 -0
  97. package/src/playground/scenes/railsCobweb.ts +1 -1
  98. package/src/playground/scenes/rotationIssue.ts +1 -1
  99. package/src/playground/scenes/slabsOptimization.ts +1 -2
  100. package/src/playground/scenes/transparencyIssue.ts +1 -1
  101. package/src/playground/shared.ts +2 -2
  102. package/src/resourcesManager/resourcesManager.ts +29 -54
  103. package/src/resourcesManager/resourcesManager.worker.test.ts +6 -10
  104. package/src/shims/minecraftData.ts +70 -24
  105. package/src/sign-renderer/index.html +10 -12
  106. package/src/sign-renderer/index.ts +29 -29
  107. package/src/sign-renderer/playground.ts +22 -15
  108. package/src/sign-renderer/tests.test.ts +16 -13
  109. package/src/sign-renderer/vite.config.ts +2 -2
  110. package/src/three/appShared.ts +46 -25
  111. package/src/three/bannerRenderer.ts +33 -61
  112. package/src/three/cameraCollisionBlockCache.ts +156 -0
  113. package/src/three/cameraCollisionSolidity.ts +50 -0
  114. package/src/three/cameraShake.ts +15 -6
  115. package/src/three/chunkMeshManager.ts +223 -390
  116. package/src/three/cinimaticScript.ts +26 -15
  117. package/src/three/cubeDrawSpans.ts +27 -37
  118. package/src/three/cubeMultiDraw.ts +9 -22
  119. package/src/three/documentRenderer.ts +15 -18
  120. package/src/three/entities.ts +175 -150
  121. package/src/three/entity/EntityMesh.ts +114 -108
  122. package/src/three/entity/animations.js +3 -3
  123. package/src/three/entity/armorModels.ts +15 -15
  124. package/src/three/entity/gltfAnimationUtils.ts +2 -5
  125. package/src/three/fireworks.ts +34 -32
  126. package/src/three/fireworksRenderer.ts +32 -29
  127. package/src/three/globalBlockBuffer.ts +167 -100
  128. package/src/three/globalLegacyBuffer.ts +248 -264
  129. package/src/three/graphicsBackendBase.ts +19 -25
  130. package/src/three/graphicsBackendOffThread.ts +12 -15
  131. package/src/three/hand.ts +21 -21
  132. package/src/three/handLegacy.ts +3 -13
  133. package/src/three/holdingBlock.ts +116 -79
  134. package/src/three/holdingBlockFactory.ts +1 -4
  135. package/src/three/holdingBlockItemIdentity.test.ts +25 -17
  136. package/src/three/holdingBlockItemIdentity.ts +9 -6
  137. package/src/three/holdingBlockLegacy.ts +113 -132
  138. package/src/three/itemMesh.ts +20 -29
  139. package/src/three/legacyMultiDraw.ts +10 -16
  140. package/src/three/legacySectionCull.ts +8 -14
  141. package/src/three/menuBackground/activeView.ts +1 -4
  142. package/src/three/menuBackground/assetUrl.ts +1 -1
  143. package/src/three/menuBackground/classic.ts +4 -12
  144. package/src/three/menuBackground/gpuPreference.ts +1 -3
  145. package/src/three/menuBackground/index.ts +2 -11
  146. package/src/three/menuBackground/renderer.ts +1 -5
  147. package/src/three/menuBackground/types.ts +1 -4
  148. package/src/three/menuBackground/v2.ts +196 -96
  149. package/src/three/menuBackground/v2Meta.ts +3 -3
  150. package/src/three/menuBackground/worldBlocks.ts +37 -35
  151. package/src/three/modules/blockBreakParticles.ts +59 -28
  152. package/src/three/modules/cameraBobbing.ts +3 -6
  153. package/src/three/modules/index.ts +1 -1
  154. package/src/three/modules/rain.ts +10 -23
  155. package/src/three/modules/sciFiWorldReveal.ts +11 -25
  156. package/src/three/modules/starfield.ts +7 -13
  157. package/src/three/renderSlot.ts +28 -16
  158. package/src/three/rendererModuleSystem.ts +1 -3
  159. package/src/three/sceneOrigin.ts +96 -33
  160. package/src/three/sectionRaycastAabb.ts +24 -110
  161. package/src/three/shaderCubeMesh.ts +6 -17
  162. package/src/three/shaders/cubeBlockShader.ts +85 -96
  163. package/src/three/shaders/legacyBlockShader.ts +21 -43
  164. package/src/three/shaders/textureIndexMapping.ts +89 -95
  165. package/src/three/shaders/tintPalette.ts +156 -170
  166. package/src/three/signTextureCache.ts +9 -12
  167. package/src/three/skyboxRenderer.ts +62 -70
  168. package/src/three/tests/chunkMeshManagerLegacy.test.ts +34 -64
  169. package/src/three/tests/cubeDrawSpans.test.ts +55 -25
  170. package/src/three/tests/globalBlockBuffer.test.ts +217 -0
  171. package/src/three/tests/globalLegacyBuffer.test.ts +300 -41
  172. package/src/three/tests/legacyMultiDraw.test.ts +8 -29
  173. package/src/three/tests/pr3PerFrameCpuCuts.test.ts +106 -29
  174. package/src/three/tests/signTextureCache.test.ts +4 -4
  175. package/src/three/thirdPersonVoxelRaycast.ts +120 -0
  176. package/src/three/threeJsMedia.ts +55 -72
  177. package/src/three/threeJsParticles.ts +32 -41
  178. package/src/three/threeJsSound.ts +3 -3
  179. package/src/three/threeJsUtils.ts +3 -3
  180. package/src/three/threeWorker.ts +2 -2
  181. package/src/three/waypointSprite.ts +55 -82
  182. package/src/three/waypoints.ts +20 -23
  183. package/src/three/world/cursorBlock.ts +25 -12
  184. package/src/three/world/vr.ts +11 -17
  185. package/src/three/worldGeometryExport.ts +15 -34
  186. package/src/three/worldRendererThree.ts +144 -166
  187. package/src/wasm-mesher/bridge/convertChunk.ts +3 -9
  188. package/src/wasm-mesher/bridge/render-from-wasm.ts +204 -229
  189. package/src/wasm-mesher/bridge/shaderCubeBridge.ts +26 -67
  190. package/src/wasm-mesher/tests/cameraCollisionBlockCache.test.ts +82 -0
  191. package/src/wasm-mesher/tests/cullingRegression.test.ts +307 -0
  192. package/src/wasm-mesher/tests/heightmapParity.test.ts +8 -18
  193. package/src/wasm-mesher/tests/mesherWasmConversionCache.test.ts +2 -2
  194. package/src/wasm-mesher/tests/sectionRaycastAabb.test.ts +1 -93
  195. package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +103 -141
  196. package/src/wasm-mesher/tests/splitColumnWasmOutput.test.ts +14 -22
  197. package/src/wasm-mesher/tests/thirdPersonVoxelRaycast.test.ts +63 -0
  198. package/src/wasm-mesher/worker/mesherWasm.ts +150 -141
  199. package/src/wasm-mesher/worker/mesherWasmConversionCache.ts +2 -8
  200. package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +1 -3
  201. package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +1 -5
  202. package/src/wasm-mesher/worker/mesherWasmRequestTracker.ts +42 -42
  203. package/src/worldView/worldView.spiral.test.ts +1 -1
  204. package/src/worldView/worldView.ts +34 -39
  205. package/src/worldView/worldViewWorkerBridge.test.ts +4 -4
@@ -25,22 +25,23 @@ export class SkyboxRenderer {
25
25
  private readonly brightnessAtPosition = 1
26
26
  debugGui: DebugGui
27
27
 
28
- constructor (private readonly scene: THREE.Scene, public defaultSkybox: boolean, public initialImage: string | null) {
29
- this.debugGui = new DebugGui('skybox_renderer', this, [
30
- 'temperature',
31
- 'worldTime',
32
- 'inWater',
33
- 'waterBreathing',
34
- 'fogOrangeness',
35
- 'brightnessAtPosition',
36
- 'distanceFactor'
37
- ], {
38
- brightnessAtPosition: { min: 0, max: 1, step: 0.01 },
39
- temperature: { min: 0, max: 1, step: 0.01 },
40
- worldTime: { min: 0, max: 24_000, step: 1 },
41
- fogOrangeness: { min: -1, max: 1, step: 0.01 },
42
- distanceFactor: { min: 0, max: 5, step: 0.01 },
43
- })
28
+ constructor(
29
+ private readonly scene: THREE.Scene,
30
+ public defaultSkybox: boolean,
31
+ public initialImage: string | null
32
+ ) {
33
+ this.debugGui = new DebugGui(
34
+ 'skybox_renderer',
35
+ this,
36
+ ['temperature', 'worldTime', 'inWater', 'waterBreathing', 'fogOrangeness', 'brightnessAtPosition', 'distanceFactor'],
37
+ {
38
+ brightnessAtPosition: { min: 0, max: 1, step: 0.01 },
39
+ temperature: { min: 0, max: 1, step: 0.01 },
40
+ worldTime: { min: 0, max: 24_000, step: 1 },
41
+ fogOrangeness: { min: -1, max: 1, step: 0.01 },
42
+ distanceFactor: { min: 0, max: 5, step: 0.01 }
43
+ }
44
+ )
44
45
 
45
46
  if (!initialImage) {
46
47
  this.createGradientSky()
@@ -48,13 +49,13 @@ export class SkyboxRenderer {
48
49
  // this.debugGui.activate()
49
50
  }
50
51
 
51
- async init () {
52
+ async init() {
52
53
  if (this.initialImage) {
53
54
  await this.setSkyboxImage(this.initialImage)
54
55
  }
55
56
  }
56
57
 
57
- async setSkyboxImage (imageUrl: string) {
58
+ async setSkyboxImage(imageUrl: string) {
58
59
  // Dispose old textures if they exist
59
60
  if (this.texture) {
60
61
  this.texture.dispose()
@@ -62,19 +63,16 @@ export class SkyboxRenderer {
62
63
 
63
64
  // Load the equirectangular texture
64
65
  const textureLoader = new THREE.TextureLoader()
65
- this.texture = await new Promise((resolve) => {
66
- textureLoader.load(
67
- imageUrl,
68
- (texture) => {
69
- texture.mapping = THREE.EquirectangularReflectionMapping
70
- texture.colorSpace = THREE.SRGBColorSpace
71
- // Keep pixelated look
72
- texture.minFilter = THREE.NearestFilter
73
- texture.magFilter = THREE.NearestFilter
74
- texture.needsUpdate = true
75
- resolve(texture)
76
- }
77
- )
66
+ this.texture = await new Promise(resolve => {
67
+ textureLoader.load(imageUrl, texture => {
68
+ texture.mapping = THREE.EquirectangularReflectionMapping
69
+ texture.colorSpace = THREE.SRGBColorSpace
70
+ // Keep pixelated look
71
+ texture.minFilter = THREE.NearestFilter
72
+ texture.magFilter = THREE.NearestFilter
73
+ texture.needsUpdate = true
74
+ resolve(texture)
75
+ })
78
76
  })
79
77
 
80
78
  // Create or update the skybox
@@ -100,7 +98,7 @@ export class SkyboxRenderer {
100
98
  }
101
99
  }
102
100
 
103
- update (cameraPosition: THREE.Vector3, newViewDistance: number) {
101
+ update(cameraPosition: THREE.Vector3, newViewDistance: number) {
104
102
  if (newViewDistance !== this.viewDistance) {
105
103
  this.viewDistance = newViewDistance
106
104
  this.updateSkyColors()
@@ -118,7 +116,7 @@ export class SkyboxRenderer {
118
116
  }
119
117
 
120
118
  // Update world time
121
- updateTime (timeOfDay: number, partialTicks = 0) {
119
+ updateTime(timeOfDay: number, partialTicks = 0) {
122
120
  if (this.debugGui.visible) return
123
121
  this.worldTime = timeOfDay
124
122
  this.partialTicks = partialTicks
@@ -126,20 +124,20 @@ export class SkyboxRenderer {
126
124
  }
127
125
 
128
126
  // Update view distance
129
- updateViewDistance (viewDistance: number) {
127
+ updateViewDistance(viewDistance: number) {
130
128
  this.viewDistance = viewDistance
131
129
  this.updateSkyColors()
132
130
  }
133
131
 
134
132
  // Update temperature (for biome support)
135
- updateTemperature (temperature: number) {
133
+ updateTemperature(temperature: number) {
136
134
  if (this.debugGui.visible) return
137
135
  this.temperature = temperature
138
136
  this.updateSkyColors()
139
137
  }
140
138
 
141
139
  // Update water state
142
- updateWaterState (inWater: boolean, waterBreathing: boolean) {
140
+ updateWaterState(inWater: boolean, waterBreathing: boolean) {
143
141
  if (this.debugGui.visible) return
144
142
  this.inWater = inWater
145
143
  this.waterBreathing = waterBreathing
@@ -147,13 +145,13 @@ export class SkyboxRenderer {
147
145
  }
148
146
 
149
147
  // Update default skybox setting
150
- updateDefaultSkybox (defaultSkybox: boolean) {
148
+ updateDefaultSkybox(defaultSkybox: boolean) {
151
149
  if (this.debugGui.visible) return
152
150
  this.defaultSkybox = defaultSkybox
153
151
  this.updateSkyColors()
154
152
  }
155
153
 
156
- private createGradientSky () {
154
+ private createGradientSky() {
157
155
  const size = 64
158
156
  const scale = 256 / size + 2
159
157
 
@@ -190,7 +188,7 @@ export class SkyboxRenderer {
190
188
  this.updateSkyColors()
191
189
  }
192
190
 
193
- private getFogColor (partialTicks = 0): THREE.Vector3 {
191
+ private getFogColor(partialTicks = 0): THREE.Vector3 {
194
192
  const angle = this.getCelestialAngle(partialTicks)
195
193
  let rotation = Math.cos(angle * Math.PI * 2) * 2 + 0.5
196
194
  rotation = Math.max(0, Math.min(1, rotation))
@@ -199,14 +197,14 @@ export class SkyboxRenderer {
199
197
  let y = 0.847_058_83
200
198
  let z = 1
201
199
 
202
- x *= (rotation * 0.94 + 0.06)
203
- y *= (rotation * 0.94 + 0.06)
204
- z *= (rotation * 0.91 + 0.09)
200
+ x *= rotation * 0.94 + 0.06
201
+ y *= rotation * 0.94 + 0.06
202
+ z *= rotation * 0.91 + 0.09
205
203
 
206
204
  return new THREE.Vector3(x, y, z)
207
205
  }
208
206
 
209
- private getSkyColor (x = 0, z = 0, partialTicks = 0): THREE.Vector3 {
207
+ private getSkyColor(x = 0, z = 0, partialTicks = 0): THREE.Vector3 {
210
208
  const angle = this.getCelestialAngle(partialTicks)
211
209
  let brightness = Math.cos(angle * 3.141_593 * 2) * 2 + 0.5
212
210
 
@@ -220,15 +218,11 @@ export class SkyboxRenderer {
220
218
  const green = ((rgb >> 8) & 0xff) / 255
221
219
  const blue = (rgb & 0xff) / 255
222
220
 
223
- return new THREE.Vector3(
224
- red * brightness,
225
- green * brightness,
226
- blue * brightness
227
- )
221
+ return new THREE.Vector3(red * brightness, green * brightness, blue * brightness)
228
222
  }
229
223
 
230
- private calculateCelestialAngle (time: number, partialTicks: number): number {
231
- const modTime = (time % 24_000)
224
+ private calculateCelestialAngle(time: number, partialTicks: number): number {
225
+ const modTime = time % 24_000
232
226
  let angle = (modTime + partialTicks) / 24_000 - 0.25
233
227
 
234
228
  if (angle < 0) {
@@ -238,21 +232,21 @@ export class SkyboxRenderer {
238
232
  angle--
239
233
  }
240
234
 
241
- angle = 1 - ((Math.cos(angle * Math.PI) + 1) / 2)
235
+ angle = 1 - (Math.cos(angle * Math.PI) + 1) / 2
242
236
  angle += (angle - angle) / 3
243
237
 
244
238
  return angle
245
239
  }
246
240
 
247
- private getCelestialAngle (partialTicks: number): number {
241
+ private getCelestialAngle(partialTicks: number): number {
248
242
  return this.calculateCelestialAngle(this.worldTime, partialTicks)
249
243
  }
250
244
 
251
- private getTemperature (x: number, z: number): number {
245
+ private getTemperature(x: number, z: number): number {
252
246
  return this.temperature
253
247
  }
254
248
 
255
- private getSkyColorByTemp (temperature: number): number {
249
+ private getSkyColorByTemp(temperature: number): number {
256
250
  temperature /= 3
257
251
  if (temperature < -1) temperature = -1
258
252
  if (temperature > 1) temperature = 1
@@ -262,17 +256,20 @@ export class SkyboxRenderer {
262
256
  // Orange is around hue 0.08-0.15, so we need to shift from blue-purple (0.62) toward orange
263
257
  // Use a more dramatic shift and also increase saturation for more noticeable effect
264
258
  const orangeHue = 0.12 // Orange hue value
265
- const hue = this.fogOrangeness > 0
266
- ? baseHue + (orangeHue - baseHue) * this.fogOrangeness * 0.8 // Blend toward orange
267
- : baseHue + this.fogOrangeness * 0.1 // Subtle shift for negative values
259
+ const hue =
260
+ this.fogOrangeness > 0
261
+ ? baseHue + (orangeHue - baseHue) * this.fogOrangeness * 0.8 // Blend toward orange
262
+ : baseHue + this.fogOrangeness * 0.1 // Subtle shift for negative values
268
263
  const saturation = 0.5 + temperature * 0.1 + Math.abs(this.fogOrangeness) * 0.3 // Increase saturation with orangeness
269
264
  const brightness = 1
270
265
 
271
266
  return this.hsbToRgb(hue, saturation, brightness)
272
267
  }
273
268
 
274
- private hsbToRgb (hue: number, saturation: number, brightness: number): number {
275
- let r = 0; let g = 0; let b = 0
269
+ private hsbToRgb(hue: number, saturation: number, brightness: number): number {
270
+ let r = 0
271
+ let g = 0
272
+ let b = 0
276
273
  if (saturation === 0) {
277
274
  r = g = b = Math.floor(brightness * 255 + 0.5)
278
275
  } else {
@@ -280,7 +277,7 @@ export class SkyboxRenderer {
280
277
  const f = h - Math.floor(h)
281
278
  const p = brightness * (1 - saturation)
282
279
  const q = brightness * (1 - saturation * f)
283
- const t = brightness * (1 - (saturation * (1 - f)))
280
+ const t = brightness * (1 - saturation * (1 - f))
284
281
  switch (Math.floor(h)) {
285
282
  case 0:
286
283
  r = Math.floor(brightness * 255 + 0.5)
@@ -314,10 +311,10 @@ export class SkyboxRenderer {
314
311
  break
315
312
  }
316
313
  }
317
- return 0xff_00_00_00 | (r << 16) | (g << 8) | (Math.trunc(b))
314
+ return 0xff_00_00_00 | (r << 16) | (g << 8) | Math.trunc(b)
318
315
  }
319
316
 
320
- private updateSkyColors () {
317
+ private updateSkyColors() {
321
318
  if (!this.skyMesh || !this.voidMesh) return
322
319
 
323
320
  // If default skybox is disabled, hide the skybox meshes
@@ -357,7 +354,7 @@ export class SkyboxRenderer {
357
354
 
358
355
  // Normal sky colors
359
356
  const viewDistance = this.viewDistance * 16
360
- const viewFactor = 1 - (0.25 + 0.75 * this.viewDistance / 32) ** 0.25
357
+ const viewFactor = 1 - (0.25 + (0.75 * this.viewDistance) / 32) ** 0.25
361
358
 
362
359
  const angle = this.getCelestialAngle(this.partialTicks)
363
360
  const skyColor = this.getSkyColor(0, 0, this.partialTicks)
@@ -375,16 +372,11 @@ export class SkyboxRenderer {
375
372
 
376
373
  this.scene.background = new THREE.Color(red, green, blue)
377
374
  this.scene.fog = new THREE.Fog(new THREE.Color(red, green, blue), 0.0025, viewDistance * this.distanceFactor)
378
-
379
375
  ;(this.skyMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(skyColor.x, skyColor.y, skyColor.z))
380
- ;(this.voidMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(
381
- skyColor.x * 0.2 + 0.04,
382
- skyColor.y * 0.2 + 0.04,
383
- skyColor.z * 0.6 + 0.1
384
- ))
376
+ ;(this.voidMesh.material as THREE.MeshBasicMaterial).color.set(new THREE.Color(skyColor.x * 0.2 + 0.04, skyColor.y * 0.2 + 0.04, skyColor.z * 0.6 + 0.1))
385
377
  }
386
378
 
387
- dispose () {
379
+ dispose() {
388
380
  if (this.texture) {
389
381
  this.texture.dispose()
390
382
  }
@@ -3,7 +3,7 @@ import { test, expect, vi } from 'vitest'
3
3
  import * as THREE from 'three'
4
4
 
5
5
  vi.mock('../entity/EntityMesh', () => ({
6
- getMesh: vi.fn(),
6
+ getMesh: vi.fn()
7
7
  }))
8
8
 
9
9
  import { ChunkMeshManager } from '../chunkMeshManager'
@@ -11,13 +11,8 @@ import type { WorldRendererThree } from '../worldRendererThree'
11
11
  import type { MesherGeometryOutput } from '../../mesher-shared/shared'
12
12
  import { renderWasmOutputToGeometry } from '../../wasm-mesher/bridge/render-from-wasm'
13
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
- ])
14
+ function makeQuadArrays() {
15
+ const positions = new Float32Array([-1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1])
21
16
  const colors = new Float32Array(12).fill(1)
22
17
  const skyLights = new Float32Array(4).fill(1)
23
18
  const blockLights = new Float32Array(4).fill(0)
@@ -26,7 +21,7 @@ function makeQuadArrays () {
26
21
  return { positions, colors, skyLights, blockLights, uvs, indices }
27
22
  }
28
23
 
29
- function makeBlendOnlyGeometry (): MesherGeometryOutput {
24
+ function makeBlendOnlyGeometry(): MesherGeometryOutput {
30
25
  const blend = makeQuadArrays()
31
26
  return {
32
27
  sectionYNumber: 0,
@@ -62,12 +57,12 @@ function makeBlendOnlyGeometry (): MesherGeometryOutput {
62
57
  skyLights: blend.skyLights,
63
58
  blockLights: blend.blockLights,
64
59
  uvs: blend.uvs,
65
- indices: blend.indices,
66
- },
60
+ indices: blend.indices
61
+ }
67
62
  }
68
63
  }
69
64
 
70
- function makeMixedGeometry (): MesherGeometryOutput {
65
+ function makeMixedGeometry(): MesherGeometryOutput {
71
66
  const opaque = makeQuadArrays()
72
67
  const blend = makeQuadArrays()
73
68
  return {
@@ -104,12 +99,12 @@ function makeMixedGeometry (): MesherGeometryOutput {
104
99
  skyLights: blend.skyLights,
105
100
  blockLights: blend.blockLights,
106
101
  uvs: blend.uvs,
107
- indices: blend.indices,
108
- },
102
+ indices: blend.indices
103
+ }
109
104
  }
110
105
  }
111
106
 
112
- function makeInvalidBlendGeometry (): MesherGeometryOutput {
107
+ function makeInvalidBlendGeometry(): MesherGeometryOutput {
113
108
  const geo = makeBlendOnlyGeometry()
114
109
  const blend = geo.blend!
115
110
  return {
@@ -117,8 +112,8 @@ function makeInvalidBlendGeometry (): MesherGeometryOutput {
117
112
  blend: {
118
113
  ...blend,
119
114
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 2, 0, 0]),
120
- indices: new Uint32Array([0, 1, 2, 0, 2, 1, 3]),
121
- },
115
+ indices: new Uint32Array([0, 1, 2, 0, 2, 1, 3])
116
+ }
122
117
  }
123
118
  }
124
119
 
@@ -128,23 +123,18 @@ type ManagerOptions = {
128
123
  finishedChunks?: Record<string, boolean>
129
124
  }
130
125
 
131
- function makeShaderCubeOnlyGeometry (): MesherGeometryOutput {
126
+ function makeShaderCubeOnlyGeometry(): MesherGeometryOutput {
132
127
  const block = {
133
128
  position: [0, 0, 0] as [number, number, number],
134
129
  block_state_id: 1,
135
130
  visible_faces: (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5),
136
131
  ao_data: Array.from({ length: 6 }, () => [3, 3, 3, 3]),
137
132
  light_data: Array.from({ length: 6 }, () => [1, 1, 1, 1]),
138
- light_combined: Array.from({ length: 6 }, () => [255, 255, 255, 255]),
133
+ light_combined: Array.from({ length: 6 }, () => [255, 255, 255, 255])
139
134
  }
140
- const out = renderWasmOutputToGeometry(
141
- { blocks: [block], block_count: 1, block_iterations: 0 },
142
- '1.16.5',
143
- '0,0,0',
144
- { x: 8, y: 8, z: 8 },
145
- undefined,
146
- { shaderCubes: true },
147
- )
135
+ const out = renderWasmOutputToGeometry({ blocks: [block], block_count: 1, block_iterations: 0 }, '1.16.5', '0,0,0', { x: 8, y: 8, z: 8 }, undefined, {
136
+ shaderCubes: true
137
+ })
148
138
  return {
149
139
  sectionYNumber: 0,
150
140
  chunkKey: '0,0',
@@ -172,11 +162,11 @@ function makeShaderCubeOnlyGeometry (): MesherGeometryOutput {
172
162
  banners: {},
173
163
  hadErrors: false,
174
164
  blocksCount: 1,
175
- shaderCubes: out.shaderCubes,
165
+ shaderCubes: out.shaderCubes
176
166
  }
177
167
  }
178
168
 
179
- function makeCullCamera (): THREE.PerspectiveCamera {
169
+ function makeCullCamera(): THREE.PerspectiveCamera {
180
170
  const camera = new THREE.PerspectiveCamera(60, 1, 0.1, 1000)
181
171
  camera.position.set(8, 8, 20)
182
172
  camera.lookAt(8, 8, 8)
@@ -184,13 +174,19 @@ function makeCullCamera (): THREE.PerspectiveCamera {
184
174
  return camera
185
175
  }
186
176
 
187
- function createManager (opts: ManagerOptions = {}): ChunkMeshManager {
177
+ function drainCubeUploads(manager: ChunkMeshManager): void {
178
+ const gb = manager.globalBlockBuffer
179
+ if (!gb) return
180
+ while (gb.hasPendingUploads()) gb.uploadDirtyRange()
181
+ }
182
+
183
+ function createManager(opts: ManagerOptions = {}): ChunkMeshManager {
188
184
  const scene = new THREE.Scene()
189
185
  const material = new THREE.MeshBasicMaterial()
190
186
  const revealModule = opts.revealDefer
191
187
  ? {
192
- shouldDeferSectionGeometry: () => true,
193
- }
188
+ shouldDeferSectionGeometry: () => true
189
+ }
194
190
  : undefined
195
191
  const worldRenderer = {
196
192
  shaderCubeBlocksEnabled: () => opts.shaderCubes ?? false,
@@ -198,12 +194,12 @@ function createManager (opts: ManagerOptions = {}): ChunkMeshManager {
198
194
  sceneOrigin: {
199
195
  track: () => {},
200
196
  removeAndUntrack: () => {},
201
- removeAndUntrackAll: () => {},
197
+ removeAndUntrackAll: () => {}
202
198
  },
203
199
  blockEntities: {},
204
200
  worldRendererConfig: opts.shaderCubes ? { wasmMesher: true } : {},
205
201
  displayOptions: { inWorldRenderingConfig: {} },
206
- finishedChunks: opts.finishedChunks ?? (opts.shaderCubes ? { '0,0': true } : {}),
202
+ finishedChunks: opts.finishedChunks ?? (opts.shaderCubes ? { '0,0': true } : {})
207
203
  } as unknown as WorldRendererThree
208
204
  return new ChunkMeshManager(worldRenderer, scene, material, 256, 1)
209
205
  }
@@ -251,6 +247,8 @@ test('ChunkMeshManager: hidden section excluded from draw spans', () => {
251
247
  expect(manager.globalLegacyBlendBuffer?.getVisibleIndexSpans().length).toBe(0)
252
248
 
253
249
  section.visible = true
250
+ const blendBuf = manager.globalLegacyBlendBuffer!
251
+ while (blendBuf.hasPendingUploads()) blendBuf.uploadDirtyRange()
254
252
  manager.updateSectionCullAndSort(camera, 8, 8, 20)
255
253
  expect(manager.globalLegacyBlendBuffer?.getVisibleIndexSpans().length).toBeGreaterThan(0)
256
254
 
@@ -298,36 +296,6 @@ test('ChunkMeshManager: invalid blend geometry falls back to pooled mesh', () =>
298
296
  manager.dispose()
299
297
  })
300
298
 
301
- test('ChunkMeshManager: raycastGlobalLegacySections rejects off-ray sections within center distance', () => {
302
- const manager = createManager()
303
- const onRayKey = '0,0,0'
304
- const offRayKey = '0,2,0'
305
-
306
- manager.updateSection(onRayKey, makeBlendOnlyGeometry())
307
-
308
- const offRayGeo = makeBlendOnlyGeometry()
309
- offRayGeo.sz = 40
310
- manager.updateSection(offRayKey, offRayGeo)
311
-
312
- expect(manager.globalLegacyBlendBuffer?.hasSection(onRayKey)).toBe(true)
313
- expect(manager.globalLegacyBlendBuffer?.hasSection(offRayKey)).toBe(true)
314
- expect(manager.sectionObjects[offRayKey]?.worldZ).toBe(40)
315
-
316
- const origin = new THREE.Vector3(4, 8, 8)
317
- const direction = new THREE.Vector3(1, 0, 0).normalize()
318
- const raycaster = new THREE.Raycaster(origin, direction)
319
- raycaster.far = 4
320
-
321
- const hit = manager.raycastGlobalLegacySections(raycaster, origin, 80)
322
- expect(hit).toBeDefined()
323
- expect(hit!).toBeGreaterThan(2)
324
- expect(hit!).toBeLessThan(4)
325
-
326
- manager.cleanupSection(onRayKey)
327
- manager.cleanupSection(offRayKey)
328
- manager.dispose()
329
- })
330
-
331
299
  test('ChunkMeshManager: mixed opaque and blend route to separate global buffers', () => {
332
300
  const manager = createManager()
333
301
  const key = '0,0,0'
@@ -352,6 +320,7 @@ test('ChunkMeshManager: hidden cube section excluded from draw spans', () => {
352
320
  manager.updateSection(key, makeShaderCubeOnlyGeometry())
353
321
  const section = manager.sectionObjects[key]!
354
322
  expect(manager.globalBlockBuffer?.hasSection(key)).toBe(true)
323
+ drainCubeUploads(manager)
355
324
 
356
325
  const camera = makeCullCamera()
357
326
  manager.updateSectionCullAndSort(camera, 8, 8, 20)
@@ -385,6 +354,7 @@ test('ChunkMeshManager: finishChunkDisplay reveals cube spans and marks cull dir
385
354
  expect(manager.sectionObjects[key]?.visible).toBe(true)
386
355
  expect(markCullDirtySpy).toHaveBeenCalled()
387
356
 
357
+ drainCubeUploads(manager)
388
358
  manager.updateSectionCullAndSort(camera, 8, 8, 20)
389
359
  expect(manager.globalBlockBuffer?.getVisibleSpans().length).toBeGreaterThan(0)
390
360
 
@@ -1,46 +1,76 @@
1
1
  //@ts-nocheck
2
2
  import { describe, expect, test } from 'vitest'
3
- import {
4
- buildVisibleCubeSpans,
5
- MAX_CUBE_SPANS,
6
- SPAN_GAP_TOLERANCE_FACES,
7
- } from '../cubeDrawSpans'
3
+ import { buildVisibleCubeSpans } from '../cubeDrawSpans'
8
4
 
9
5
  describe('buildVisibleCubeSpans', () => {
10
6
  test('contiguous slots merge into one span', () => {
11
- const spans = buildVisibleCubeSpans([
12
- { start: 0, count: 4 },
13
- { start: 4, count: 2 },
14
- ], 6)
7
+ const spans = buildVisibleCubeSpans(
8
+ [
9
+ { start: 0, count: 4 },
10
+ { start: 4, count: 2 }
11
+ ],
12
+ 6
13
+ )
15
14
  expect(spans.length).toBe(1)
16
15
  expect(spans[0]).toEqual({ start: 0, count: 6 })
17
16
  })
18
17
 
19
18
  test('scattered slots stay as multiple spans', () => {
20
- const gap = SPAN_GAP_TOLERANCE_FACES + 1
21
- const spans = buildVisibleCubeSpans([
22
- { start: 0, count: 1 },
23
- { start: 1 + gap, count: 1 },
24
- ], 1 + gap + 1)
19
+ const spans = buildVisibleCubeSpans(
20
+ [
21
+ { start: 0, count: 1 },
22
+ { start: 10, count: 1 }
23
+ ],
24
+ 11
25
+ )
25
26
  expect(spans.length).toBe(2)
26
27
  expect(spans[0]).toEqual({ start: 0, count: 1 })
27
- expect(spans[1]).toEqual({ start: 1 + gap, count: 1 })
28
+ expect(spans[1]).toEqual({ start: 10, count: 1 })
28
29
  })
29
30
 
30
31
  test('full draw when most faces visible', () => {
31
- const spans = buildVisibleCubeSpans([
32
- { start: 0, count: 3 },
33
- { start: 3, count: 3 },
34
- { start: 6, count: 2 },
35
- ], 8)
32
+ const spans = buildVisibleCubeSpans(
33
+ [
34
+ { start: 0, count: 3 },
35
+ { start: 3, count: 3 },
36
+ { start: 6, count: 2 }
37
+ ],
38
+ 8
39
+ )
36
40
  expect(spans.length).toBe(1)
37
41
  expect(spans[0]).toEqual({ start: 0, count: 8 })
38
42
  })
39
43
 
40
- test('caps at MAX_CUBE_SPANS with full coverage', () => {
41
- const visibleSectionCount = MAX_CUBE_SPANS + 5
42
- const padFaces = SPAN_GAP_TOLERANCE_FACES + 1
43
- const visibleSlots: Array<{ start: number, count: number }> = []
44
+ test('full draw blocked when canFullDraw is false', () => {
45
+ const spans = buildVisibleCubeSpans([{ start: 0, count: 6 }], 8, false)
46
+ expect(spans).toEqual([{ start: 0, count: 6 }])
47
+ })
48
+
49
+ test('carves pending interior range from full-draw span', () => {
50
+ const spans = buildVisibleCubeSpans([{ start: 0, count: 6 }], 8, true, undefined, [{ start: 2, end: 3 }])
51
+ expect(spans).toEqual([
52
+ { start: 0, count: 2 },
53
+ { start: 4, count: 4 }
54
+ ])
55
+ })
56
+
57
+ test('does not merge across interior gap', () => {
58
+ const spans = buildVisibleCubeSpans(
59
+ [
60
+ { start: 0, count: 1 },
61
+ { start: 2, count: 1 }
62
+ ],
63
+ 3
64
+ )
65
+ expect(spans.length).toBe(2)
66
+ expect(spans[0]).toEqual({ start: 0, count: 1 })
67
+ expect(spans[1]).toEqual({ start: 2, count: 1 })
68
+ })
69
+
70
+ test('does not cap span count when many scattered sections', () => {
71
+ const visibleSectionCount = 69
72
+ const padFaces = 10
73
+ const visibleSlots: Array<{ start: number; count: number }> = []
44
74
  let cursor = 0
45
75
 
46
76
  for (let i = 0; i < visibleSectionCount; i++) {
@@ -53,7 +83,7 @@ describe('buildVisibleCubeSpans', () => {
53
83
 
54
84
  const highWatermark = cursor
55
85
  const spans = buildVisibleCubeSpans(visibleSlots, highWatermark)
56
- expect(spans.length).toBe(MAX_CUBE_SPANS)
86
+ expect(spans.length).toBe(visibleSectionCount)
57
87
 
58
88
  const covered = new Set<number>()
59
89
  for (const span of spans) {