minerender 2.1.0-alpha.87 → 2.1.0-alpha.88
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.
- package/dist/browser/index.d.mts +92 -3
- package/dist/browser/index.d.ts +92 -3
- package/dist/browser/index.js +502 -184
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +502 -185
- package/dist/browser/index.mjs.map +1 -1
- package/dist/browser/section.worker.js +119 -0
- package/dist/browser/section.worker.js.map +1 -0
- package/dist/browser/section.worker.mjs +119 -0
- package/dist/browser/section.worker.mjs.map +1 -0
- package/dist/bundle.js +511 -187
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +91 -3
- package/dist/node/index.d.ts +91 -3
- package/dist/node/index.js +498 -184
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +494 -184
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/bundle.js
CHANGED
|
@@ -39810,6 +39810,23 @@ void main() {
|
|
|
39810
39810
|
setTimeout(() => resolve(), timeout);
|
|
39811
39811
|
});
|
|
39812
39812
|
}
|
|
39813
|
+
function yieldToEventLoop() {
|
|
39814
|
+
const scheduler = globalThis.scheduler;
|
|
39815
|
+
if (scheduler?.yield) return scheduler.yield();
|
|
39816
|
+
return new Promise((resolve) => {
|
|
39817
|
+
if (typeof MessageChannel !== "undefined") {
|
|
39818
|
+
const channel = new MessageChannel();
|
|
39819
|
+
channel.port1.onmessage = () => {
|
|
39820
|
+
channel.port1.close();
|
|
39821
|
+
channel.port2.close();
|
|
39822
|
+
resolve();
|
|
39823
|
+
};
|
|
39824
|
+
channel.port2.postMessage(void 0);
|
|
39825
|
+
} else {
|
|
39826
|
+
setTimeout(resolve, 0);
|
|
39827
|
+
}
|
|
39828
|
+
});
|
|
39829
|
+
}
|
|
39813
39830
|
function clampRotationDegrees(deg) {
|
|
39814
39831
|
return deg % 360;
|
|
39815
39832
|
}
|
|
@@ -99623,7 +99640,7 @@ return ${compiler2.callType("value", tagType)}
|
|
|
99623
99640
|
});
|
|
99624
99641
|
|
|
99625
99642
|
// ../../node_modules/@zip.js/zip.js/lib/zip-fs.js
|
|
99626
|
-
var
|
|
99643
|
+
var import_meta2, baseURL;
|
|
99627
99644
|
var init_zip_fs = __esm({
|
|
99628
99645
|
"../../node_modules/@zip.js/zip.js/lib/zip-fs.js"() {
|
|
99629
99646
|
init_dirname();
|
|
@@ -99638,9 +99655,9 @@ return ${compiler2.callType("value", tagType)}
|
|
|
99638
99655
|
init_zip_reader();
|
|
99639
99656
|
init_zip_writer();
|
|
99640
99657
|
init_zip_fs_core();
|
|
99641
|
-
|
|
99658
|
+
import_meta2 = {};
|
|
99642
99659
|
try {
|
|
99643
|
-
baseURL =
|
|
99660
|
+
baseURL = import_meta2.url;
|
|
99644
99661
|
} catch (_4) {
|
|
99645
99662
|
}
|
|
99646
99663
|
configure({ baseURL });
|
|
@@ -106568,6 +106585,7 @@ ${shader.fragmentShader}`.replace(
|
|
|
106568
106585
|
SchematicParser: () => SchematicParser,
|
|
106569
106586
|
SectionMesh: () => SectionMesh,
|
|
106570
106587
|
SectionModels: () => SectionModels,
|
|
106588
|
+
SectionWorker: () => SectionWorker,
|
|
106571
106589
|
SkinImage: () => SkinImage,
|
|
106572
106590
|
SkinObject: () => SkinObject,
|
|
106573
106591
|
SkinPart: () => SkinPart,
|
|
@@ -106592,6 +106610,7 @@ ${shader.fragmentShader}`.replace(
|
|
|
106592
106610
|
axisToVec3: () => axisToVec3,
|
|
106593
106611
|
base64decode: () => base64decode,
|
|
106594
106612
|
base64encode: () => base64encode,
|
|
106613
|
+
buildSectionGeometry: () => buildSectionGeometry,
|
|
106595
106614
|
capeTextureSizes: () => capeTextureSizes,
|
|
106596
106615
|
captureException: () => captureException,
|
|
106597
106616
|
changeEvent: () => changeEvent,
|
|
@@ -106644,6 +106663,7 @@ ${shader.fragmentShader}`.replace(
|
|
|
106644
106663
|
sampleEntityAnimation: () => sampleEntityAnimation,
|
|
106645
106664
|
sampleEntityKeyframes: () => sampleEntityKeyframes,
|
|
106646
106665
|
sampleFluid: () => sampleFluid,
|
|
106666
|
+
sectionGeometryTransferables: () => sectionGeometryTransferables,
|
|
106647
106667
|
serializeBoxGeometryKey: () => serializeBoxGeometryKey,
|
|
106648
106668
|
serializeImageKey: () => serializeImageKey,
|
|
106649
106669
|
serializeMaterialKey: () => serializeMaterialKey,
|
|
@@ -106661,7 +106681,8 @@ ${shader.fragmentShader}`.replace(
|
|
|
106661
106681
|
toDegrees: () => toDegrees,
|
|
106662
106682
|
toRadians: () => toRadians,
|
|
106663
106683
|
toTrianglesDrawMode: () => toTrianglesDrawMode,
|
|
106664
|
-
trimCanvas: () => trimCanvas
|
|
106684
|
+
trimCanvas: () => trimCanvas,
|
|
106685
|
+
yieldToEventLoop: () => yieldToEventLoop
|
|
106665
106686
|
});
|
|
106666
106687
|
init_dirname();
|
|
106667
106688
|
init_buffer2();
|
|
@@ -106762,6 +106783,7 @@ ${shader.fragmentShader}`.replace(
|
|
|
106762
106783
|
}
|
|
106763
106784
|
|
|
106764
106785
|
// src/env/browser/BrowserEnv.ts
|
|
106786
|
+
var import_meta = {};
|
|
106765
106787
|
var BrowserEnv = class {
|
|
106766
106788
|
constructor() {
|
|
106767
106789
|
this.name = "browser";
|
|
@@ -106789,6 +106811,14 @@ ${shader.fragmentShader}`.replace(
|
|
|
106789
106811
|
version: version3
|
|
106790
106812
|
}));
|
|
106791
106813
|
}
|
|
106814
|
+
createWorker(name2) {
|
|
106815
|
+
if (name2 !== "section" || typeof Worker === "undefined") return void 0;
|
|
106816
|
+
try {
|
|
106817
|
+
return new Worker(new URL("./section.worker.mjs", import_meta.url), { type: "module" });
|
|
106818
|
+
} catch {
|
|
106819
|
+
return void 0;
|
|
106820
|
+
}
|
|
106821
|
+
}
|
|
106792
106822
|
};
|
|
106793
106823
|
function registerBrowserEnv() {
|
|
106794
106824
|
const env3 = new BrowserEnv();
|
|
@@ -118755,6 +118785,16 @@ gl_FragDepth=readDepth(vUv);
|
|
|
118755
118785
|
init_buffer2();
|
|
118756
118786
|
init_process2();
|
|
118757
118787
|
init_AssetKey();
|
|
118788
|
+
var blockKeys = /* @__PURE__ */ new Map();
|
|
118789
|
+
function blockKey(type) {
|
|
118790
|
+
let key = blockKeys.get(type);
|
|
118791
|
+
if (!key) {
|
|
118792
|
+
key = AssetKey.parse("blockstates", type);
|
|
118793
|
+
if (blockKeys.size >= 4096) blockKeys.clear();
|
|
118794
|
+
blockKeys.set(type, key);
|
|
118795
|
+
}
|
|
118796
|
+
return key;
|
|
118797
|
+
}
|
|
118758
118798
|
var ChunkData = class _ChunkData {
|
|
118759
118799
|
constructor() {
|
|
118760
118800
|
this.indices = new Uint16Array(4096);
|
|
@@ -118782,10 +118822,10 @@ gl_FragDepth=readDepth(vUv);
|
|
|
118782
118822
|
let key;
|
|
118783
118823
|
let nbt;
|
|
118784
118824
|
if (block && !_ChunkData.isAir(block)) {
|
|
118785
|
-
const type =
|
|
118825
|
+
const type = blockKey(block.type).toNamespacedString();
|
|
118786
118826
|
const properties = Object.fromEntries(Object.keys(block.properties ?? {}).sort().map((name2) => [name2, block.properties[name2]]));
|
|
118787
118827
|
state = Object.freeze(Object.keys(properties).length ? { type, properties: Object.freeze(properties) } : { type });
|
|
118788
|
-
key =
|
|
118828
|
+
key = _ChunkData.paletteKey(block);
|
|
118789
118829
|
if (block.nbt !== void 0) nbt = structuredClone(block.nbt);
|
|
118790
118830
|
}
|
|
118791
118831
|
const previousId = this.indices[index];
|
|
@@ -118822,9 +118862,14 @@ gl_FragDepth=readDepth(vUv);
|
|
|
118822
118862
|
}
|
|
118823
118863
|
static isAir(block) {
|
|
118824
118864
|
if (typeof block === "undefined" || typeof block.type === "undefined") return true;
|
|
118825
|
-
const key =
|
|
118865
|
+
const key = blockKey(block.type);
|
|
118826
118866
|
return key.namespace === "minecraft" && !key.type && ["air", "cave_air", "void_air"].includes(key.path);
|
|
118827
118867
|
}
|
|
118868
|
+
/** Identifies a normalized block type and its sorted properties, excluding per-cell NBT. */
|
|
118869
|
+
static paletteKey(block) {
|
|
118870
|
+
const properties = Object.fromEntries(Object.keys(block.properties ?? {}).sort().map((name2) => [name2, block.properties[name2]]));
|
|
118871
|
+
return JSON.stringify([blockKey(block.type).toNamespacedString(), properties]);
|
|
118872
|
+
}
|
|
118828
118873
|
static copyBlock(state, nbt) {
|
|
118829
118874
|
const block = { type: state.type };
|
|
118830
118875
|
if (state.properties) block.properties = { ...state.properties };
|
|
@@ -119004,14 +119049,17 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119004
119049
|
const perLong = Math.floor(64 / bits2);
|
|
119005
119050
|
const expected = padded ? Math.ceil(4096 / perLong) : Math.ceil(4096 * bits2 / 64);
|
|
119006
119051
|
if (tag.value.length !== expected) throw new MineRenderError(`Invalid Anvil block-state array length: expected ${expected}`);
|
|
119007
|
-
const words = tag.value.map(([high, low]) =>
|
|
119008
|
-
const mask = (
|
|
119052
|
+
const words = tag.value.map(([high, low]) => [high >>> 0, low >>> 0]);
|
|
119053
|
+
const mask = (1 << bits2) - 1;
|
|
119009
119054
|
for (let index = 0; index < 4096; index++) {
|
|
119010
|
-
const
|
|
119011
|
-
const
|
|
119012
|
-
|
|
119013
|
-
|
|
119014
|
-
|
|
119055
|
+
const bitPos = index * bits2;
|
|
119056
|
+
const word = padded ? Math.floor(index / perLong) : bitPos >>> 6;
|
|
119057
|
+
const shift = padded ? index % perLong * bits2 : bitPos & 63;
|
|
119058
|
+
const [high, low] = words[word];
|
|
119059
|
+
let value = shift < 32 ? low >>> shift : high >>> shift - 32;
|
|
119060
|
+
if (shift < 32 && shift + bits2 > 32) value += high * 2 ** (32 - shift);
|
|
119061
|
+
if (!padded && shift + bits2 > 64) value += words[word + 1][1] * 2 ** (64 - shift);
|
|
119062
|
+
indices[index] = value & mask;
|
|
119015
119063
|
}
|
|
119016
119064
|
return indices;
|
|
119017
119065
|
}
|
|
@@ -119167,7 +119215,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119167
119215
|
init_process2();
|
|
119168
119216
|
init_three_module();
|
|
119169
119217
|
init_Model();
|
|
119170
|
-
|
|
119218
|
+
init_util();
|
|
119171
119219
|
init_AssetKey();
|
|
119172
119220
|
init_BlockStates();
|
|
119173
119221
|
init_CubeFace();
|
|
@@ -119315,7 +119363,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119315
119363
|
* Places a structure's blocks at their stored positions, then refreshes neighboring faces.
|
|
119316
119364
|
* Entity NBT is retained by the structure but is not rendered.
|
|
119317
119365
|
*
|
|
119318
|
-
* @param useBatches -
|
|
119366
|
+
* @param useBatches - Yields between chunks by default. Set to `false` for sequential placement.
|
|
119319
119367
|
* @param executor - Optional queue for batched placement. The caller remains responsible for stopping it.
|
|
119320
119368
|
*/
|
|
119321
119369
|
async placeMultiBlock(multiblock, useBatches = true, executor) {
|
|
@@ -119332,8 +119380,10 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119332
119380
|
};
|
|
119333
119381
|
const place = (block) => this.placeBlock(new Vector3(...block.position), block, collect);
|
|
119334
119382
|
const keys = /* @__PURE__ */ new Map();
|
|
119383
|
+
const types2 = /* @__PURE__ */ new Set();
|
|
119335
119384
|
for (const block of multiblock.blocks) {
|
|
119336
|
-
if (Chunk.isAir(block)) continue;
|
|
119385
|
+
if (Chunk.isAir(block) || types2.has(block.type)) continue;
|
|
119386
|
+
types2.add(block.type);
|
|
119337
119387
|
const key = AssetKey.parse("blockstates", block.type);
|
|
119338
119388
|
keys.set(key.serialize(), key);
|
|
119339
119389
|
}
|
|
@@ -119342,6 +119392,23 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119342
119392
|
for (const block of multiblock.blocks) await place(block);
|
|
119343
119393
|
return;
|
|
119344
119394
|
}
|
|
119395
|
+
if (!executor) {
|
|
119396
|
+
const groups2 = /* @__PURE__ */ new Map();
|
|
119397
|
+
const position = new Vector3();
|
|
119398
|
+
for (const block of multiblock.blocks) {
|
|
119399
|
+
const [x4, y5, z4] = block.position;
|
|
119400
|
+
this.validatePosBounds(position.set(x4, y5, z4));
|
|
119401
|
+
const cx = Math.floor(x4 / 16), cy = Math.floor(y5 / 16), cz = Math.floor(z4 / 16);
|
|
119402
|
+
const key = `${cx}_${cy}_${cz}`;
|
|
119403
|
+
const chunk = this._chunks.get(key) ?? (Chunk.isAir(block) ? void 0 : this.getOrCreateChunkAt(position));
|
|
119404
|
+
if (!chunk) continue;
|
|
119405
|
+
let group = groups2.get(chunk);
|
|
119406
|
+
if (!group) groups2.set(chunk, group = []);
|
|
119407
|
+
group.push({ index: (y5 - cy * 16) * 256 + (z4 - cz * 16) * 16 + x4 - cx * 16, block });
|
|
119408
|
+
}
|
|
119409
|
+
await this.placeChunkGroups(groups2, changes);
|
|
119410
|
+
return;
|
|
119411
|
+
}
|
|
119345
119412
|
const positions = /* @__PURE__ */ new Map();
|
|
119346
119413
|
for (const block of multiblock.blocks) {
|
|
119347
119414
|
const key = block.position.join(",");
|
|
@@ -119350,19 +119417,34 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119350
119417
|
else positions.set(key, [block]);
|
|
119351
119418
|
}
|
|
119352
119419
|
const groups = [...positions.values()];
|
|
119353
|
-
|
|
119354
|
-
|
|
119355
|
-
|
|
119356
|
-
|
|
119357
|
-
|
|
119358
|
-
|
|
119359
|
-
|
|
119360
|
-
|
|
119361
|
-
|
|
119362
|
-
|
|
119420
|
+
for (let i4 = 0; i4 < groups.length; i4 += executor.batch) {
|
|
119421
|
+
const results = await Promise.allSettled(groups.slice(i4, i4 + executor.batch).map(
|
|
119422
|
+
(blocks) => executor.submit(async () => {
|
|
119423
|
+
for (const block of blocks) await place(block);
|
|
119424
|
+
})
|
|
119425
|
+
));
|
|
119426
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
119427
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
119428
|
+
}
|
|
119429
|
+
}
|
|
119430
|
+
async placeChunkGroups(groups, changes) {
|
|
119431
|
+
let sliceStart = performance.now();
|
|
119432
|
+
for (const [chunk, blocks] of groups) {
|
|
119433
|
+
let positions;
|
|
119434
|
+
try {
|
|
119435
|
+
positions = await chunk.placeBlocks(blocks);
|
|
119436
|
+
} finally {
|
|
119437
|
+
positions ?? (positions = blocks.map(({ index }) => new Vector3(
|
|
119438
|
+
chunk.x * 16 + index % 16,
|
|
119439
|
+
chunk.y * 16 + Math.floor(index / 256),
|
|
119440
|
+
chunk.z * 16 + Math.floor(index / 16) % 16
|
|
119441
|
+
)));
|
|
119442
|
+
for (const pos of positions) changes.set(`${pos.x},${pos.y},${pos.z}`, pos);
|
|
119443
|
+
}
|
|
119444
|
+
if (performance.now() - sliceStart > 8) {
|
|
119445
|
+
await yieldToEventLoop();
|
|
119446
|
+
sliceStart = performance.now();
|
|
119363
119447
|
}
|
|
119364
|
-
} finally {
|
|
119365
|
-
if (!executor) queue2.stop();
|
|
119366
119448
|
}
|
|
119367
119449
|
}
|
|
119368
119450
|
/** Replaces one chunk column's blocks. Entity NBT remains available on the parsed chunk. */
|
|
@@ -119370,7 +119452,24 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119370
119452
|
const changes = /* @__PURE__ */ new Map();
|
|
119371
119453
|
try {
|
|
119372
119454
|
await this.clearChunkColumn(chunk.x, chunk.z, changes);
|
|
119455
|
+
const groups = /* @__PURE__ */ new Map();
|
|
119373
119456
|
for (const section of chunk.sections) {
|
|
119457
|
+
if (!executor) {
|
|
119458
|
+
const blocks2 = [];
|
|
119459
|
+
for (let index = 0; index < 4096; index++) {
|
|
119460
|
+
const block = section.data.get(index);
|
|
119461
|
+
if (block) blocks2.push({ index, block });
|
|
119462
|
+
}
|
|
119463
|
+
if (blocks2.length) {
|
|
119464
|
+
const position = new Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
|
|
119465
|
+
this.validatePosBounds(position);
|
|
119466
|
+
const target = this.getOrCreateChunkAt(position);
|
|
119467
|
+
const previous = groups.get(target);
|
|
119468
|
+
if (previous) previous.push(...blocks2);
|
|
119469
|
+
else groups.set(target, blocks2);
|
|
119470
|
+
}
|
|
119471
|
+
continue;
|
|
119472
|
+
}
|
|
119374
119473
|
const blocks = [];
|
|
119375
119474
|
for (let index = 0; index < 4096; index++) {
|
|
119376
119475
|
const block = section.data.get(index);
|
|
@@ -119385,6 +119484,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119385
119484
|
}
|
|
119386
119485
|
await this.placeBlocks({ size: [16, 16, 16], blocks }, true, executor, changes);
|
|
119387
119486
|
}
|
|
119487
|
+
if (!executor) await this.placeChunkGroups(groups, changes);
|
|
119388
119488
|
} finally {
|
|
119389
119489
|
await this.updateCulling([...changes.values()]);
|
|
119390
119490
|
}
|
|
@@ -119425,19 +119525,23 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119425
119525
|
this.sectionModels?.clear();
|
|
119426
119526
|
}
|
|
119427
119527
|
updateCulling(positions) {
|
|
119528
|
+
const neighbor = new Vector3();
|
|
119428
119529
|
for (const pos of positions) {
|
|
119429
|
-
|
|
119430
|
-
|
|
119431
|
-
|
|
119432
|
-
this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
|
|
119433
|
-
}
|
|
119530
|
+
const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
|
|
119531
|
+
const chunk = this._chunks.get(`${cx}_${cy}_${cz}`);
|
|
119532
|
+
const lx = pos.x - cx * 16, ly = pos.y - cy * 16, lz = pos.z - cz * 16;
|
|
119434
119533
|
for (let y5 = -1; y5 <= 1; y5++) {
|
|
119435
119534
|
for (let z4 = -1; z4 <= 1; z4++) {
|
|
119436
119535
|
for (let x4 = -1; x4 <= 1; x4++) {
|
|
119437
|
-
const
|
|
119438
|
-
|
|
119439
|
-
|
|
119440
|
-
|
|
119536
|
+
const nx = lx + x4, ny = ly + y5, nz = lz + z4;
|
|
119537
|
+
const section = nx >= 0 && nx < 16 && ny >= 0 && ny < 16 && nz >= 0 && nz < 16 ? chunk : this._chunks.get(`${cx + Math.floor(nx / 16)}_${cy + Math.floor(ny / 16)}_${cz + Math.floor(nz / 16)}`);
|
|
119538
|
+
if (!section) continue;
|
|
119539
|
+
const index = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
|
|
119540
|
+
let pending = this.pendingCulling.get(section);
|
|
119541
|
+
if (pending?.has(index)) continue;
|
|
119542
|
+
if (Math.abs(x4) + Math.abs(y5) + Math.abs(z4) > 1 && !section.getBlockAt(neighbor.set(pos.x + x4, pos.y + y5, pos.z + z4))?.object?.fluidKind) continue;
|
|
119543
|
+
if (!pending) this.pendingCulling.set(section, pending = /* @__PURE__ */ new Set());
|
|
119544
|
+
pending.add(index);
|
|
119441
119545
|
}
|
|
119442
119546
|
}
|
|
119443
119547
|
}
|
|
@@ -119445,39 +119549,38 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119445
119549
|
return this.culling ?? (this.culling = Promise.resolve().then(async () => {
|
|
119446
119550
|
try {
|
|
119447
119551
|
while (this.pendingCulling.size) {
|
|
119448
|
-
const batch = [...this.pendingCulling
|
|
119552
|
+
const batch = [...this.pendingCulling];
|
|
119449
119553
|
this.pendingCulling.clear();
|
|
119450
|
-
const
|
|
119451
|
-
|
|
119452
|
-
|
|
119453
|
-
|
|
119454
|
-
|
|
119455
|
-
|
|
119456
|
-
|
|
119457
|
-
|
|
119458
|
-
|
|
119459
|
-
|
|
119460
|
-
|
|
119461
|
-
|
|
119462
|
-
|
|
119463
|
-
|
|
119464
|
-
|
|
119465
|
-
|
|
119466
|
-
|
|
119467
|
-
|
|
119468
|
-
|
|
119469
|
-
|
|
119470
|
-
|
|
119471
|
-
|
|
119472
|
-
|
|
119473
|
-
|
|
119474
|
-
|
|
119475
|
-
mask |= 1 << face;
|
|
119554
|
+
for (const [chunk, indices] of batch) {
|
|
119555
|
+
for (const index of indices) {
|
|
119556
|
+
if (!chunk.isBlockVisibleIndex(index)) continue;
|
|
119557
|
+
const lx = index % 16, ly = Math.floor(index / 256), lz = Math.floor(index / 16) % 16;
|
|
119558
|
+
const wx = chunk.x * 16 + lx, wy = chunk.y * 16 + ly, wz = chunk.z * 16 + lz;
|
|
119559
|
+
const block = chunk.getBlockAt(neighbor.set(wx, wy, wz));
|
|
119560
|
+
if (block.object?.fluidKind) {
|
|
119561
|
+
await block.object.updateFluid((x4, y5, z4) => {
|
|
119562
|
+
const nx = lx + x4, ny = ly + y5, nz = lz + z4;
|
|
119563
|
+
const section = nx >= 0 && nx < 16 && ny >= 0 && ny < 16 && nz >= 0 && nz < 16 ? chunk : this._chunks.get(`${chunk.x + Math.floor(nx / 16)}_${chunk.y + Math.floor(ny / 16)}_${chunk.z + Math.floor(nz / 16)}`);
|
|
119564
|
+
const neighborIndex = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
|
|
119565
|
+
const object3 = section?.isBlockVisibleIndex(neighborIndex) ? section.getBlockAt(neighbor.set(wx + x4, wy + y5, wz + z4))?.object : void 0;
|
|
119566
|
+
return {
|
|
119567
|
+
fluid: object3?.fluidKind,
|
|
119568
|
+
level: object3?.fluidLevel,
|
|
119569
|
+
solid: section?.isOccludingIndex(neighborIndex) ?? false
|
|
119570
|
+
};
|
|
119571
|
+
});
|
|
119572
|
+
}
|
|
119573
|
+
let mask = 0;
|
|
119574
|
+
for (let face = 0; face < CUBE_FACE_OFFSETS.length; face++) {
|
|
119575
|
+
const offset = CUBE_FACE_OFFSETS[face];
|
|
119576
|
+
const nx = lx + offset[0], ny = ly + offset[1], nz = lz + offset[2];
|
|
119577
|
+
const section = nx >= 0 && nx < 16 && ny >= 0 && ny < 16 && nz >= 0 && nz < 16 ? chunk : this._chunks.get(`${chunk.x + Math.floor(nx / 16)}_${chunk.y + Math.floor(ny / 16)}_${chunk.z + Math.floor(nz / 16)}`);
|
|
119578
|
+
if (section?.isOccludingIndex((ny & 15) * 256 + (nz & 15) * 16 + (nx & 15))) mask |= 1 << face;
|
|
119476
119579
|
}
|
|
119580
|
+
await chunk.setCullMaskIndex(index, mask);
|
|
119477
119581
|
}
|
|
119478
|
-
await chunk.setCullMaskAt(pos, mask);
|
|
119479
119582
|
}
|
|
119480
|
-
|
|
119583
|
+
await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
|
|
119481
119584
|
}
|
|
119482
119585
|
} finally {
|
|
119483
119586
|
this.culling = void 0;
|
|
@@ -119542,7 +119645,234 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119542
119645
|
init_process2();
|
|
119543
119646
|
init_three_module();
|
|
119544
119647
|
init_CanvasCompat();
|
|
119648
|
+
init_CubeFace();
|
|
119545
119649
|
init_Materials();
|
|
119650
|
+
|
|
119651
|
+
// src/world/SectionGeometry.ts
|
|
119652
|
+
init_dirname();
|
|
119653
|
+
init_buffer2();
|
|
119654
|
+
init_process2();
|
|
119655
|
+
init_CubeFace();
|
|
119656
|
+
function buildSectionGeometry(input) {
|
|
119657
|
+
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize } = input;
|
|
119658
|
+
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
119659
|
+
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
119660
|
+
const visible = [];
|
|
119661
|
+
const visibleAtlases = /* @__PURE__ */ new Set();
|
|
119662
|
+
for (let entry = 0; entry < count; entry++) {
|
|
119663
|
+
const template = templateData[templates[entry]];
|
|
119664
|
+
if (!template.cullFaces.some((direction) => !(cullMasks[entry] & direction))) continue;
|
|
119665
|
+
visible.push(entry);
|
|
119666
|
+
visibleAtlases.add(template.atlas);
|
|
119667
|
+
}
|
|
119668
|
+
const pages = [];
|
|
119669
|
+
const locations = /* @__PURE__ */ new Map();
|
|
119670
|
+
for (const atlas of [...visibleAtlases].sort((a4, b4) => atlases[b4].height - atlases[a4].height)) {
|
|
119671
|
+
const { width, height } = atlases[atlas];
|
|
119672
|
+
if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
|
|
119673
|
+
let selected = -1;
|
|
119674
|
+
for (let i4 = 0; i4 < pages.length; i4++) {
|
|
119675
|
+
const page2 = pages[i4];
|
|
119676
|
+
const nextRow = page2.x + width > maxAtlasSize;
|
|
119677
|
+
if ((nextRow ? page2.y + page2.rowHeight : page2.y) + height > maxAtlasSize) continue;
|
|
119678
|
+
if (nextRow) {
|
|
119679
|
+
page2.y += page2.rowHeight;
|
|
119680
|
+
page2.x = 0;
|
|
119681
|
+
page2.rowHeight = 0;
|
|
119682
|
+
}
|
|
119683
|
+
selected = i4;
|
|
119684
|
+
break;
|
|
119685
|
+
}
|
|
119686
|
+
if (selected < 0) {
|
|
119687
|
+
selected = pages.length;
|
|
119688
|
+
pages.push({ placements: [], entries: [], x: 0, y: 0, rowHeight: 0, width: 0, height: 0 });
|
|
119689
|
+
}
|
|
119690
|
+
const page = pages[selected];
|
|
119691
|
+
page.placements.push({ atlas, x: page.x, y: page.y });
|
|
119692
|
+
locations.set(atlas, { page: selected, x: page.x, y: page.y });
|
|
119693
|
+
page.x += width;
|
|
119694
|
+
page.rowHeight = Math.max(page.rowHeight, height);
|
|
119695
|
+
page.width = Math.max(page.width, page.x);
|
|
119696
|
+
page.height = Math.max(page.height, page.y + height);
|
|
119697
|
+
}
|
|
119698
|
+
for (const entry of visible) pages[locations.get(templateData[templates[entry]].atlas).page].entries.push(entry);
|
|
119699
|
+
return pages.map((page) => {
|
|
119700
|
+
let faces = 0;
|
|
119701
|
+
for (const entry of page.entries) {
|
|
119702
|
+
const template = templateData[templates[entry]];
|
|
119703
|
+
for (let face = 0; face < CUBE_FACES.length; face++) {
|
|
119704
|
+
if (!(cullMasks[entry] & template.cullFaces[face])) faces++;
|
|
119705
|
+
}
|
|
119706
|
+
}
|
|
119707
|
+
const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
|
|
119708
|
+
const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
|
|
119709
|
+
const outputIndices = new Uint32Array(faces * 6);
|
|
119710
|
+
let vertex2 = 0, indexOffset = 0;
|
|
119711
|
+
for (const entry of page.entries) {
|
|
119712
|
+
const template = templateData[templates[entry]];
|
|
119713
|
+
const atlas = atlases[template.atlas];
|
|
119714
|
+
const placement = locations.get(template.atlas);
|
|
119715
|
+
const mapU = (u4) => (placement.x + u4 * atlas.width) / page.width;
|
|
119716
|
+
const mapV = (v5) => 1 - (placement.y + (1 - v5) * atlas.height) / page.height;
|
|
119717
|
+
const offsetX = indices[entry] % 16 * 16;
|
|
119718
|
+
const offsetY = Math.floor(indices[entry] / 256) * 16;
|
|
119719
|
+
const offsetZ = Math.floor(indices[entry] / 16) % 16 * 16;
|
|
119720
|
+
for (let face = 0; face < CUBE_FACES.length; face++) {
|
|
119721
|
+
if (cullMasks[entry] & template.cullFaces[face]) continue;
|
|
119722
|
+
const start = vertex2;
|
|
119723
|
+
for (let corner = 0; corner < 4; corner++, vertex2++) {
|
|
119724
|
+
const source = face * 4 + corner;
|
|
119725
|
+
positions[vertex2 * 3] = template.positions[source * 3] + offsetX;
|
|
119726
|
+
positions[vertex2 * 3 + 1] = template.positions[source * 3 + 1] + offsetY;
|
|
119727
|
+
positions[vertex2 * 3 + 2] = template.positions[source * 3 + 2] + offsetZ;
|
|
119728
|
+
normals[vertex2 * 3] = template.normals[source * 3];
|
|
119729
|
+
normals[vertex2 * 3 + 1] = template.normals[source * 3 + 1];
|
|
119730
|
+
normals[vertex2 * 3 + 2] = template.normals[source * 3 + 2];
|
|
119731
|
+
uvs[vertex2 * 2] = mapU(template.uvs[source * 2]);
|
|
119732
|
+
uvs[vertex2 * 2 + 1] = mapV(template.uvs[source * 2 + 1]);
|
|
119733
|
+
uvBounds[vertex2 * 4] = mapU(template.uvBounds[source * 4]);
|
|
119734
|
+
uvBounds[vertex2 * 4 + 1] = mapV(template.uvBounds[source * 4 + 1]);
|
|
119735
|
+
uvBounds[vertex2 * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);
|
|
119736
|
+
uvBounds[vertex2 * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);
|
|
119737
|
+
colors[vertex2 * 3] = template.colors[source * 3];
|
|
119738
|
+
colors[vertex2 * 3 + 1] = template.colors[source * 3 + 1];
|
|
119739
|
+
colors[vertex2 * 3 + 2] = template.colors[source * 3 + 2];
|
|
119740
|
+
}
|
|
119741
|
+
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[face * 6 + corner] - face * 4;
|
|
119742
|
+
}
|
|
119743
|
+
}
|
|
119744
|
+
return { width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices };
|
|
119745
|
+
});
|
|
119746
|
+
}
|
|
119747
|
+
function sectionGeometryTransferables(pages) {
|
|
119748
|
+
return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer]);
|
|
119749
|
+
}
|
|
119750
|
+
|
|
119751
|
+
// src/world/SectionWorker.ts
|
|
119752
|
+
init_dirname();
|
|
119753
|
+
init_buffer2();
|
|
119754
|
+
init_process2();
|
|
119755
|
+
init_Env();
|
|
119756
|
+
var _SectionWorker = class _SectionWorker {
|
|
119757
|
+
constructor(worker) {
|
|
119758
|
+
this.worker = worker;
|
|
119759
|
+
this.nextId = 0;
|
|
119760
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
119761
|
+
worker.addEventListener("message", (event) => {
|
|
119762
|
+
const reply = event.data;
|
|
119763
|
+
const pending = this.pending.get(reply.id);
|
|
119764
|
+
if (!pending) return;
|
|
119765
|
+
this.pending.delete(reply.id);
|
|
119766
|
+
if (reply.type === "pages") pending.resolve(reply.pages);
|
|
119767
|
+
else pending.reject(new Error(reply.message));
|
|
119768
|
+
});
|
|
119769
|
+
worker.addEventListener("error", (event) => this.fail(event.message || "Section worker failed"));
|
|
119770
|
+
worker.addEventListener("messageerror", () => this.fail("Section worker message could not be deserialized"));
|
|
119771
|
+
}
|
|
119772
|
+
/** The shared worker, or undefined when the environment has none or a previous worker failed. */
|
|
119773
|
+
static shared() {
|
|
119774
|
+
if (!this.initialized) {
|
|
119775
|
+
this.initialized = true;
|
|
119776
|
+
const worker = Env.provider.createWorker?.("section");
|
|
119777
|
+
if (worker) this.instance = new _SectionWorker(worker);
|
|
119778
|
+
}
|
|
119779
|
+
return this.instance;
|
|
119780
|
+
}
|
|
119781
|
+
/** Builds geometry without transferring the input buffers away from the caller. */
|
|
119782
|
+
build(input) {
|
|
119783
|
+
if (!this.worker) return Promise.reject(new Error("Section worker terminated"));
|
|
119784
|
+
return new Promise((resolve, reject) => {
|
|
119785
|
+
const id = this.nextId++;
|
|
119786
|
+
this.pending.set(id, { resolve, reject });
|
|
119787
|
+
this.worker.postMessage({ id, type: "build", input });
|
|
119788
|
+
});
|
|
119789
|
+
}
|
|
119790
|
+
/** Rejects pending builds, terminates the worker, and makes shared() return undefined. */
|
|
119791
|
+
terminate() {
|
|
119792
|
+
this.fail("Section worker terminated");
|
|
119793
|
+
}
|
|
119794
|
+
fail(message) {
|
|
119795
|
+
const error2 = new Error(message);
|
|
119796
|
+
for (const pending of this.pending.values()) pending.reject(error2);
|
|
119797
|
+
this.pending.clear();
|
|
119798
|
+
this.worker?.terminate();
|
|
119799
|
+
this.worker = void 0;
|
|
119800
|
+
_SectionWorker.instance = void 0;
|
|
119801
|
+
}
|
|
119802
|
+
};
|
|
119803
|
+
_SectionWorker.initialized = false;
|
|
119804
|
+
var SectionWorker = _SectionWorker;
|
|
119805
|
+
|
|
119806
|
+
// src/world/SectionMesh.ts
|
|
119807
|
+
var templateCache = /* @__PURE__ */ new WeakMap();
|
|
119808
|
+
function toInput(entries, maxAtlasSize) {
|
|
119809
|
+
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
119810
|
+
const atlases = [];
|
|
119811
|
+
const atlasIds = /* @__PURE__ */ new Map();
|
|
119812
|
+
const templateIds = /* @__PURE__ */ new Map();
|
|
119813
|
+
const input = {
|
|
119814
|
+
count: entries.length,
|
|
119815
|
+
indices: new Uint16Array(entries.length),
|
|
119816
|
+
templates: new Uint16Array(entries.length),
|
|
119817
|
+
cullMasks: new Uint8Array(entries.length),
|
|
119818
|
+
templateData: [],
|
|
119819
|
+
atlases: [],
|
|
119820
|
+
maxAtlasSize
|
|
119821
|
+
};
|
|
119822
|
+
for (let i4 = 0; i4 < entries.length; i4++) {
|
|
119823
|
+
const { index, template, cullMask } = entries[i4];
|
|
119824
|
+
let id = templateIds.get(template);
|
|
119825
|
+
if (id === void 0) {
|
|
119826
|
+
let atlas = atlasIds.get(template.atlas);
|
|
119827
|
+
if (atlas === void 0) {
|
|
119828
|
+
atlas = atlases.length;
|
|
119829
|
+
atlasIds.set(template.atlas, atlas);
|
|
119830
|
+
atlases.push(template.atlas);
|
|
119831
|
+
input.atlases.push({ width: template.atlas.image.width, height: template.atlas.image.height });
|
|
119832
|
+
}
|
|
119833
|
+
let data = templateCache.get(template);
|
|
119834
|
+
if (!data) {
|
|
119835
|
+
data = {
|
|
119836
|
+
positions: new Float32Array(72),
|
|
119837
|
+
normals: new Float32Array(72),
|
|
119838
|
+
uvs: new Float32Array(48),
|
|
119839
|
+
uvBounds: new Float32Array(96),
|
|
119840
|
+
colors: new Float32Array(72),
|
|
119841
|
+
indices: new Uint16Array(36),
|
|
119842
|
+
cullFaces: new Uint8Array(template.cullFaces),
|
|
119843
|
+
atlas: 0
|
|
119844
|
+
};
|
|
119845
|
+
const position = template.geometry.getAttribute("position");
|
|
119846
|
+
const normal = template.geometry.getAttribute("normal");
|
|
119847
|
+
const uv = template.geometry.getAttribute("uv");
|
|
119848
|
+
const bounds = template.geometry.getAttribute("uvBounds");
|
|
119849
|
+
const color3 = template.geometry.getAttribute("color");
|
|
119850
|
+
for (let vertex2 = 0; vertex2 < CUBE_FACES.length * 4; vertex2++) {
|
|
119851
|
+
data.positions.set([position.getX(vertex2), position.getY(vertex2), position.getZ(vertex2)], vertex2 * 3);
|
|
119852
|
+
data.normals.set([normal.getX(vertex2), normal.getY(vertex2), normal.getZ(vertex2)], vertex2 * 3);
|
|
119853
|
+
data.uvs.set([uv.getX(vertex2), uv.getY(vertex2)], vertex2 * 2);
|
|
119854
|
+
data.uvBounds.set([
|
|
119855
|
+
bounds?.getX(vertex2) ?? 0,
|
|
119856
|
+
bounds?.getY(vertex2) ?? 0,
|
|
119857
|
+
bounds?.getZ(vertex2) ?? 1,
|
|
119858
|
+
bounds?.getW(vertex2) ?? 1
|
|
119859
|
+
], vertex2 * 4);
|
|
119860
|
+
data.colors.set([color3?.getX(vertex2) ?? 1, color3?.getY(vertex2) ?? 1, color3?.getZ(vertex2) ?? 1], vertex2 * 3);
|
|
119861
|
+
}
|
|
119862
|
+
const indices = template.geometry.getIndex();
|
|
119863
|
+
for (let i5 = 0; i5 < data.indices.length; i5++) data.indices[i5] = indices.getX(i5);
|
|
119864
|
+
templateCache.set(template, data);
|
|
119865
|
+
}
|
|
119866
|
+
id = input.templateData.length;
|
|
119867
|
+
templateIds.set(template, id);
|
|
119868
|
+
input.templateData.push({ ...data, atlas });
|
|
119869
|
+
}
|
|
119870
|
+
input.indices[i4] = index;
|
|
119871
|
+
input.templates[i4] = id;
|
|
119872
|
+
input.cullMasks[i4] = cullMask;
|
|
119873
|
+
}
|
|
119874
|
+
return { input, atlases };
|
|
119875
|
+
}
|
|
119546
119876
|
var SectionMesh = class _SectionMesh extends Group {
|
|
119547
119877
|
constructor() {
|
|
119548
119878
|
super(...arguments);
|
|
@@ -119550,86 +119880,31 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119550
119880
|
}
|
|
119551
119881
|
/** Builds section-local meshes from visible cube faces. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
119552
119882
|
static build(entries, maxAtlasSize = 2048) {
|
|
119553
|
-
|
|
119554
|
-
|
|
119555
|
-
|
|
119556
|
-
|
|
119557
|
-
|
|
119558
|
-
|
|
119559
|
-
|
|
119560
|
-
|
|
119561
|
-
|
|
119562
|
-
|
|
119563
|
-
|
|
119564
|
-
if ((nextRow ? page.y + page.rowHeight : page.y) + height > maxAtlasSize) continue;
|
|
119565
|
-
if (nextRow) {
|
|
119566
|
-
page.y += page.rowHeight;
|
|
119567
|
-
page.x = 0;
|
|
119568
|
-
page.rowHeight = 0;
|
|
119569
|
-
}
|
|
119570
|
-
selected = page;
|
|
119571
|
-
break;
|
|
119572
|
-
}
|
|
119573
|
-
if (!selected) {
|
|
119574
|
-
selected = { placements: [], entries: [], x: 0, y: 0, rowHeight: 0, width: 0, height: 0 };
|
|
119575
|
-
pages.push(selected);
|
|
119576
|
-
}
|
|
119577
|
-
const placement = { atlas, x: selected.x, y: selected.y };
|
|
119578
|
-
selected.placements.push(placement);
|
|
119579
|
-
selected.x += width;
|
|
119580
|
-
selected.rowHeight = Math.max(selected.rowHeight, height);
|
|
119581
|
-
selected.width = Math.max(selected.width, selected.x);
|
|
119582
|
-
selected.height = Math.max(selected.height, selected.y + height);
|
|
119583
|
-
locations.set(atlas, { page: selected, placement });
|
|
119584
|
-
}
|
|
119585
|
-
for (const entry of visible) locations.get(entry.template.atlas).page.entries.push(entry);
|
|
119883
|
+
const { input, atlases } = toInput(entries, maxAtlasSize);
|
|
119884
|
+
return this.fromPages(buildSectionGeometry(input), atlases);
|
|
119885
|
+
}
|
|
119886
|
+
/** Builds section-local meshes in a browser worker when available, with synchronous fallback. */
|
|
119887
|
+
static async buildAsync(entries, maxAtlasSize = 2048) {
|
|
119888
|
+
const { input, atlases } = toInput(entries, maxAtlasSize);
|
|
119889
|
+
const worker = SectionWorker.shared();
|
|
119890
|
+
const pages = worker ? await worker.build(input).catch(() => buildSectionGeometry(input)) : buildSectionGeometry(input);
|
|
119891
|
+
return this.fromPages(pages, atlases);
|
|
119892
|
+
}
|
|
119893
|
+
static fromPages(pages, atlases) {
|
|
119586
119894
|
const section = new _SectionMesh();
|
|
119587
119895
|
for (const page of pages) {
|
|
119588
119896
|
const canvas = createCanvas(page.width, page.height);
|
|
119589
119897
|
const context = canvas.getContext("2d");
|
|
119590
119898
|
for (const { atlas, x: x4, y: y5 } of page.placements) {
|
|
119591
|
-
context.drawImage(atlas.image.canvas, x4, y5);
|
|
119592
|
-
}
|
|
119593
|
-
const positions = [], normals = [], uvs = [], uvBounds = [], colors = [], indices = [];
|
|
119594
|
-
for (const { index, template, cullMask } of page.entries) {
|
|
119595
|
-
const position = template.geometry.getAttribute("position");
|
|
119596
|
-
const normal = template.geometry.getAttribute("normal");
|
|
119597
|
-
const uv = template.geometry.getAttribute("uv");
|
|
119598
|
-
const bounds = template.geometry.getAttribute("uvBounds");
|
|
119599
|
-
const color3 = template.geometry.getAttribute("color");
|
|
119600
|
-
const sourceIndices = template.geometry.getIndex();
|
|
119601
|
-
const placement = locations.get(template.atlas).placement;
|
|
119602
|
-
const mapU = (u4) => (placement.x + u4 * template.atlas.image.width) / page.width;
|
|
119603
|
-
const mapV = (v5) => 1 - (placement.y + (1 - v5) * template.atlas.image.height) / page.height;
|
|
119604
|
-
const offsetX = index % 16 * 16;
|
|
119605
|
-
const offsetY = Math.floor(index / 256) * 16;
|
|
119606
|
-
const offsetZ = Math.floor(index / 16) % 16 * 16;
|
|
119607
|
-
for (let face = 0; face < 6; face++) {
|
|
119608
|
-
if (cullMask & template.cullFaces[face]) continue;
|
|
119609
|
-
const start = positions.length / 3;
|
|
119610
|
-
for (let corner = 0; corner < 4; corner++) {
|
|
119611
|
-
const vertex2 = face * 4 + corner;
|
|
119612
|
-
positions.push(position.getX(vertex2) + offsetX, position.getY(vertex2) + offsetY, position.getZ(vertex2) + offsetZ);
|
|
119613
|
-
normals.push(normal.getX(vertex2), normal.getY(vertex2), normal.getZ(vertex2));
|
|
119614
|
-
uvs.push(mapU(uv.getX(vertex2)), mapV(uv.getY(vertex2)));
|
|
119615
|
-
uvBounds.push(
|
|
119616
|
-
mapU(bounds?.getX(vertex2) ?? 0),
|
|
119617
|
-
mapV(bounds?.getY(vertex2) ?? 0),
|
|
119618
|
-
mapU(bounds?.getZ(vertex2) ?? 1),
|
|
119619
|
-
mapV(bounds?.getW(vertex2) ?? 1)
|
|
119620
|
-
);
|
|
119621
|
-
colors.push(color3?.getX(vertex2) ?? 1, color3?.getY(vertex2) ?? 1, color3?.getZ(vertex2) ?? 1);
|
|
119622
|
-
}
|
|
119623
|
-
for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
|
|
119624
|
-
}
|
|
119899
|
+
context.drawImage(atlases[atlas].image.canvas, x4, y5);
|
|
119625
119900
|
}
|
|
119626
119901
|
const geometry = new BufferGeometry();
|
|
119627
|
-
geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
|
|
119628
|
-
geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3));
|
|
119629
|
-
geometry.setAttribute("uv", new Float32BufferAttribute(uvs, 2));
|
|
119630
|
-
geometry.setAttribute("uvBounds", new Float32BufferAttribute(uvBounds, 4));
|
|
119631
|
-
geometry.setAttribute("color", new Float32BufferAttribute(colors, 3));
|
|
119632
|
-
geometry.setIndex(indices);
|
|
119902
|
+
geometry.setAttribute("position", new Float32BufferAttribute(page.positions.buffer, 3));
|
|
119903
|
+
geometry.setAttribute("normal", new Float32BufferAttribute(page.normals.buffer, 3));
|
|
119904
|
+
geometry.setAttribute("uv", new Float32BufferAttribute(page.uvs.buffer, 2));
|
|
119905
|
+
geometry.setAttribute("uvBounds", new Float32BufferAttribute(page.uvBounds.buffer, 4));
|
|
119906
|
+
geometry.setAttribute("color", new Float32BufferAttribute(page.colors.buffer, 3));
|
|
119907
|
+
geometry.setIndex(new Uint32BufferAttribute(page.indices.buffer, 1));
|
|
119633
119908
|
geometry.computeBoundingBox();
|
|
119634
119909
|
geometry.computeBoundingSphere();
|
|
119635
119910
|
const material = Materials.createShadedCanvasMaterial(canvas, false, false, true);
|
|
@@ -119663,7 +119938,9 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119663
119938
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
119664
119939
|
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
119665
119940
|
this.hiddenBlocks = /* @__PURE__ */ new Set();
|
|
119941
|
+
this.blockPosition = new Vector3();
|
|
119666
119942
|
this.meshDirty = false;
|
|
119943
|
+
this.meshGeneration = 0;
|
|
119667
119944
|
this.scene = scene;
|
|
119668
119945
|
this.x = x4;
|
|
119669
119946
|
this.y = y5;
|
|
@@ -119676,7 +119953,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119676
119953
|
if (isTripleArray(posOrX)) {
|
|
119677
119954
|
return this.getBlockAt(new Vector3(posOrX[0], posOrX[1], posOrX[2]));
|
|
119678
119955
|
}
|
|
119679
|
-
const pos = this.
|
|
119956
|
+
const pos = this.blockPosition.set(posOrX.x - this.x * 16, posOrX.y - this.y * 16, posOrX.z - this.z * 16);
|
|
119680
119957
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
119681
119958
|
return this.renderedBlocks.get(index);
|
|
119682
119959
|
}
|
|
@@ -119700,48 +119977,81 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119700
119977
|
worldPos = this.chunkPosToWorldPos(pos);
|
|
119701
119978
|
}
|
|
119702
119979
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
119703
|
-
this.hiddenBlocks.delete(index);
|
|
119704
|
-
this.data.set(index, block);
|
|
119705
|
-
const readBlock = this.data.snapshot(index);
|
|
119706
|
-
this.renderedBlocks.get(index)?.object?.removeFromScene();
|
|
119707
|
-
if (this.sectionBlocks.delete(index)) this.meshDirty = true;
|
|
119708
|
-
this.renderedBlocks.delete(index);
|
|
119709
|
-
let object3;
|
|
119710
119980
|
try {
|
|
119711
|
-
|
|
119712
|
-
|
|
119713
|
-
const blockState = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
|
|
119714
|
-
if (!blockState) {
|
|
119715
|
-
this.data.set(index, void 0);
|
|
119716
|
-
return void 0;
|
|
119717
|
-
}
|
|
119718
|
-
const perBlock = !this.sectionModels || getFluidKind(blockState.key, stored.properties) || blockState.key && BlockEntities.entry(await BlockEntities.getIndex(blockState.key.root), blockState.key.toNamespacedString());
|
|
119719
|
-
const template = perBlock ? void 0 : await this.sectionModels.get(blockState, stored.properties);
|
|
119720
|
-
if (template) {
|
|
119721
|
-
this.sectionBlocks.set(index, { index, template, cullMask: 0 });
|
|
119722
|
-
this.meshDirty = true;
|
|
119723
|
-
} else {
|
|
119724
|
-
object3 = await this.scene.addBlock(blockState, {
|
|
119725
|
-
mergeMeshes: true,
|
|
119726
|
-
instanceMeshes: true,
|
|
119727
|
-
maxInstanceCount: 2e3,
|
|
119728
|
-
initialState: stored.properties
|
|
119729
|
-
});
|
|
119730
|
-
object3.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
|
|
119731
|
-
}
|
|
119732
|
-
const info = { get block() {
|
|
119733
|
-
return readBlock();
|
|
119734
|
-
}, object: object3 };
|
|
119735
|
-
this.renderedBlocks.set(index, info);
|
|
119736
|
-
return info;
|
|
119737
|
-
} catch (error2) {
|
|
119738
|
-
this.data.set(index, void 0);
|
|
119739
|
-
object3?.removeFromScene();
|
|
119740
|
-
throw error2;
|
|
119981
|
+
await this.placeBlocks([{ index, block }]);
|
|
119982
|
+
return this.renderedBlocks.get(index);
|
|
119741
119983
|
} finally {
|
|
119742
119984
|
await onBlocksChanged?.([worldPos]);
|
|
119743
119985
|
}
|
|
119744
119986
|
}
|
|
119987
|
+
/** Places cells in input order and returns changed world positions without refreshing neighbors. */
|
|
119988
|
+
async placeBlocks(blocks) {
|
|
119989
|
+
const resolutions = /* @__PURE__ */ new Map();
|
|
119990
|
+
for (const { block } of blocks) {
|
|
119991
|
+
if (!block || ChunkData.isAir(block)) continue;
|
|
119992
|
+
const key = ChunkData.paletteKey(block);
|
|
119993
|
+
if (resolutions.has(key)) continue;
|
|
119994
|
+
const stored = { type: block.type, properties: block.properties ? { ...block.properties } : void 0 };
|
|
119995
|
+
const resolved = (async () => {
|
|
119996
|
+
const blockState = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
|
|
119997
|
+
const perBlock = !blockState || !this.sectionModels || !!getFluidKind(blockState.key, stored.properties) || !!(blockState.key && BlockEntities.entry(await BlockEntities.getIndex(blockState.key.root), blockState.key.toNamespacedString()));
|
|
119998
|
+
if (!perBlock) await this.sectionModels.get(blockState, stored.properties);
|
|
119999
|
+
return { blockState, perBlock };
|
|
120000
|
+
})();
|
|
120001
|
+
resolutions.set(key, resolved);
|
|
120002
|
+
void resolved.catch(() => void 0);
|
|
120003
|
+
}
|
|
120004
|
+
const positions = [];
|
|
120005
|
+
let failed = false, failure;
|
|
120006
|
+
for (const { index, block } of blocks) {
|
|
120007
|
+
this.hiddenBlocks.delete(index);
|
|
120008
|
+
this.data.set(index, block);
|
|
120009
|
+
const readBlock = this.data.snapshot(index);
|
|
120010
|
+
this.renderedBlocks.get(index)?.object?.removeFromScene();
|
|
120011
|
+
if (this.sectionBlocks.delete(index)) this.meshDirty = true;
|
|
120012
|
+
this.renderedBlocks.delete(index);
|
|
120013
|
+
const worldPos = new Vector3(
|
|
120014
|
+
this.x * 16 + index % 16,
|
|
120015
|
+
this.y * 16 + Math.floor(index / 256),
|
|
120016
|
+
this.z * 16 + Math.floor(index / 16) % 16
|
|
120017
|
+
);
|
|
120018
|
+
positions.push(worldPos);
|
|
120019
|
+
let object3;
|
|
120020
|
+
try {
|
|
120021
|
+
if (!readBlock) continue;
|
|
120022
|
+
const stored = readBlock();
|
|
120023
|
+
const key = ChunkData.paletteKey(stored);
|
|
120024
|
+
const { blockState, perBlock } = await resolutions.get(key);
|
|
120025
|
+
if (!blockState) {
|
|
120026
|
+
this.data.set(index, void 0);
|
|
120027
|
+
continue;
|
|
120028
|
+
}
|
|
120029
|
+
const template = perBlock ? void 0 : await this.sectionModels.get(blockState, stored.properties);
|
|
120030
|
+
if (template) {
|
|
120031
|
+
this.sectionBlocks.set(index, { index, template, cullMask: 0 });
|
|
120032
|
+
this.meshDirty = true;
|
|
120033
|
+
} else {
|
|
120034
|
+
object3 = await this.scene.addBlock(blockState, {
|
|
120035
|
+
mergeMeshes: true,
|
|
120036
|
+
instanceMeshes: true,
|
|
120037
|
+
maxInstanceCount: 2e3,
|
|
120038
|
+
initialState: stored.properties
|
|
120039
|
+
});
|
|
120040
|
+
object3.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
|
|
120041
|
+
}
|
|
120042
|
+
this.renderedBlocks.set(index, { get block() {
|
|
120043
|
+
return readBlock();
|
|
120044
|
+
}, object: object3 });
|
|
120045
|
+
} catch (error2) {
|
|
120046
|
+
this.data.set(index, void 0);
|
|
120047
|
+
object3?.removeFromScene();
|
|
120048
|
+
if (!failed) failure = error2;
|
|
120049
|
+
failed = true;
|
|
120050
|
+
}
|
|
120051
|
+
}
|
|
120052
|
+
if (failed) throw failure;
|
|
120053
|
+
return positions;
|
|
120054
|
+
}
|
|
119745
120055
|
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
119746
120056
|
async setBlockVisibleAt(pos, visible) {
|
|
119747
120057
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
@@ -119762,15 +120072,24 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119762
120072
|
await this.onBlocksChanged?.([pos]);
|
|
119763
120073
|
}
|
|
119764
120074
|
isBlockVisibleAt(pos) {
|
|
119765
|
-
|
|
120075
|
+
return this.isBlockVisibleIndex(_Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos)));
|
|
120076
|
+
}
|
|
120077
|
+
/** Reports whether a cell has a visible render object or section entry. */
|
|
120078
|
+
isBlockVisibleIndex(index) {
|
|
119766
120079
|
return this.renderedBlocks.has(index) && !this.hiddenBlocks.has(index);
|
|
119767
120080
|
}
|
|
119768
120081
|
isOccludingAt(pos) {
|
|
119769
|
-
|
|
120082
|
+
return this.isOccludingIndex(_Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos)));
|
|
120083
|
+
}
|
|
120084
|
+
/** Reports whether a visible cell hides neighboring cube faces. */
|
|
120085
|
+
isOccludingIndex(index) {
|
|
119770
120086
|
return !this.hiddenBlocks.has(index) && (this.sectionBlocks.has(index) || (this.renderedBlocks.get(index)?.object?.isOccluding ?? false));
|
|
119771
120087
|
}
|
|
119772
120088
|
async setCullMaskAt(pos, mask) {
|
|
119773
|
-
|
|
120089
|
+
await this.setCullMaskIndex(_Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos)), mask);
|
|
120090
|
+
}
|
|
120091
|
+
/** Updates hidden faces for a cell's section entry or individual render object. */
|
|
120092
|
+
async setCullMaskIndex(index, mask) {
|
|
119774
120093
|
const entry = this.sectionBlocks.get(index);
|
|
119775
120094
|
if (entry) {
|
|
119776
120095
|
if (entry.cullMask !== mask) {
|
|
@@ -119781,12 +120100,17 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119781
120100
|
await this.renderedBlocks.get(index)?.object?.setCullMask(mask);
|
|
119782
120101
|
}
|
|
119783
120102
|
}
|
|
119784
|
-
|
|
120103
|
+
/** Rebuilds visible section geometry and discards results superseded by another rebuild or clear. */
|
|
120104
|
+
async rebuildSectionMesh() {
|
|
119785
120105
|
if (!this.meshDirty) return;
|
|
119786
|
-
|
|
119787
|
-
|
|
119788
|
-
|
|
119789
|
-
) : void 0;
|
|
120106
|
+
this.meshDirty = false;
|
|
120107
|
+
const generation = ++this.meshGeneration;
|
|
120108
|
+
const entries = [...this.sectionBlocks.values()].filter((entry) => !this.hiddenBlocks.has(entry.index));
|
|
120109
|
+
const next = entries.length ? await SectionMesh.buildAsync(entries, this.sectionModels.maxAtlasSize) : void 0;
|
|
120110
|
+
if (generation !== this.meshGeneration) {
|
|
120111
|
+
next?.dispose();
|
|
120112
|
+
return;
|
|
120113
|
+
}
|
|
119790
120114
|
this.sectionMesh?.dispose();
|
|
119791
120115
|
this.sectionMesh = next;
|
|
119792
120116
|
if (next) {
|
|
@@ -119794,7 +120118,6 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119794
120118
|
this.scene.add(next);
|
|
119795
120119
|
}
|
|
119796
120120
|
this.scene.dirty = true;
|
|
119797
|
-
this.meshDirty = false;
|
|
119798
120121
|
}
|
|
119799
120122
|
/** Removes stored blocks and their render objects, then notifies the owning world of changed positions. */
|
|
119800
120123
|
async clear(onBlocksChanged = this.onBlocksChanged) {
|
|
@@ -119803,6 +120126,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119803
120126
|
));
|
|
119804
120127
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
119805
120128
|
this.sectionBlocks.clear();
|
|
120129
|
+
this.meshGeneration++;
|
|
119806
120130
|
this.sectionMesh?.dispose();
|
|
119807
120131
|
this.sectionMesh = void 0;
|
|
119808
120132
|
this.meshDirty = false;
|