minecraft-renderer 0.1.37 → 0.1.39

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.
@@ -67,7 +67,7 @@ export class WorldRendererThree extends WorldRendererCommon {
67
67
  cameraContainer!: THREE.Object3D
68
68
  media: ThreeJsMedia
69
69
  get waitingChunksToDisplay() {
70
- return {} as { [chunkKey: string]: string[] }
70
+ return this.chunkMeshManager.waitingChunksToDisplay
71
71
  }
72
72
  waypoints: WaypointsRenderer
73
73
  cinimaticScript: CinimaticScriptRunner
@@ -82,7 +82,14 @@ export class WorldRendererThree extends WorldRendererCommon {
82
82
  camera!: THREE.PerspectiveCamera
83
83
  renderTimeAvg = 0
84
84
  private pendingSectionUpdates = new Map<string, { geometry: MesherGeometryOutput, key: string, type: string }>()
85
- private pendingSectionBufferStartTime: number | null = null
85
+ /**
86
+ * Per-section buffering timestamps for `applyPendingSectionUpdates`.
87
+ * Each section gets its own deadline so a continuous stream of updates
88
+ * (e.g. server-side block changes from explosions, pistons, fluid ticks)
89
+ * does not flush freshly added sections together with stale ones via a
90
+ * single global timer.
91
+ */
92
+ private pendingSectionBufferStartTimes = new Map<string, number>()
86
93
  private static readonly MAX_SECTION_UPDATE_BUFFER_MS = 500
87
94
  // Memory usage tracking (in bytes)
88
95
  get estimatedMemoryUsage() {
@@ -747,42 +754,57 @@ export class WorldRendererThree extends WorldRendererCommon {
747
754
  }
748
755
 
749
756
  finishChunk(chunkKey: string) {
750
- // Existing sections are buffered and flushed from applyPendingSectionUpdates().
757
+ // Reveal all sections of this chunk that were held invisible by the
758
+ // "Batch Chunks Display" (`_renderByChunks`) option. No-op when the
759
+ // option is off — `waitingChunksToDisplay` is empty in that case.
760
+ this.chunkMeshManager.finishChunkDisplay(chunkKey)
751
761
  }
752
762
 
753
763
  private applyPendingSectionUpdates() {
754
764
  if (this.pendingSectionUpdates.size === 0) return
755
765
 
756
766
  const now = performance.now()
757
- const sinceFirst = now - (this.pendingSectionBufferStartTime ?? now)
767
+ const sectionHeight = this.getSectionHeight()
768
+ const ready: string[] = []
758
769
 
759
- if (sinceFirst < WorldRendererThree.MAX_SECTION_UPDATE_BUFFER_MS) {
760
- const sectionHeight = this.getSectionHeight()
761
- for (const key of this.pendingSectionUpdates.keys()) {
770
+ for (const key of this.pendingSectionUpdates.keys()) {
771
+ const startedAt = this.pendingSectionBufferStartTimes.get(key) ?? now
772
+ const sinceFirst = now - startedAt
773
+
774
+ if (sinceFirst < WorldRendererThree.MAX_SECTION_UPDATE_BUFFER_MS) {
775
+ // Still within this section's grace window — wait if any neighbor is
776
+ // currently being re-meshed so we don't briefly expose a hole between
777
+ // the just-updated section and a stale neighbor (sky-flicker bug).
762
778
  const [sx, sy, sz] = key.split(',').map(Number)
763
779
  const neighborKeys = [
764
780
  `${sx - 16},${sy},${sz}`, `${sx + 16},${sy},${sz}`,
765
781
  `${sx},${sy - sectionHeight},${sz}`, `${sx},${sy + sectionHeight},${sz}`,
766
782
  `${sx},${sy},${sz - 16}`, `${sx},${sy},${sz + 16}`,
767
783
  ]
768
-
784
+ let neighborBusy = false
769
785
  for (const neighborKey of neighborKeys) {
770
786
  if (
771
787
  this.sectionsWaiting.has(neighborKey) &&
772
788
  !this.pendingSectionUpdates.has(neighborKey) &&
773
789
  this.sectionObjects[neighborKey]
774
790
  ) {
775
- return
791
+ neighborBusy = true
792
+ break
776
793
  }
777
794
  }
795
+ if (neighborBusy) continue
778
796
  }
797
+
798
+ ready.push(key)
779
799
  }
780
800
 
781
- const updates = [...this.pendingSectionUpdates.values()]
782
- this.pendingSectionUpdates.clear()
783
- this.pendingSectionBufferStartTime = null
801
+ if (ready.length === 0) return
802
+
803
+ for (const key of ready) {
804
+ const update = this.pendingSectionUpdates.get(key)!
805
+ this.pendingSectionUpdates.delete(key)
806
+ this.pendingSectionBufferStartTimes.delete(key)
784
807
 
785
- for (const update of updates) {
786
808
  const chunkCoords = update.key.split(',')
787
809
  const chunkKey = `${chunkCoords[0]},${chunkCoords[2]}`
788
810
 
@@ -805,12 +827,9 @@ export class WorldRendererThree extends WorldRendererCommon {
805
827
  for (const key of [...this.pendingSectionUpdates.keys()]) {
806
828
  if (key.startsWith(`${x},`) && key.endsWith(`,${z}`)) {
807
829
  this.pendingSectionUpdates.delete(key)
830
+ this.pendingSectionBufferStartTimes.delete(key)
808
831
  }
809
832
  }
810
-
811
- if (this.pendingSectionUpdates.size === 0) {
812
- this.pendingSectionBufferStartTime = null
813
- }
814
833
  }
815
834
 
816
835
  handleWorkerMessage(data: { geometry: MesherGeometryOutput, key, type }): void {
@@ -819,15 +838,17 @@ export class WorldRendererThree extends WorldRendererCommon {
819
838
  const chunkKey = `${chunkCoords[0]},${chunkCoords[2]}`
820
839
  if (!this.loadedChunks[chunkKey] || !this.active) {
821
840
  this.pendingSectionUpdates.delete(data.key)
822
- if (this.pendingSectionUpdates.size === 0) {
823
- this.pendingSectionBufferStartTime = null
824
- }
841
+ this.pendingSectionBufferStartTimes.delete(data.key)
825
842
  return
826
843
  }
827
844
 
828
845
  if (this.sectionObjects[data.key]) {
829
846
  this.pendingSectionUpdates.set(data.key, data)
830
- this.pendingSectionBufferStartTime ??= performance.now()
847
+ // Per-section deadline: only set if we don't already have one, so
848
+ // repeated updates to the same section don't postpone its flush.
849
+ if (!this.pendingSectionBufferStartTimes.has(data.key)) {
850
+ this.pendingSectionBufferStartTimes.set(data.key, performance.now())
851
+ }
831
852
  return
832
853
  }
833
854
 
@@ -1137,6 +1158,7 @@ export class WorldRendererThree extends WorldRendererCommon {
1137
1158
  chunksRenderDistanceOverride !== undefined
1138
1159
  ) {
1139
1160
  for (const [key, object] of Object.entries(this.sectionObjects)) {
1161
+ if (object._waitingForChunkDisplay) continue
1140
1162
  const [x, y, z] = key.split(',').map(Number)
1141
1163
  const isVisible =
1142
1164
  // eslint-disable-next-line no-constant-binary-expression, sonarjs/no-redundant-boolean
@@ -1149,9 +1171,11 @@ export class WorldRendererThree extends WorldRendererCommon {
1149
1171
  object.visible = isVisible
1150
1172
  }
1151
1173
  } else {
1152
- for (const object of Object.values(this.sectionObjects)) {
1153
- object.visible = true
1154
- }
1174
+ // No debug visibility override active — defer to the manager so the
1175
+ // performance-based override distance (set by `recordRenderTime` /
1176
+ // `autoLowerRenderDistance`) is honored, instead of force-showing every
1177
+ // section every frame and clobbering it.
1178
+ this.chunkMeshManager.updateSectionsVisibility()
1155
1179
  }
1156
1180
  }
1157
1181
 
@@ -1322,20 +1346,16 @@ export class WorldRendererThree extends WorldRendererCommon {
1322
1346
  }
1323
1347
 
1324
1348
  updateShowChunksBorder(value: boolean) {
1325
- for (const object of Object.values(this.sectionObjects)) {
1326
- for (const child of object.children) {
1327
- if (child.name === 'helper') {
1328
- child.visible = value
1329
- }
1330
- }
1331
- }
1349
+ // Lazily create helpers on the first toggle (they are not created upfront
1350
+ // for sections streamed in while the option was off).
1351
+ this.chunkMeshManager.updateAllBoxHelpers(value)
1332
1352
  }
1333
1353
 
1334
1354
  resetWorld() {
1335
1355
  super.resetWorld()
1336
1356
 
1337
1357
  this.pendingSectionUpdates.clear()
1338
- this.pendingSectionBufferStartTime = null
1358
+ this.pendingSectionBufferStartTimes.clear()
1339
1359
  this.chunkMeshManager.dispose()
1340
1360
  this.chunkMeshManager = new ChunkMeshManager(this, this.scene, this.material, this.worldSizeParams.worldHeight, this.viewDistance)
1341
1361
 
@@ -1366,6 +1386,11 @@ export class WorldRendererThree extends WorldRendererCommon {
1366
1386
  textures[key].dispose()
1367
1387
  delete textures[key]
1368
1388
  }
1389
+ // Sign / head textures moved to ChunkMeshManager.signHeadsRenderer in PR
1390
+ // #16; without invalidating that cache here, sign edits (and any other
1391
+ // block-entity NBT change picked up via setSectionDirty) would re-render
1392
+ // with the stale cached canvas until a full world reset.
1393
+ this.chunkMeshManager.cleanSignChunkTextures(x, z)
1369
1394
  }
1370
1395
 
1371
1396
  readdChunks() {
@@ -1399,6 +1424,13 @@ export class WorldRendererThree extends WorldRendererCommon {
1399
1424
  this.chunkMeshManager.releaseSection(key)
1400
1425
  }
1401
1426
  }
1427
+ // Drop near-first reveal state and re-check any farther chunks
1428
+ // that may have been blocked by this column.
1429
+ this.chunkMeshManager.onChunkRemovedFromGate(`${x},${z}`)
1430
+ }
1431
+
1432
+ protected onViewerChunkPositionChanged(): void {
1433
+ this.chunkMeshManager.tryRevealPending()
1402
1434
  }
1403
1435
 
1404
1436
  setSectionDirty(...args: Parameters<WorldRendererCommon['setSectionDirty']>) {
@@ -1422,7 +1454,7 @@ export class WorldRendererThree extends WorldRendererCommon {
1422
1454
 
1423
1455
  destroy(): void {
1424
1456
  this.pendingSectionUpdates.clear()
1425
- this.pendingSectionBufferStartTime = null
1457
+ this.pendingSectionBufferStartTimes.clear()
1426
1458
  this.chunkMeshManager.dispose()
1427
1459
  this.disposeModules()
1428
1460
  this.fireworksLegacy.destroy()
@@ -64,6 +64,7 @@ interface CachedBlockModel {
64
64
  blockProps: Record<string, any>
65
65
  models: any // BlockModelPartsResolved
66
66
  isCube: boolean
67
+ boundingBox: string
67
68
  // Precomputed per-model variant
68
69
  modelVariants: Array<{
69
70
  model: any
@@ -86,10 +87,51 @@ interface WasmBlockFaceData {
86
87
  light_data: number[][]
87
88
  }
88
89
 
89
- interface WasmGeometryOutput {
90
+ export interface WasmGeometryOutput {
90
91
  blocks: WasmBlockFaceData[]
91
92
  block_count: number
92
93
  block_iterations: number
94
+ /**
95
+ * Per-(x,z) max non-invisible block Y for the meshed column, indexed as
96
+ * `z * 16 + x`. Sentinel value `-32768` = no block in that column.
97
+ *
98
+ * Populated by Rust `Mesher::generate_with_world` (see
99
+ * `wasm-mesher/src/mesher.rs`, field `heightmap`). serde_wasm_bindgen
100
+ * serializes `Vec<i16>` as a plain JS `number[]`, which is why the type
101
+ * here is `ArrayLike<number>` rather than `Int16Array` — the runtime
102
+ * adapter `extractColumnHeightmap` handles both shapes.
103
+ *
104
+ * Used at runtime by `mesherWasm.ts` `processColumnTick`: every column
105
+ * tick the WASM heightmap is extracted via `extractColumnHeightmap` and
106
+ * posted to the main thread as a `'heightmap'` message. JS
107
+ * `computeHeightmap` is now only a fallback (length mismatch / missing
108
+ * field) and a safety-net for empty columns at chunk load. Empty-column
109
+ * semantics are aligned: both Rust and JS use `-32768` (see
110
+ * `EMPTY_COLUMN_HEIGHTMAP_SENTINEL`).
111
+ */
112
+ heightmap?: ArrayLike<number> | null
113
+ }
114
+
115
+ /**
116
+ * Extract a 256-entry Int16Array heightmap from a full-column WASM mesher
117
+ * result, indexed as `z * 16 + x` (matching the JS `computeHeightmap`
118
+ * convention). Returns `null` when the WASM output does not carry a
119
+ * heightmap or carries one of unexpected length — in that case the
120
+ * caller MUST fall back to JS `computeHeightmap` rather than guess.
121
+ *
122
+ * This adapter is the single place that converts Rust's `Vec<i16>` heightmap
123
+ * shape into a transferable typed array. Tests exercise this same adapter so
124
+ * future runtime usage and parity assertions cannot drift apart.
125
+ */
126
+ export function extractColumnHeightmap(
127
+ wasmOutput: { heightmap?: ArrayLike<number> | null } | null | undefined
128
+ ): Int16Array | null {
129
+ const raw = wasmOutput?.heightmap
130
+ if (!raw || raw.length !== 256) return null
131
+ if (raw instanceof Int16Array) return new Int16Array(raw)
132
+ const out = new Int16Array(256)
133
+ for (let i = 0; i < 256; i++) out[i] = raw[i]
134
+ return out
93
135
  }
94
136
 
95
137
  /**
@@ -181,6 +223,7 @@ function getCachedBlockModel(
181
223
  models,
182
224
  modelVariants,
183
225
  isCube,
226
+ boundingBox: blockObj.boundingBox,
184
227
  }
185
228
 
186
229
  cache.set(cacheKey, cached)
@@ -697,6 +740,11 @@ export function renderWasmOutputToGeometry(
697
740
  globalShift = vecsub3(globalShift, matmul3(globalMatrix, globalShift))
698
741
  }
699
742
 
743
+ // Mirror JS mesher: doAO = model.ao ?? block.boundingBox !== 'empty'.
744
+ // When false, faces are emitted full-bright without AO/light sampling and without
745
+ // triangle-flip reordering (matches JS `light = 1` and standard winding).
746
+ const doAO = (model as any).ao ?? cachedModel.boundingBox !== 'empty'
747
+
700
748
  for (const element of model.elements ?? []) {
701
749
  let localMatrix = null as any
702
750
  let localShift = null as any
@@ -723,8 +771,12 @@ export function renderWasmOutputToGeometry(
723
771
  Math.round(transformedDir[2]),
724
772
  ]
725
773
  const dirKey = `${transformedDirI[0]},${transformedDirI[1]},${transformedDirI[2]}`
774
+ // faceIdx may be undefined for diagonal-rotated faces (e.g. signs at 45/135/225/315 deg).
775
+ // Such faces are not representable in the 6-axis WASM visible_faces / ao_data / light_data
776
+ // arrays. We still emit them (mirrors JS mesher behavior); cullface and AO/light data
777
+ // lookups are skipped, and the model-lighting fallback below derives AO/light by
778
+ // sampling neighbors via transformedDirI (its rounded form, same as for cardinal axes).
726
779
  const faceIdx = dirKeyToIndex[dirKey]
727
- if (faceIdx === undefined) continue
728
780
 
729
781
  const minx = element.from[0]
730
782
  const miny = element.from[1]
@@ -733,13 +785,13 @@ export function renderWasmOutputToGeometry(
733
785
  const maxy = element.to[1]
734
786
  const maxz = element.to[2]
735
787
 
736
- if (matchingEFace.cullface) {
788
+ if (matchingEFace.cullface && faceIdx !== undefined) {
737
789
  if ((block.visible_faces & (1 << faceIdx)) === 0) {
738
790
  continue
739
791
  }
740
792
  }
741
793
 
742
- const faceDataIndex = wasmFaceToDataIndex[faceIdx]
794
+ const faceDataIndex = faceIdx === undefined ? undefined : wasmFaceToDataIndex[faceIdx]
743
795
  const aoValuesRaw = faceDataIndex === undefined ? undefined : block.ao_data[faceDataIndex]
744
796
  const lightValuesRaw = faceDataIndex === undefined ? undefined : block.light_data[faceDataIndex]
745
797
 
@@ -787,8 +839,13 @@ export function renderWasmOutputToGeometry(
787
839
 
788
840
  let ao = 3
789
841
  let cornerLightResult = 15
842
+ let light: number
790
843
 
791
- if (useModelLighting) {
844
+ if (!doAO) {
845
+ // JS parity: skip AO/light sampling, emit full-bright vertex.
846
+ computedAoValues[cornerIdx] = 3
847
+ light = 1
848
+ } else if (useModelLighting) {
792
849
  const cursor = new Vec3(bx, by, bz)
793
850
 
794
851
  const dx = pos[0] * 2 - 1
@@ -849,9 +906,11 @@ export function renderWasmOutputToGeometry(
849
906
  cornerLightResult = baseLight * 15
850
907
  }
851
908
 
852
- const light = (ao + 1) / 4 * (cornerLightResult / 15)
909
+ if (doAO) {
910
+ light = (ao + 1) / 4 * (cornerLightResult / 15)
911
+ }
853
912
 
854
- colors.push(tint[0] * light, tint[1] * light, tint[2] * light)
913
+ colors.push(tint[0] * light!, tint[1] * light!, tint[2] * light!)
855
914
 
856
915
  const baseu = (pos[3] - 0.5) * uvcs - (pos[4] - 0.5) * uvsn + 0.5
857
916
  const basev = (pos[3] - 0.5) * uvsn + (pos[4] - 0.5) * uvcs + 0.5
@@ -865,7 +924,7 @@ export function renderWasmOutputToGeometry(
865
924
  const aoValues = computedAoValues
866
925
 
867
926
  let tri1: number[], tri2: number[]
868
- if (aoValues[0] + aoValues[3] >= aoValues[1] + aoValues[2]) {
927
+ if (doAO && aoValues[0] + aoValues[3] >= aoValues[1] + aoValues[2]) {
869
928
  tri1 = [baseIndex, baseIndex + 3, baseIndex + 2]
870
929
  tri2 = [baseIndex, baseIndex + 1, baseIndex + 3]
871
930
  } else {
@@ -915,15 +974,101 @@ export function renderWasmOutputToGeometry(
915
974
  },
916
975
  }
917
976
 
918
- console.log(`[WASM] Final geometry summary:`)
919
- console.log(`[WASM] Total vertices: ${positions.length / 3}`)
920
- console.log(`[WASM] Total triangles: ${indices.length / 3}`)
921
- console.log(`[WASM] Positions: [${positions.slice(0, 12).join(',')}...] (first 4 vertices)`)
922
- console.log(`[WASM] Indices: [${indices.slice(0, 12).join(',')}...] (first 2 faces)`)
977
+ log(`[WASM] Final geometry summary:`)
978
+ log(`[WASM] Total vertices: ${positions.length / 3}`)
979
+ log(`[WASM] Total triangles: ${indices.length / 3}`)
980
+ log(`[WASM] Positions: [${positions.slice(0, 12).join(',')}...] (first 4 vertices)`)
981
+ log(`[WASM] Indices: [${indices.slice(0, 12).join(',')}...] (first 2 faces)`)
923
982
 
924
983
  return result
925
984
  }
926
985
 
986
+ /**
987
+ * Split a single full-column WASM mesher result into per-section
988
+ * `ExportedSection` outputs by filtering `wasmResult.blocks` per requested
989
+ * section's Y range and invoking `renderWasmOutputToGeometry` once per
990
+ * section.
991
+ *
992
+ * Why split at the block level (and not after geometry generation):
993
+ * - Liquids (water/lava), signs/heads/banners metadata, AO/light arrays
994
+ * and index numbering are computed inside `renderWasmOutputToGeometry`.
995
+ * Splitting *finished* vertex/index buffers would silently break those.
996
+ * - Filtering blocks by Y range and re-running the post-processor per
997
+ * section keeps the output identical to the existing per-section path.
998
+ *
999
+ * Y=15/16 (and any other inter-section) seam handling:
1000
+ * - The Rust mesher produced `wasmResult` over the full column, so each
1001
+ * block's `visible_faces`, `ao_data` and `light_data` already account
1002
+ * for its true neighbors — including the block above at the section
1003
+ * seam (e.g. a Y=15 top face is correctly suppressed when Y=16 is
1004
+ * opaque, even though Y=16 lives in the next render section).
1005
+ * - This helper therefore does NOT need to widen the per-section block
1006
+ * window: a strict `[sy*sectionHeight, sy*sectionHeight + sectionHeight)`
1007
+ * filter on `block.position[1]` is sufficient. The neighbor information
1008
+ * is already baked into each block's per-face mask/AO/light arrays.
1009
+ *
1010
+ * Empty sections: sections with no blocks in range still get a call into
1011
+ * `renderWasmOutputToGeometry` with an empty `blocks` array, so the
1012
+ * returned `ExportedSection` shape matches what the per-section path
1013
+ * produces for an empty section (empty positions/normals/colors/uvs/
1014
+ * indices arrays).
1015
+ *
1016
+ * Note: this pure helper is not gated internally; callers decide whether
1017
+ * column meshing is enabled.
1018
+ */
1019
+ export function splitColumnWasmOutputToSections(
1020
+ fullColumnOutput: WasmGeometryOutput,
1021
+ requestedSectionKeys: Array<{ x: number, y: number, z: number }>,
1022
+ ctx: { version: string, world?: World, sectionHeight?: number }
1023
+ ): Map<string, { exported: ExportedSection, blocksCount: number }> {
1024
+ const { version, world } = ctx
1025
+ const sectionHeight = ctx.sectionHeight ?? 16
1026
+
1027
+ // Bucket blocks by section Y once, so we don't re-scan the full column
1028
+ // for every requested section. Bucket key = section-relative chunk Y
1029
+ // (i.e. floor(by / sectionHeight)).
1030
+ const blocksByChunkY = new Map<number, WasmBlockFaceData[]>()
1031
+ for (const block of fullColumnOutput.blocks) {
1032
+ const by = block.position[1]
1033
+ const chunkY = Math.floor(by / sectionHeight)
1034
+ let bucket = blocksByChunkY.get(chunkY)
1035
+ if (!bucket) {
1036
+ bucket = []
1037
+ blocksByChunkY.set(chunkY, bucket)
1038
+ }
1039
+ bucket.push(block)
1040
+ }
1041
+
1042
+ const out = new Map<string, { exported: ExportedSection, blocksCount: number }>()
1043
+ for (const { x, y, z } of requestedSectionKeys) {
1044
+ // `y` here is the section's world-Y origin (multiple of sectionHeight),
1045
+ // matching the convention used by `mesherWasm.ts` (section keys are
1046
+ // `${chunkX*16},${sectionY},${chunkZ*16}` with sectionY a world-Y
1047
+ // multiple of 16). Translate to chunk-Y bucket index.
1048
+ const chunkY = Math.floor(y / sectionHeight)
1049
+ const sectionBlocks = blocksByChunkY.get(chunkY) ?? []
1050
+
1051
+ const sectionView: WasmGeometryOutput = {
1052
+ blocks: sectionBlocks,
1053
+ block_count: sectionBlocks.length,
1054
+ block_iterations: fullColumnOutput.block_iterations,
1055
+ }
1056
+
1057
+ const sectionKey = `${x},${y},${z}`
1058
+ const sectionPosition = { x: x + 8, y: y + 8, z: z + 8 }
1059
+ const exported = renderWasmOutputToGeometry(
1060
+ sectionView,
1061
+ version,
1062
+ sectionKey,
1063
+ sectionPosition,
1064
+ world
1065
+ )
1066
+ out.set(sectionKey, { exported, blocksCount: sectionBlocks.length })
1067
+ }
1068
+
1069
+ return out
1070
+ }
1071
+
927
1072
  /**
928
1073
  * Convert WASM output to exported geometry format
929
1074
  */
@@ -7,16 +7,16 @@
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
 
16
16
  export interface InitOutput {
17
17
  readonly memory: WebAssembly.Memory;
18
- readonly generate_geometry: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number, v: number, w: number, x: number, y: number, z: number, a1: number) => any;
19
- readonly generate_geometry_multi: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number, v: number, w: number, x: number, y: number, z: number, a1: number, b1: number, c1: number, d1: number, e1: number) => any;
18
+ readonly generate_geometry: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number, v: number, w: number, x: number, y: number, z: number, a1: number, b1: number) => any;
19
+ readonly generate_geometry_multi: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number, v: number, w: number, x: number, y: number, z: number, a1: number, b1: number, c1: number, d1: number, e1: number, f1: number) => any;
20
20
  readonly __wbindgen_malloc: (a: number, b: number) => number;
21
21
  readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
22
22
  readonly __wbindgen_externrefs: WebAssembly.Table;
@@ -1,15 +1,5 @@
1
1
  let wasm;
2
2
 
3
- function _assertBoolean(n) {
4
- if (typeof(n) !== 'boolean') {
5
- throw new Error(`expected a boolean argument, found ${typeof(n)}`);
6
- }
7
- }
8
-
9
- function _assertNum(n) {
10
- if (typeof(n) !== 'number') throw new Error(`expected a number argument, found ${typeof(n)}`);
11
- }
12
-
13
3
  function debugString(val) {
14
4
  // primitive types
15
5
  const type = typeof val;
@@ -112,22 +102,6 @@ function getUint8ArrayMemory0() {
112
102
  return cachedUint8ArrayMemory0;
113
103
  }
114
104
 
115
- function logError(f, args) {
116
- try {
117
- return f.apply(this, args);
118
- } catch (e) {
119
- let error = (function () {
120
- try {
121
- return e instanceof Error ? `${e.message}\n\nStack:\n${e.stack}` : e.toString();
122
- } catch(_) {
123
- return "<failed to stringify thrown value>";
124
- }
125
- }());
126
- console.error("wasm-bindgen: imported JS function that was not marked as `catch` threw an error:", error);
127
- throw e;
128
- }
129
- }
130
-
131
105
  function passArray16ToWasm0(arg, malloc) {
132
106
  const ptr = malloc(arg.length * 2, 2) >>> 0;
133
107
  getUint16ArrayMemory0().set(arg, ptr / 2);
@@ -150,7 +124,6 @@ function passArray8ToWasm0(arg, malloc) {
150
124
  }
151
125
 
152
126
  function passStringToWasm0(arg, malloc, realloc) {
153
- if (typeof(arg) !== 'string') throw new Error(`expected a string argument, found ${typeof(arg)}`);
154
127
  if (realloc === undefined) {
155
128
  const buf = cachedTextEncoder.encode(arg);
156
129
  const ptr = malloc(buf.length, 1) >>> 0;
@@ -178,7 +151,7 @@ function passStringToWasm0(arg, malloc, realloc) {
178
151
  ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
179
152
  const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
180
153
  const ret = cachedTextEncoder.encodeInto(arg, view);
181
- if (ret.read !== arg.length) throw new Error('failed to pass whole string');
154
+
182
155
  offset += ret.written;
183
156
  ptr = realloc(ptr, len, offset, 1) >>> 0;
184
157
  }
@@ -227,6 +200,7 @@ let WASM_VECTOR_LEN = 0;
227
200
  * @param {number} section_height
228
201
  * @param {number} world_min_y
229
202
  * @param {number} world_max_y
203
+ * @param {number} section_data_start_y
230
204
  * @param {Uint16Array} block_states
231
205
  * @param {Uint8Array} block_light
232
206
  * @param {Uint8Array} sky_light
@@ -241,13 +215,7 @@ let WASM_VECTOR_LEN = 0;
241
215
  * @param {number} sky_light_value
242
216
  * @returns {any}
243
217
  */
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
- _assertNum(section_x);
246
- _assertNum(section_y);
247
- _assertNum(section_z);
248
- _assertNum(section_height);
249
- _assertNum(world_min_y);
250
- _assertNum(world_max_y);
218
+ 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) {
251
219
  const ptr0 = passArray16ToWasm0(block_states, wasm.__wbindgen_malloc);
252
220
  const len0 = WASM_VECTOR_LEN;
253
221
  const ptr1 = passArray8ToWasm0(block_light, wasm.__wbindgen_malloc);
@@ -266,10 +234,7 @@ export function generate_geometry(section_x, section_y, section_z, section_heigh
266
234
  const len7 = WASM_VECTOR_LEN;
267
235
  const ptr8 = passArray16ToWasm0(occluding_blocks, wasm.__wbindgen_malloc);
268
236
  const len8 = WASM_VECTOR_LEN;
269
- _assertBoolean(enable_lighting);
270
- _assertBoolean(smooth_lighting);
271
- _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);
237
+ 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
238
  return ret;
274
239
  }
275
240
 
@@ -280,6 +245,7 @@ export function generate_geometry(section_x, section_y, section_z, section_heigh
280
245
  * @param {number} section_height
281
246
  * @param {number} world_min_y
282
247
  * @param {number} world_max_y
248
+ * @param {number} section_data_start_y
283
249
  * @param {Int32Array} chunk_xs
284
250
  * @param {Int32Array} chunk_zs
285
251
  * @param {Uint16Array} block_states
@@ -296,13 +262,7 @@ export function generate_geometry(section_x, section_y, section_z, section_heigh
296
262
  * @param {number} sky_light_value
297
263
  * @returns {any}
298
264
  */
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) {
300
- _assertNum(section_x);
301
- _assertNum(section_y);
302
- _assertNum(section_z);
303
- _assertNum(section_height);
304
- _assertNum(world_min_y);
305
- _assertNum(world_max_y);
265
+ 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) {
306
266
  const ptr0 = passArray32ToWasm0(chunk_xs, wasm.__wbindgen_malloc);
307
267
  const len0 = WASM_VECTOR_LEN;
308
268
  const ptr1 = passArray32ToWasm0(chunk_zs, wasm.__wbindgen_malloc);
@@ -325,10 +285,7 @@ export function generate_geometry_multi(section_x, section_y, section_z, section
325
285
  const len9 = WASM_VECTOR_LEN;
326
286
  const ptr10 = passArray16ToWasm0(occluding_blocks, wasm.__wbindgen_malloc);
327
287
  const len10 = WASM_VECTOR_LEN;
328
- _assertBoolean(enable_lighting);
329
- _assertBoolean(smooth_lighting);
330
- _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);
288
+ 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
289
  return ret;
333
290
  }
334
291
 
@@ -367,10 +324,10 @@ async function __wbg_load(module, imports) {
367
324
  function __wbg_get_imports() {
368
325
  const imports = {};
369
326
  imports.wbg = {};
370
- imports.wbg.__wbg_Error_52673b7de5a0ca89 = function() { return logError(function (arg0, arg1) {
327
+ imports.wbg.__wbg_Error_52673b7de5a0ca89 = function(arg0, arg1) {
371
328
  const ret = Error(getStringFromWasm0(arg0, arg1));
372
329
  return ret;
373
- }, arguments) };
330
+ };
374
331
  imports.wbg.__wbg___wbindgen_debug_string_adfb662ae34724b6 = function(arg0, arg1) {
375
332
  const ret = debugString(arg1);
376
333
  const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@@ -381,35 +338,35 @@ function __wbg_get_imports() {
381
338
  imports.wbg.__wbg___wbindgen_throw_dd24417ed36fc46e = function(arg0, arg1) {
382
339
  throw new Error(getStringFromWasm0(arg0, arg1));
383
340
  };
384
- imports.wbg.__wbg_new_1ba21ce319a06297 = function() { return logError(function () {
341
+ imports.wbg.__wbg_new_1ba21ce319a06297 = function() {
385
342
  const ret = new Object();
386
343
  return ret;
387
- }, arguments) };
388
- imports.wbg.__wbg_new_25f239778d6112b9 = function() { return logError(function () {
344
+ };
345
+ imports.wbg.__wbg_new_25f239778d6112b9 = function() {
389
346
  const ret = new Array();
390
347
  return ret;
391
- }, arguments) };
392
- imports.wbg.__wbg_set_3f1d0b984ed272ed = function() { return logError(function (arg0, arg1, arg2) {
348
+ };
349
+ imports.wbg.__wbg_set_3f1d0b984ed272ed = function(arg0, arg1, arg2) {
393
350
  arg0[arg1] = arg2;
394
- }, arguments) };
395
- imports.wbg.__wbg_set_7df433eea03a5c14 = function() { return logError(function (arg0, arg1, arg2) {
351
+ };
352
+ imports.wbg.__wbg_set_7df433eea03a5c14 = function(arg0, arg1, arg2) {
396
353
  arg0[arg1 >>> 0] = arg2;
397
- }, arguments) };
398
- imports.wbg.__wbindgen_cast_2241b6af4c4b2941 = function() { return logError(function (arg0, arg1) {
354
+ };
355
+ imports.wbg.__wbindgen_cast_2241b6af4c4b2941 = function(arg0, arg1) {
399
356
  // Cast intrinsic for `Ref(String) -> Externref`.
400
357
  const ret = getStringFromWasm0(arg0, arg1);
401
358
  return ret;
402
- }, arguments) };
403
- imports.wbg.__wbindgen_cast_4625c577ab2ec9ee = function() { return logError(function (arg0) {
359
+ };
360
+ imports.wbg.__wbindgen_cast_4625c577ab2ec9ee = function(arg0) {
404
361
  // Cast intrinsic for `U64 -> Externref`.
405
362
  const ret = BigInt.asUintN(64, arg0);
406
363
  return ret;
407
- }, arguments) };
408
- imports.wbg.__wbindgen_cast_d6cd19b81560fd6e = function() { return logError(function (arg0) {
364
+ };
365
+ imports.wbg.__wbindgen_cast_d6cd19b81560fd6e = function(arg0) {
409
366
  // Cast intrinsic for `F64 -> Externref`.
410
367
  const ret = arg0;
411
368
  return ret;
412
- }, arguments) };
369
+ };
413
370
  imports.wbg.__wbindgen_init_externref_table = function() {
414
371
  const table = wasm.__wbindgen_externrefs;
415
372
  const offset = table.grow(4);