minerender 2.1.0-alpha.87 → 2.1.0-alpha.89
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 +102 -3
- package/dist/browser/index.d.ts +102 -3
- package/dist/browser/index.js +683 -213
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +683 -214
- 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 +700 -221
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +101 -3
- package/dist/node/index.d.ts +101 -3
- package/dist/node/index.js +680 -213
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +675 -213
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/bundle.js
CHANGED
|
@@ -21996,8 +21996,8 @@ var MineRender = (() => {
|
|
|
21996
21996
|
}
|
|
21997
21997
|
}
|
|
21998
21998
|
}
|
|
21999
|
-
function vertexAttribPointer(index, size, type, normalized, stride, offset,
|
|
22000
|
-
if (
|
|
21999
|
+
function vertexAttribPointer(index, size, type, normalized, stride, offset, integer3) {
|
|
22000
|
+
if (integer3 === true) {
|
|
22001
22001
|
gl.vertexAttribIPointer(index, size, type, stride, offset);
|
|
22002
22002
|
} else {
|
|
22003
22003
|
gl.vertexAttribPointer(index, size, type, normalized, stride, offset);
|
|
@@ -22024,7 +22024,7 @@ var MineRender = (() => {
|
|
|
22024
22024
|
const buffer2 = attribute.buffer;
|
|
22025
22025
|
const type = attribute.type;
|
|
22026
22026
|
const bytesPerElement = attribute.bytesPerElement;
|
|
22027
|
-
const
|
|
22027
|
+
const integer3 = type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType;
|
|
22028
22028
|
if (geometryAttribute.isInterleavedBufferAttribute) {
|
|
22029
22029
|
const data = geometryAttribute.data;
|
|
22030
22030
|
const stride = data.stride;
|
|
@@ -22050,7 +22050,7 @@ var MineRender = (() => {
|
|
|
22050
22050
|
normalized,
|
|
22051
22051
|
stride * bytesPerElement,
|
|
22052
22052
|
(offset + size / programAttribute.locationSize * i4) * bytesPerElement,
|
|
22053
|
-
|
|
22053
|
+
integer3
|
|
22054
22054
|
);
|
|
22055
22055
|
}
|
|
22056
22056
|
} else {
|
|
@@ -22075,7 +22075,7 @@ var MineRender = (() => {
|
|
|
22075
22075
|
normalized,
|
|
22076
22076
|
size * bytesPerElement,
|
|
22077
22077
|
size / programAttribute.locationSize * i4 * bytesPerElement,
|
|
22078
|
-
|
|
22078
|
+
integer3
|
|
22079
22079
|
);
|
|
22080
22080
|
}
|
|
22081
22081
|
}
|
|
@@ -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,12 +106585,14 @@ ${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,
|
|
106574
106592
|
SkinTextures: () => SkinTextures,
|
|
106575
106593
|
Skins: () => Skins,
|
|
106576
106594
|
SpecialItems: () => SpecialItems,
|
|
106595
|
+
SpongeSchematicParser: () => SpongeSchematicParser,
|
|
106577
106596
|
StructureParser: () => StructureParser,
|
|
106578
106597
|
TextureAtlas: () => TextureAtlas,
|
|
106579
106598
|
TextureLoader: () => TextureLoader2,
|
|
@@ -106592,6 +106611,7 @@ ${shader.fragmentShader}`.replace(
|
|
|
106592
106611
|
axisToVec3: () => axisToVec3,
|
|
106593
106612
|
base64decode: () => base64decode,
|
|
106594
106613
|
base64encode: () => base64encode,
|
|
106614
|
+
buildSectionGeometry: () => buildSectionGeometry,
|
|
106595
106615
|
capeTextureSizes: () => capeTextureSizes,
|
|
106596
106616
|
captureException: () => captureException,
|
|
106597
106617
|
changeEvent: () => changeEvent,
|
|
@@ -106644,6 +106664,7 @@ ${shader.fragmentShader}`.replace(
|
|
|
106644
106664
|
sampleEntityAnimation: () => sampleEntityAnimation,
|
|
106645
106665
|
sampleEntityKeyframes: () => sampleEntityKeyframes,
|
|
106646
106666
|
sampleFluid: () => sampleFluid,
|
|
106667
|
+
sectionGeometryTransferables: () => sectionGeometryTransferables,
|
|
106647
106668
|
serializeBoxGeometryKey: () => serializeBoxGeometryKey,
|
|
106648
106669
|
serializeImageKey: () => serializeImageKey,
|
|
106649
106670
|
serializeMaterialKey: () => serializeMaterialKey,
|
|
@@ -106661,7 +106682,8 @@ ${shader.fragmentShader}`.replace(
|
|
|
106661
106682
|
toDegrees: () => toDegrees,
|
|
106662
106683
|
toRadians: () => toRadians,
|
|
106663
106684
|
toTrianglesDrawMode: () => toTrianglesDrawMode,
|
|
106664
|
-
trimCanvas: () => trimCanvas
|
|
106685
|
+
trimCanvas: () => trimCanvas,
|
|
106686
|
+
yieldToEventLoop: () => yieldToEventLoop
|
|
106665
106687
|
});
|
|
106666
106688
|
init_dirname();
|
|
106667
106689
|
init_buffer2();
|
|
@@ -106762,6 +106784,7 @@ ${shader.fragmentShader}`.replace(
|
|
|
106762
106784
|
}
|
|
106763
106785
|
|
|
106764
106786
|
// src/env/browser/BrowserEnv.ts
|
|
106787
|
+
var import_meta = {};
|
|
106765
106788
|
var BrowserEnv = class {
|
|
106766
106789
|
constructor() {
|
|
106767
106790
|
this.name = "browser";
|
|
@@ -106789,6 +106812,14 @@ ${shader.fragmentShader}`.replace(
|
|
|
106789
106812
|
version: version3
|
|
106790
106813
|
}));
|
|
106791
106814
|
}
|
|
106815
|
+
createWorker(name2) {
|
|
106816
|
+
if (name2 !== "section" || typeof Worker === "undefined") return void 0;
|
|
106817
|
+
try {
|
|
106818
|
+
return new Worker(new URL("./section.worker.mjs", import_meta.url), { type: "module" });
|
|
106819
|
+
} catch {
|
|
106820
|
+
return void 0;
|
|
106821
|
+
}
|
|
106822
|
+
}
|
|
106792
106823
|
};
|
|
106793
106824
|
function registerBrowserEnv() {
|
|
106794
106825
|
const env3 = new BrowserEnv();
|
|
@@ -111337,46 +111368,46 @@ property list uchar int vertex_index
|
|
|
111337
111368
|
}
|
|
111338
111369
|
var BlockStateResolver = class {
|
|
111339
111370
|
/** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
|
|
111340
|
-
static async defaults(
|
|
111341
|
-
const defaults =
|
|
111371
|
+
static async defaults(blockState2) {
|
|
111372
|
+
const defaults = blockState2.key ? await BlockStates.getDefaultState(blockState2.key) : void 0;
|
|
111342
111373
|
const state = {};
|
|
111343
111374
|
if (defaults && Object.keys(defaults).length > 0) {
|
|
111344
111375
|
for (const key in defaults) state[key] = defaults[key].default;
|
|
111345
|
-
} else if (
|
|
111346
|
-
const variant = Object.keys(
|
|
111376
|
+
} else if (blockState2.variants) {
|
|
111377
|
+
const variant = Object.keys(blockState2.variants)[0];
|
|
111347
111378
|
if (variant) {
|
|
111348
111379
|
for (const property of variant.split(",")) {
|
|
111349
111380
|
const [key, value] = property.split("=");
|
|
111350
111381
|
state[key] = value;
|
|
111351
111382
|
}
|
|
111352
111383
|
}
|
|
111353
|
-
} else if (
|
|
111354
|
-
const condition =
|
|
111384
|
+
} else if (blockState2.multipart) {
|
|
111385
|
+
const condition = blockState2.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
|
|
111355
111386
|
for (const [key, value] of Object.entries(condition ?? {})) state[key] = value.split("|")[0];
|
|
111356
111387
|
}
|
|
111357
111388
|
return state;
|
|
111358
111389
|
}
|
|
111359
111390
|
/** Selects matching models. Supply `choose` to control selection within each alternatives array. */
|
|
111360
|
-
static select(
|
|
111361
|
-
return this.matching(
|
|
111391
|
+
static select(blockState2, state, choose = this.choose) {
|
|
111392
|
+
return this.matching(blockState2, state).map(choose);
|
|
111362
111393
|
}
|
|
111363
111394
|
/** Returns matching model groups before choosing weighted alternatives. */
|
|
111364
|
-
static matching(
|
|
111395
|
+
static matching(blockState2, state) {
|
|
111365
111396
|
const out = [];
|
|
111366
|
-
if (
|
|
111367
|
-
if (Object.keys(
|
|
111368
|
-
out.push(
|
|
111397
|
+
if (blockState2.variants) {
|
|
111398
|
+
if (Object.keys(blockState2.variants).length === 1 && "" in blockState2.variants) {
|
|
111399
|
+
out.push(blockState2.variants[""]);
|
|
111369
111400
|
} else {
|
|
111370
|
-
for (const variantKey in
|
|
111401
|
+
for (const variantKey in blockState2.variants) {
|
|
111371
111402
|
const matches = variantKey.split(",").every((property) => {
|
|
111372
111403
|
const [key, value] = property.split("=");
|
|
111373
111404
|
return `${state[key]}` === `${value}`;
|
|
111374
111405
|
});
|
|
111375
|
-
if (matches) out.push(
|
|
111406
|
+
if (matches) out.push(blockState2.variants[variantKey]);
|
|
111376
111407
|
}
|
|
111377
111408
|
}
|
|
111378
|
-
} else if (
|
|
111379
|
-
for (const part of
|
|
111409
|
+
} else if (blockState2.multipart) {
|
|
111410
|
+
for (const part of blockState2.multipart) {
|
|
111380
111411
|
if (part.apply && (!part.when || matchesCondition(part.when, state))) {
|
|
111381
111412
|
out.push(part.apply);
|
|
111382
111413
|
}
|
|
@@ -111515,9 +111546,9 @@ property list uchar int vertex_index
|
|
|
111515
111546
|
init_FluidGeometry();
|
|
111516
111547
|
init_Entities();
|
|
111517
111548
|
var _BlockObject = class _BlockObject extends SceneObject {
|
|
111518
|
-
constructor(
|
|
111549
|
+
constructor(blockState2, options) {
|
|
111519
111550
|
super(options);
|
|
111520
|
-
this.blockState =
|
|
111551
|
+
this.blockState = blockState2;
|
|
111521
111552
|
this.isBlockObject = true;
|
|
111522
111553
|
this._previousState = {};
|
|
111523
111554
|
this._state = {};
|
|
@@ -113712,6 +113743,160 @@ property list uchar int vertex_index
|
|
|
113712
113743
|
throw new MineRenderError(`Schematic ${name2} must be a compound list`);
|
|
113713
113744
|
}
|
|
113714
113745
|
|
|
113746
|
+
// src/model/multiblock/SpongeSchematicParser.ts
|
|
113747
|
+
init_dirname();
|
|
113748
|
+
init_buffer2();
|
|
113749
|
+
init_process2();
|
|
113750
|
+
init_MineRenderError();
|
|
113751
|
+
var SpongeSchematicParser = class {
|
|
113752
|
+
/**
|
|
113753
|
+
* Parses decoded NBT with a local block palette, omitting air blocks.
|
|
113754
|
+
* Applies Offset to block and entity positions; size remains the source dimensions.
|
|
113755
|
+
* Biomes and metadata are not imported, and DataVersion does not trigger migration.
|
|
113756
|
+
*/
|
|
113757
|
+
static async parse(nbt) {
|
|
113758
|
+
const tags = nbt.value.Schematic === void 0 ? nbt.value : compound(nbt.value.Schematic, "Schematic");
|
|
113759
|
+
const version3 = integer2(tags.Version, "Version");
|
|
113760
|
+
if (version3 !== 2 && version3 !== 3) {
|
|
113761
|
+
throw new MineRenderError(`Unsupported Sponge schematic version ${version3}; expected 2 or 3`);
|
|
113762
|
+
}
|
|
113763
|
+
const dataVersion = integer2(tags.DataVersion, "DataVersion");
|
|
113764
|
+
const size = ["Width", "Height", "Length"].map((name2) => {
|
|
113765
|
+
const tag = tags[name2];
|
|
113766
|
+
if (tag?.type !== "short" || !Number.isInteger(tag.value) || tag.value < -32768 || tag.value > 65535 || tag.value === 0) {
|
|
113767
|
+
throw new MineRenderError(`Sponge schematic ${name2} must be a positive unsigned short`);
|
|
113768
|
+
}
|
|
113769
|
+
return tag.value & 65535;
|
|
113770
|
+
});
|
|
113771
|
+
const offset = tags.Offset === void 0 ? [0, 0, 0] : intPosition(tags.Offset, "Offset");
|
|
113772
|
+
const blocks = [];
|
|
113773
|
+
const container = version3 === 2 ? tags : tags.Blocks === void 0 ? void 0 : compound(tags.Blocks, "Blocks");
|
|
113774
|
+
if (container) {
|
|
113775
|
+
const paletteTag = container.Palette;
|
|
113776
|
+
if (!paletteTag) throw new MineRenderError("Sponge schematic requires a local Palette; global block IDs are not supported");
|
|
113777
|
+
const palette = /* @__PURE__ */ new Map();
|
|
113778
|
+
const paletteMax = version3 === 2 && tags.PaletteMax !== void 0 ? integer2(tags.PaletteMax, "PaletteMax") : void 0;
|
|
113779
|
+
if (paletteMax !== void 0 && paletteMax <= 0) throw new MineRenderError("Sponge schematic PaletteMax must be positive");
|
|
113780
|
+
for (const [state, tag] of Object.entries(compound(paletteTag, "Palette"))) {
|
|
113781
|
+
const id = integer2(tag, "Palette index");
|
|
113782
|
+
if (id < 0 || palette.has(id) || paletteMax !== void 0 && id >= paletteMax) {
|
|
113783
|
+
throw new MineRenderError(`Invalid or duplicate Sponge schematic palette index ${id}`);
|
|
113784
|
+
}
|
|
113785
|
+
palette.set(id, blockState(state));
|
|
113786
|
+
}
|
|
113787
|
+
const [width, height, length] = size;
|
|
113788
|
+
const volume = width * height * length;
|
|
113789
|
+
const data = container[version3 === 2 ? "BlockData" : "Data"];
|
|
113790
|
+
if (data?.type !== "byteArray" || !Array.isArray(data.value) || data.value.length < volume) {
|
|
113791
|
+
throw new MineRenderError(`Sponge schematic block data must contain ${volume} varints`);
|
|
113792
|
+
}
|
|
113793
|
+
const blockEntities = /* @__PURE__ */ new Map();
|
|
113794
|
+
for (const entity of compoundList2(container, "BlockEntities")) {
|
|
113795
|
+
const pos = intPosition(entity.Pos, "BlockEntities Pos");
|
|
113796
|
+
if (pos.some((value2, axis) => value2 < 0 || value2 >= size[axis])) {
|
|
113797
|
+
throw new MineRenderError("Sponge schematic block entity position is outside its dimensions");
|
|
113798
|
+
}
|
|
113799
|
+
const index = pos[0] + pos[2] * width + pos[1] * width * length;
|
|
113800
|
+
if (blockEntities.has(index)) throw new MineRenderError(`Duplicate Sponge schematic block entity at index ${index}`);
|
|
113801
|
+
const value = entityData(entity, version3);
|
|
113802
|
+
for (const [axis, name2] of ["x", "y", "z"].entries()) {
|
|
113803
|
+
value[name2] = { type: "int", value: pos[axis] + offset[axis] };
|
|
113804
|
+
}
|
|
113805
|
+
blockEntities.set(index, { type: "compound", value });
|
|
113806
|
+
}
|
|
113807
|
+
let cursor = 0;
|
|
113808
|
+
for (let index = 0; index < volume; index++) {
|
|
113809
|
+
let id = 0;
|
|
113810
|
+
for (let shift = 0; ; shift += 7) {
|
|
113811
|
+
const byte = data.value[cursor++];
|
|
113812
|
+
if (!Number.isInteger(byte) || byte < -128 || byte > 255) {
|
|
113813
|
+
throw new MineRenderError(`Invalid or truncated Sponge schematic varint at index ${index}`);
|
|
113814
|
+
}
|
|
113815
|
+
const unsigned = byte & 255;
|
|
113816
|
+
if (shift === 28 && unsigned > 7) {
|
|
113817
|
+
throw new MineRenderError(`Sponge schematic varint exceeds a nonnegative int at index ${index}`);
|
|
113818
|
+
}
|
|
113819
|
+
id += (unsigned & 127) * 2 ** shift;
|
|
113820
|
+
if ((unsigned & 128) === 0) break;
|
|
113821
|
+
}
|
|
113822
|
+
const state = palette.get(id);
|
|
113823
|
+
if (!state) throw new MineRenderError(`Sponge schematic palette index ${id} does not exist`);
|
|
113824
|
+
if (["minecraft:air", "minecraft:cave_air", "minecraft:void_air"].includes(state.type)) continue;
|
|
113825
|
+
blocks.push({
|
|
113826
|
+
type: state.type,
|
|
113827
|
+
properties: { ...state.properties },
|
|
113828
|
+
position: [
|
|
113829
|
+
index % width + offset[0],
|
|
113830
|
+
Math.floor(index / (width * length)) + offset[1],
|
|
113831
|
+
Math.floor(index / width) % length + offset[2]
|
|
113832
|
+
],
|
|
113833
|
+
nbt: blockEntities.get(index)
|
|
113834
|
+
});
|
|
113835
|
+
}
|
|
113836
|
+
if (cursor !== data.value.length) throw new MineRenderError("Sponge schematic block data has trailing bytes");
|
|
113837
|
+
}
|
|
113838
|
+
const entities = compoundList2(tags, "Entities").map((entity) => {
|
|
113839
|
+
const pos = entity.Pos;
|
|
113840
|
+
if (pos?.type !== "list" || pos.value.type !== "double" || pos.value.value.length !== 3 || !pos.value.value.every(Number.isFinite)) {
|
|
113841
|
+
throw new MineRenderError("Sponge schematic entity Pos must contain three doubles");
|
|
113842
|
+
}
|
|
113843
|
+
const position = pos.value.value.map((value2, axis) => value2 + offset[axis]);
|
|
113844
|
+
const value = entityData(entity, version3);
|
|
113845
|
+
value.Pos = { type: "list", value: { type: "double", value: [...position] } };
|
|
113846
|
+
return { position, nbt: { type: "compound", value } };
|
|
113847
|
+
});
|
|
113848
|
+
return { size, blocks, entities, dataVersion };
|
|
113849
|
+
}
|
|
113850
|
+
};
|
|
113851
|
+
function integer2(tag, name2) {
|
|
113852
|
+
if (tag?.type !== "int" || !Number.isInteger(tag.value) || tag.value < -2147483648 || tag.value > 2147483647) {
|
|
113853
|
+
throw new MineRenderError(`Sponge schematic ${name2} must be an int`);
|
|
113854
|
+
}
|
|
113855
|
+
return tag.value;
|
|
113856
|
+
}
|
|
113857
|
+
function compound(tag, name2) {
|
|
113858
|
+
if (tag?.type !== "compound" || !tag.value || typeof tag.value !== "object" || Array.isArray(tag.value)) {
|
|
113859
|
+
throw new MineRenderError(`Sponge schematic ${name2} must be a compound`);
|
|
113860
|
+
}
|
|
113861
|
+
return tag.value;
|
|
113862
|
+
}
|
|
113863
|
+
function intPosition(tag, name2) {
|
|
113864
|
+
if (tag?.type !== "intArray" || !Array.isArray(tag.value) || tag.value.length !== 3 || !tag.value.every((value) => Number.isInteger(value) && value >= -2147483648 && value <= 2147483647)) {
|
|
113865
|
+
throw new MineRenderError(`Sponge schematic ${name2} must contain three ints`);
|
|
113866
|
+
}
|
|
113867
|
+
return [...tag.value];
|
|
113868
|
+
}
|
|
113869
|
+
function compoundList2(tags, name2) {
|
|
113870
|
+
const tag = tags[name2];
|
|
113871
|
+
if (tag === void 0) return [];
|
|
113872
|
+
if (tag.type === "list" && Array.isArray(tag.value.value)) {
|
|
113873
|
+
if (tag.value.value.length === 0) return [];
|
|
113874
|
+
if (tag.value.type === "compound") return tag.value.value;
|
|
113875
|
+
}
|
|
113876
|
+
throw new MineRenderError(`Sponge schematic ${name2} must be a compound list`);
|
|
113877
|
+
}
|
|
113878
|
+
function blockState(state) {
|
|
113879
|
+
const match = /^((?:[a-z0-9_.-]+:)?[a-z0-9_./-]+)(?:\[([^\[\]]*)\])?$/.exec(state);
|
|
113880
|
+
if (!match) throw new MineRenderError(`Invalid Sponge schematic block state ${state}`);
|
|
113881
|
+
const properties = {};
|
|
113882
|
+
if (match[2]) {
|
|
113883
|
+
for (const entry of match[2].split(",")) {
|
|
113884
|
+
const pair = /^([a-z0-9_]+)=([^\s=,\[\]]+)$/.exec(entry);
|
|
113885
|
+
if (!pair || Object.prototype.hasOwnProperty.call(properties, pair[1])) throw new MineRenderError(`Invalid Sponge schematic block state ${state}`);
|
|
113886
|
+
Object.defineProperty(properties, pair[1], { value: pair[2], enumerable: true, writable: true, configurable: true });
|
|
113887
|
+
}
|
|
113888
|
+
}
|
|
113889
|
+
return { type: match[1].includes(":") ? match[1] : `minecraft:${match[1]}`, properties };
|
|
113890
|
+
}
|
|
113891
|
+
function entityData(entity, version3) {
|
|
113892
|
+
const id = entity.Id;
|
|
113893
|
+
if (id?.type !== "string" || !id.value) throw new MineRenderError("Sponge schematic entity Id must be a nonempty string");
|
|
113894
|
+
const { Id, Pos, ...extra } = entity;
|
|
113895
|
+
const value = version3 === 2 ? extra : entity.Data === void 0 ? {} : { ...compound(entity.Data, "entity Data") };
|
|
113896
|
+
value.id = { type: "string", value: id.value.includes(":") ? id.value : `minecraft:${id.value}` };
|
|
113897
|
+
return value;
|
|
113898
|
+
}
|
|
113899
|
+
|
|
113715
113900
|
// src/model/multiblock/StructureParser.ts
|
|
113716
113901
|
init_dirname();
|
|
113717
113902
|
init_buffer2();
|
|
@@ -114971,8 +115156,8 @@ property list uchar int vertex_index
|
|
|
114971
115156
|
* Set `options.initialState` to choose block properties such as `facing` or `axis`.
|
|
114972
115157
|
* Use the returned object's `setPosition` method to move all of its model parts.
|
|
114973
115158
|
*/
|
|
114974
|
-
async addBlock(
|
|
114975
|
-
return this.addSceneObject(
|
|
115159
|
+
async addBlock(blockState2, options, parent = this) {
|
|
115160
|
+
return this.addSceneObject(blockState2, () => new BlockObject(blockState2, options), options, parent);
|
|
114976
115161
|
}
|
|
114977
115162
|
/**
|
|
114978
115163
|
* Loads a skin and adds an initialized player model.
|
|
@@ -118755,6 +118940,16 @@ gl_FragDepth=readDepth(vUv);
|
|
|
118755
118940
|
init_buffer2();
|
|
118756
118941
|
init_process2();
|
|
118757
118942
|
init_AssetKey();
|
|
118943
|
+
var blockKeys = /* @__PURE__ */ new Map();
|
|
118944
|
+
function blockKey(type) {
|
|
118945
|
+
let key = blockKeys.get(type);
|
|
118946
|
+
if (!key) {
|
|
118947
|
+
key = AssetKey.parse("blockstates", type);
|
|
118948
|
+
if (blockKeys.size >= 4096) blockKeys.clear();
|
|
118949
|
+
blockKeys.set(type, key);
|
|
118950
|
+
}
|
|
118951
|
+
return key;
|
|
118952
|
+
}
|
|
118758
118953
|
var ChunkData = class _ChunkData {
|
|
118759
118954
|
constructor() {
|
|
118760
118955
|
this.indices = new Uint16Array(4096);
|
|
@@ -118782,10 +118977,10 @@ gl_FragDepth=readDepth(vUv);
|
|
|
118782
118977
|
let key;
|
|
118783
118978
|
let nbt;
|
|
118784
118979
|
if (block && !_ChunkData.isAir(block)) {
|
|
118785
|
-
const type =
|
|
118980
|
+
const type = blockKey(block.type).toNamespacedString();
|
|
118786
118981
|
const properties = Object.fromEntries(Object.keys(block.properties ?? {}).sort().map((name2) => [name2, block.properties[name2]]));
|
|
118787
118982
|
state = Object.freeze(Object.keys(properties).length ? { type, properties: Object.freeze(properties) } : { type });
|
|
118788
|
-
key =
|
|
118983
|
+
key = _ChunkData.paletteKey(block);
|
|
118789
118984
|
if (block.nbt !== void 0) nbt = structuredClone(block.nbt);
|
|
118790
118985
|
}
|
|
118791
118986
|
const previousId = this.indices[index];
|
|
@@ -118822,9 +119017,14 @@ gl_FragDepth=readDepth(vUv);
|
|
|
118822
119017
|
}
|
|
118823
119018
|
static isAir(block) {
|
|
118824
119019
|
if (typeof block === "undefined" || typeof block.type === "undefined") return true;
|
|
118825
|
-
const key =
|
|
119020
|
+
const key = blockKey(block.type);
|
|
118826
119021
|
return key.namespace === "minecraft" && !key.type && ["air", "cave_air", "void_air"].includes(key.path);
|
|
118827
119022
|
}
|
|
119023
|
+
/** Identifies a normalized block type and its sorted properties, excluding per-cell NBT. */
|
|
119024
|
+
static paletteKey(block) {
|
|
119025
|
+
const properties = Object.fromEntries(Object.keys(block.properties ?? {}).sort().map((name2) => [name2, block.properties[name2]]));
|
|
119026
|
+
return JSON.stringify([blockKey(block.type).toNamespacedString(), properties]);
|
|
119027
|
+
}
|
|
118828
119028
|
static copyBlock(state, nbt) {
|
|
118829
119029
|
const block = { type: state.type };
|
|
118830
119030
|
if (state.properties) block.properties = { ...state.properties };
|
|
@@ -119004,14 +119204,17 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119004
119204
|
const perLong = Math.floor(64 / bits2);
|
|
119005
119205
|
const expected = padded ? Math.ceil(4096 / perLong) : Math.ceil(4096 * bits2 / 64);
|
|
119006
119206
|
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 = (
|
|
119207
|
+
const words = tag.value.map(([high, low]) => [high >>> 0, low >>> 0]);
|
|
119208
|
+
const mask = (1 << bits2) - 1;
|
|
119009
119209
|
for (let index = 0; index < 4096; index++) {
|
|
119010
|
-
const
|
|
119011
|
-
const
|
|
119012
|
-
|
|
119013
|
-
|
|
119014
|
-
|
|
119210
|
+
const bitPos = index * bits2;
|
|
119211
|
+
const word = padded ? Math.floor(index / perLong) : bitPos >>> 6;
|
|
119212
|
+
const shift = padded ? index % perLong * bits2 : bitPos & 63;
|
|
119213
|
+
const [high, low] = words[word];
|
|
119214
|
+
let value = shift < 32 ? low >>> shift : high >>> shift - 32;
|
|
119215
|
+
if (shift < 32 && shift + bits2 > 32) value += high * 2 ** (32 - shift);
|
|
119216
|
+
if (!padded && shift + bits2 > 64) value += words[word + 1][1] * 2 ** (64 - shift);
|
|
119217
|
+
indices[index] = value & mask;
|
|
119015
119218
|
}
|
|
119016
119219
|
return indices;
|
|
119017
119220
|
}
|
|
@@ -119167,7 +119370,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119167
119370
|
init_process2();
|
|
119168
119371
|
init_three_module();
|
|
119169
119372
|
init_Model();
|
|
119170
|
-
|
|
119373
|
+
init_util();
|
|
119171
119374
|
init_AssetKey();
|
|
119172
119375
|
init_BlockStates();
|
|
119173
119376
|
init_CubeFace();
|
|
@@ -119207,18 +119410,18 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119207
119410
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
|
|
119208
119411
|
}
|
|
119209
119412
|
/** Returns a cube template, or `undefined` when the block requires an individual render object. */
|
|
119210
|
-
async get(
|
|
119211
|
-
if (!
|
|
119212
|
-
let states = this.states.get(
|
|
119213
|
-
if (!states) this.states.set(
|
|
119413
|
+
async get(blockState2, properties = {}) {
|
|
119414
|
+
if (!blockState2.variants || blockState2.multipart) return void 0;
|
|
119415
|
+
let states = this.states.get(blockState2);
|
|
119416
|
+
if (!states) this.states.set(blockState2, states = /* @__PURE__ */ new Map());
|
|
119214
119417
|
const key = JSON.stringify(Object.entries(properties).sort(([a4], [b4]) => a4.localeCompare(b4)));
|
|
119215
|
-
const prepared = await cached(states, key, () => this.prepare(
|
|
119418
|
+
const prepared = await cached(states, key, () => this.prepare(blockState2, properties));
|
|
119216
119419
|
if (!prepared) return void 0;
|
|
119217
119420
|
return prepared.templates.get(BlockStateResolver.choose(prepared.variants));
|
|
119218
119421
|
}
|
|
119219
|
-
async prepare(
|
|
119220
|
-
const state = { ...await BlockStateResolver.defaults(
|
|
119221
|
-
const groups = BlockStateResolver.matching(
|
|
119422
|
+
async prepare(blockState2, properties) {
|
|
119423
|
+
const state = { ...await BlockStateResolver.defaults(blockState2), ...properties };
|
|
119424
|
+
const groups = BlockStateResolver.matching(blockState2, state);
|
|
119222
119425
|
if (groups.length !== 1) return void 0;
|
|
119223
119426
|
const variants = groups[0];
|
|
119224
119427
|
const choices = Array.isArray(variants) ? variants : [variants];
|
|
@@ -119230,7 +119433,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119230
119433
|
const atlas = await UVMapper.getAtlas(model);
|
|
119231
119434
|
const rotation = BlockStateResolver.rotation(variant);
|
|
119232
119435
|
if (!atlas || atlas.hasAnimation || !ModelCulling.isOpaqueFullCube(atlas) || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize || ModelCulling.toLocalMask(63, rotation) !== 63) return void 0;
|
|
119233
|
-
const tints = await BlockTints.get(
|
|
119436
|
+
const tints = await BlockTints.get(blockState2.key, state, model);
|
|
119234
119437
|
let models = this.models.get(model);
|
|
119235
119438
|
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
119236
119439
|
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
@@ -119315,7 +119518,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119315
119518
|
* Places a structure's blocks at their stored positions, then refreshes neighboring faces.
|
|
119316
119519
|
* Entity NBT is retained by the structure but is not rendered.
|
|
119317
119520
|
*
|
|
119318
|
-
* @param useBatches -
|
|
119521
|
+
* @param useBatches - Yields between chunks by default. Set to `false` for sequential placement.
|
|
119319
119522
|
* @param executor - Optional queue for batched placement. The caller remains responsible for stopping it.
|
|
119320
119523
|
*/
|
|
119321
119524
|
async placeMultiBlock(multiblock, useBatches = true, executor) {
|
|
@@ -119332,8 +119535,10 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119332
119535
|
};
|
|
119333
119536
|
const place = (block) => this.placeBlock(new Vector3(...block.position), block, collect);
|
|
119334
119537
|
const keys = /* @__PURE__ */ new Map();
|
|
119538
|
+
const types2 = /* @__PURE__ */ new Set();
|
|
119335
119539
|
for (const block of multiblock.blocks) {
|
|
119336
|
-
if (Chunk.isAir(block)) continue;
|
|
119540
|
+
if (Chunk.isAir(block) || types2.has(block.type)) continue;
|
|
119541
|
+
types2.add(block.type);
|
|
119337
119542
|
const key = AssetKey.parse("blockstates", block.type);
|
|
119338
119543
|
keys.set(key.serialize(), key);
|
|
119339
119544
|
}
|
|
@@ -119342,6 +119547,23 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119342
119547
|
for (const block of multiblock.blocks) await place(block);
|
|
119343
119548
|
return;
|
|
119344
119549
|
}
|
|
119550
|
+
if (!executor) {
|
|
119551
|
+
const groups2 = /* @__PURE__ */ new Map();
|
|
119552
|
+
const position = new Vector3();
|
|
119553
|
+
for (const block of multiblock.blocks) {
|
|
119554
|
+
const [x4, y5, z4] = block.position;
|
|
119555
|
+
this.validatePosBounds(position.set(x4, y5, z4));
|
|
119556
|
+
const cx = Math.floor(x4 / 16), cy = Math.floor(y5 / 16), cz = Math.floor(z4 / 16);
|
|
119557
|
+
const key = `${cx}_${cy}_${cz}`;
|
|
119558
|
+
const chunk = this._chunks.get(key) ?? (Chunk.isAir(block) ? void 0 : this.getOrCreateChunkAt(position));
|
|
119559
|
+
if (!chunk) continue;
|
|
119560
|
+
let group = groups2.get(chunk);
|
|
119561
|
+
if (!group) groups2.set(chunk, group = []);
|
|
119562
|
+
group.push({ index: (y5 - cy * 16) * 256 + (z4 - cz * 16) * 16 + x4 - cx * 16, block });
|
|
119563
|
+
}
|
|
119564
|
+
await this.placeChunkGroups(groups2, changes);
|
|
119565
|
+
return;
|
|
119566
|
+
}
|
|
119345
119567
|
const positions = /* @__PURE__ */ new Map();
|
|
119346
119568
|
for (const block of multiblock.blocks) {
|
|
119347
119569
|
const key = block.position.join(",");
|
|
@@ -119350,19 +119572,34 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119350
119572
|
else positions.set(key, [block]);
|
|
119351
119573
|
}
|
|
119352
119574
|
const groups = [...positions.values()];
|
|
119353
|
-
|
|
119354
|
-
|
|
119355
|
-
|
|
119356
|
-
|
|
119357
|
-
|
|
119358
|
-
|
|
119359
|
-
|
|
119360
|
-
|
|
119361
|
-
|
|
119362
|
-
|
|
119575
|
+
for (let i4 = 0; i4 < groups.length; i4 += executor.batch) {
|
|
119576
|
+
const results = await Promise.allSettled(groups.slice(i4, i4 + executor.batch).map(
|
|
119577
|
+
(blocks) => executor.submit(async () => {
|
|
119578
|
+
for (const block of blocks) await place(block);
|
|
119579
|
+
})
|
|
119580
|
+
));
|
|
119581
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
119582
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
119583
|
+
}
|
|
119584
|
+
}
|
|
119585
|
+
async placeChunkGroups(groups, changes) {
|
|
119586
|
+
let sliceStart = performance.now();
|
|
119587
|
+
for (const [chunk, blocks] of groups) {
|
|
119588
|
+
let positions;
|
|
119589
|
+
try {
|
|
119590
|
+
positions = await chunk.placeBlocks(blocks);
|
|
119591
|
+
} finally {
|
|
119592
|
+
positions ?? (positions = blocks.map(({ index }) => new Vector3(
|
|
119593
|
+
chunk.x * 16 + index % 16,
|
|
119594
|
+
chunk.y * 16 + Math.floor(index / 256),
|
|
119595
|
+
chunk.z * 16 + Math.floor(index / 16) % 16
|
|
119596
|
+
)));
|
|
119597
|
+
for (const pos of positions) changes.set(`${pos.x},${pos.y},${pos.z}`, pos);
|
|
119598
|
+
}
|
|
119599
|
+
if (performance.now() - sliceStart > 8) {
|
|
119600
|
+
await yieldToEventLoop();
|
|
119601
|
+
sliceStart = performance.now();
|
|
119363
119602
|
}
|
|
119364
|
-
} finally {
|
|
119365
|
-
if (!executor) queue2.stop();
|
|
119366
119603
|
}
|
|
119367
119604
|
}
|
|
119368
119605
|
/** Replaces one chunk column's blocks. Entity NBT remains available on the parsed chunk. */
|
|
@@ -119370,7 +119607,24 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119370
119607
|
const changes = /* @__PURE__ */ new Map();
|
|
119371
119608
|
try {
|
|
119372
119609
|
await this.clearChunkColumn(chunk.x, chunk.z, changes);
|
|
119610
|
+
const groups = /* @__PURE__ */ new Map();
|
|
119373
119611
|
for (const section of chunk.sections) {
|
|
119612
|
+
if (!executor) {
|
|
119613
|
+
const blocks2 = [];
|
|
119614
|
+
for (let index = 0; index < 4096; index++) {
|
|
119615
|
+
const block = section.data.get(index);
|
|
119616
|
+
if (block) blocks2.push({ index, block });
|
|
119617
|
+
}
|
|
119618
|
+
if (blocks2.length) {
|
|
119619
|
+
const position = new Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
|
|
119620
|
+
this.validatePosBounds(position);
|
|
119621
|
+
const target = this.getOrCreateChunkAt(position);
|
|
119622
|
+
const previous = groups.get(target);
|
|
119623
|
+
if (previous) previous.push(...blocks2);
|
|
119624
|
+
else groups.set(target, blocks2);
|
|
119625
|
+
}
|
|
119626
|
+
continue;
|
|
119627
|
+
}
|
|
119374
119628
|
const blocks = [];
|
|
119375
119629
|
for (let index = 0; index < 4096; index++) {
|
|
119376
119630
|
const block = section.data.get(index);
|
|
@@ -119385,6 +119639,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119385
119639
|
}
|
|
119386
119640
|
await this.placeBlocks({ size: [16, 16, 16], blocks }, true, executor, changes);
|
|
119387
119641
|
}
|
|
119642
|
+
if (!executor) await this.placeChunkGroups(groups, changes);
|
|
119388
119643
|
} finally {
|
|
119389
119644
|
await this.updateCulling([...changes.values()]);
|
|
119390
119645
|
}
|
|
@@ -119425,19 +119680,23 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119425
119680
|
this.sectionModels?.clear();
|
|
119426
119681
|
}
|
|
119427
119682
|
updateCulling(positions) {
|
|
119683
|
+
const neighbor = new Vector3();
|
|
119428
119684
|
for (const pos of positions) {
|
|
119429
|
-
|
|
119430
|
-
|
|
119431
|
-
|
|
119432
|
-
this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
|
|
119433
|
-
}
|
|
119685
|
+
const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
|
|
119686
|
+
const chunk = this._chunks.get(`${cx}_${cy}_${cz}`);
|
|
119687
|
+
const lx = pos.x - cx * 16, ly = pos.y - cy * 16, lz = pos.z - cz * 16;
|
|
119434
119688
|
for (let y5 = -1; y5 <= 1; y5++) {
|
|
119435
119689
|
for (let z4 = -1; z4 <= 1; z4++) {
|
|
119436
119690
|
for (let x4 = -1; x4 <= 1; x4++) {
|
|
119437
|
-
const
|
|
119438
|
-
|
|
119439
|
-
|
|
119440
|
-
|
|
119691
|
+
const nx = lx + x4, ny = ly + y5, nz = lz + z4;
|
|
119692
|
+
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)}`);
|
|
119693
|
+
if (!section) continue;
|
|
119694
|
+
const index = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
|
|
119695
|
+
let pending = this.pendingCulling.get(section);
|
|
119696
|
+
if (pending?.has(index)) continue;
|
|
119697
|
+
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;
|
|
119698
|
+
if (!pending) this.pendingCulling.set(section, pending = /* @__PURE__ */ new Set());
|
|
119699
|
+
pending.add(index);
|
|
119441
119700
|
}
|
|
119442
119701
|
}
|
|
119443
119702
|
}
|
|
@@ -119445,39 +119704,38 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119445
119704
|
return this.culling ?? (this.culling = Promise.resolve().then(async () => {
|
|
119446
119705
|
try {
|
|
119447
119706
|
while (this.pendingCulling.size) {
|
|
119448
|
-
const batch = [...this.pendingCulling
|
|
119707
|
+
const batch = [...this.pendingCulling];
|
|
119449
119708
|
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;
|
|
119709
|
+
for (const [chunk, indices] of batch) {
|
|
119710
|
+
for (const index of indices) {
|
|
119711
|
+
if (!chunk.isBlockVisibleIndex(index)) continue;
|
|
119712
|
+
const lx = index % 16, ly = Math.floor(index / 256), lz = Math.floor(index / 16) % 16;
|
|
119713
|
+
const wx = chunk.x * 16 + lx, wy = chunk.y * 16 + ly, wz = chunk.z * 16 + lz;
|
|
119714
|
+
const block = chunk.getBlockAt(neighbor.set(wx, wy, wz));
|
|
119715
|
+
if (block.object?.fluidKind) {
|
|
119716
|
+
await block.object.updateFluid((x4, y5, z4) => {
|
|
119717
|
+
const nx = lx + x4, ny = ly + y5, nz = lz + z4;
|
|
119718
|
+
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)}`);
|
|
119719
|
+
const neighborIndex = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
|
|
119720
|
+
const object3 = section?.isBlockVisibleIndex(neighborIndex) ? section.getBlockAt(neighbor.set(wx + x4, wy + y5, wz + z4))?.object : void 0;
|
|
119721
|
+
return {
|
|
119722
|
+
fluid: object3?.fluidKind,
|
|
119723
|
+
level: object3?.fluidLevel,
|
|
119724
|
+
solid: section?.isOccludingIndex(neighborIndex) ?? false
|
|
119725
|
+
};
|
|
119726
|
+
});
|
|
119727
|
+
}
|
|
119728
|
+
let mask = 0;
|
|
119729
|
+
for (let face = 0; face < CUBE_FACE_OFFSETS.length; face++) {
|
|
119730
|
+
const offset = CUBE_FACE_OFFSETS[face];
|
|
119731
|
+
const nx = lx + offset[0], ny = ly + offset[1], nz = lz + offset[2];
|
|
119732
|
+
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)}`);
|
|
119733
|
+
if (section?.isOccludingIndex((ny & 15) * 256 + (nz & 15) * 16 + (nx & 15))) mask |= 1 << face;
|
|
119476
119734
|
}
|
|
119735
|
+
await chunk.setCullMaskIndex(index, mask);
|
|
119477
119736
|
}
|
|
119478
|
-
await chunk.setCullMaskAt(pos, mask);
|
|
119479
119737
|
}
|
|
119480
|
-
|
|
119738
|
+
await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
|
|
119481
119739
|
}
|
|
119482
119740
|
} finally {
|
|
119483
119741
|
this.culling = void 0;
|
|
@@ -119542,7 +119800,234 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119542
119800
|
init_process2();
|
|
119543
119801
|
init_three_module();
|
|
119544
119802
|
init_CanvasCompat();
|
|
119803
|
+
init_CubeFace();
|
|
119545
119804
|
init_Materials();
|
|
119805
|
+
|
|
119806
|
+
// src/world/SectionGeometry.ts
|
|
119807
|
+
init_dirname();
|
|
119808
|
+
init_buffer2();
|
|
119809
|
+
init_process2();
|
|
119810
|
+
init_CubeFace();
|
|
119811
|
+
function buildSectionGeometry(input) {
|
|
119812
|
+
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize } = input;
|
|
119813
|
+
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
119814
|
+
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
119815
|
+
const visible = [];
|
|
119816
|
+
const visibleAtlases = /* @__PURE__ */ new Set();
|
|
119817
|
+
for (let entry = 0; entry < count; entry++) {
|
|
119818
|
+
const template = templateData[templates[entry]];
|
|
119819
|
+
if (!template.cullFaces.some((direction) => !(cullMasks[entry] & direction))) continue;
|
|
119820
|
+
visible.push(entry);
|
|
119821
|
+
visibleAtlases.add(template.atlas);
|
|
119822
|
+
}
|
|
119823
|
+
const pages = [];
|
|
119824
|
+
const locations = /* @__PURE__ */ new Map();
|
|
119825
|
+
for (const atlas of [...visibleAtlases].sort((a4, b4) => atlases[b4].height - atlases[a4].height)) {
|
|
119826
|
+
const { width, height } = atlases[atlas];
|
|
119827
|
+
if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
|
|
119828
|
+
let selected = -1;
|
|
119829
|
+
for (let i4 = 0; i4 < pages.length; i4++) {
|
|
119830
|
+
const page2 = pages[i4];
|
|
119831
|
+
const nextRow = page2.x + width > maxAtlasSize;
|
|
119832
|
+
if ((nextRow ? page2.y + page2.rowHeight : page2.y) + height > maxAtlasSize) continue;
|
|
119833
|
+
if (nextRow) {
|
|
119834
|
+
page2.y += page2.rowHeight;
|
|
119835
|
+
page2.x = 0;
|
|
119836
|
+
page2.rowHeight = 0;
|
|
119837
|
+
}
|
|
119838
|
+
selected = i4;
|
|
119839
|
+
break;
|
|
119840
|
+
}
|
|
119841
|
+
if (selected < 0) {
|
|
119842
|
+
selected = pages.length;
|
|
119843
|
+
pages.push({ placements: [], entries: [], x: 0, y: 0, rowHeight: 0, width: 0, height: 0 });
|
|
119844
|
+
}
|
|
119845
|
+
const page = pages[selected];
|
|
119846
|
+
page.placements.push({ atlas, x: page.x, y: page.y });
|
|
119847
|
+
locations.set(atlas, { page: selected, x: page.x, y: page.y });
|
|
119848
|
+
page.x += width;
|
|
119849
|
+
page.rowHeight = Math.max(page.rowHeight, height);
|
|
119850
|
+
page.width = Math.max(page.width, page.x);
|
|
119851
|
+
page.height = Math.max(page.height, page.y + height);
|
|
119852
|
+
}
|
|
119853
|
+
for (const entry of visible) pages[locations.get(templateData[templates[entry]].atlas).page].entries.push(entry);
|
|
119854
|
+
return pages.map((page) => {
|
|
119855
|
+
let faces = 0;
|
|
119856
|
+
for (const entry of page.entries) {
|
|
119857
|
+
const template = templateData[templates[entry]];
|
|
119858
|
+
for (let face = 0; face < CUBE_FACES.length; face++) {
|
|
119859
|
+
if (!(cullMasks[entry] & template.cullFaces[face])) faces++;
|
|
119860
|
+
}
|
|
119861
|
+
}
|
|
119862
|
+
const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
|
|
119863
|
+
const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
|
|
119864
|
+
const outputIndices = new Uint32Array(faces * 6);
|
|
119865
|
+
let vertex2 = 0, indexOffset = 0;
|
|
119866
|
+
for (const entry of page.entries) {
|
|
119867
|
+
const template = templateData[templates[entry]];
|
|
119868
|
+
const atlas = atlases[template.atlas];
|
|
119869
|
+
const placement = locations.get(template.atlas);
|
|
119870
|
+
const mapU = (u4) => (placement.x + u4 * atlas.width) / page.width;
|
|
119871
|
+
const mapV = (v5) => 1 - (placement.y + (1 - v5) * atlas.height) / page.height;
|
|
119872
|
+
const offsetX = indices[entry] % 16 * 16;
|
|
119873
|
+
const offsetY = Math.floor(indices[entry] / 256) * 16;
|
|
119874
|
+
const offsetZ = Math.floor(indices[entry] / 16) % 16 * 16;
|
|
119875
|
+
for (let face = 0; face < CUBE_FACES.length; face++) {
|
|
119876
|
+
if (cullMasks[entry] & template.cullFaces[face]) continue;
|
|
119877
|
+
const start = vertex2;
|
|
119878
|
+
for (let corner = 0; corner < 4; corner++, vertex2++) {
|
|
119879
|
+
const source = face * 4 + corner;
|
|
119880
|
+
positions[vertex2 * 3] = template.positions[source * 3] + offsetX;
|
|
119881
|
+
positions[vertex2 * 3 + 1] = template.positions[source * 3 + 1] + offsetY;
|
|
119882
|
+
positions[vertex2 * 3 + 2] = template.positions[source * 3 + 2] + offsetZ;
|
|
119883
|
+
normals[vertex2 * 3] = template.normals[source * 3];
|
|
119884
|
+
normals[vertex2 * 3 + 1] = template.normals[source * 3 + 1];
|
|
119885
|
+
normals[vertex2 * 3 + 2] = template.normals[source * 3 + 2];
|
|
119886
|
+
uvs[vertex2 * 2] = mapU(template.uvs[source * 2]);
|
|
119887
|
+
uvs[vertex2 * 2 + 1] = mapV(template.uvs[source * 2 + 1]);
|
|
119888
|
+
uvBounds[vertex2 * 4] = mapU(template.uvBounds[source * 4]);
|
|
119889
|
+
uvBounds[vertex2 * 4 + 1] = mapV(template.uvBounds[source * 4 + 1]);
|
|
119890
|
+
uvBounds[vertex2 * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);
|
|
119891
|
+
uvBounds[vertex2 * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);
|
|
119892
|
+
colors[vertex2 * 3] = template.colors[source * 3];
|
|
119893
|
+
colors[vertex2 * 3 + 1] = template.colors[source * 3 + 1];
|
|
119894
|
+
colors[vertex2 * 3 + 2] = template.colors[source * 3 + 2];
|
|
119895
|
+
}
|
|
119896
|
+
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[face * 6 + corner] - face * 4;
|
|
119897
|
+
}
|
|
119898
|
+
}
|
|
119899
|
+
return { width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices };
|
|
119900
|
+
});
|
|
119901
|
+
}
|
|
119902
|
+
function sectionGeometryTransferables(pages) {
|
|
119903
|
+
return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer]);
|
|
119904
|
+
}
|
|
119905
|
+
|
|
119906
|
+
// src/world/SectionWorker.ts
|
|
119907
|
+
init_dirname();
|
|
119908
|
+
init_buffer2();
|
|
119909
|
+
init_process2();
|
|
119910
|
+
init_Env();
|
|
119911
|
+
var _SectionWorker = class _SectionWorker {
|
|
119912
|
+
constructor(worker) {
|
|
119913
|
+
this.worker = worker;
|
|
119914
|
+
this.nextId = 0;
|
|
119915
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
119916
|
+
worker.addEventListener("message", (event) => {
|
|
119917
|
+
const reply = event.data;
|
|
119918
|
+
const pending = this.pending.get(reply.id);
|
|
119919
|
+
if (!pending) return;
|
|
119920
|
+
this.pending.delete(reply.id);
|
|
119921
|
+
if (reply.type === "pages") pending.resolve(reply.pages);
|
|
119922
|
+
else pending.reject(new Error(reply.message));
|
|
119923
|
+
});
|
|
119924
|
+
worker.addEventListener("error", (event) => this.fail(event.message || "Section worker failed"));
|
|
119925
|
+
worker.addEventListener("messageerror", () => this.fail("Section worker message could not be deserialized"));
|
|
119926
|
+
}
|
|
119927
|
+
/** The shared worker, or undefined when the environment has none or a previous worker failed. */
|
|
119928
|
+
static shared() {
|
|
119929
|
+
if (!this.initialized) {
|
|
119930
|
+
this.initialized = true;
|
|
119931
|
+
const worker = Env.provider.createWorker?.("section");
|
|
119932
|
+
if (worker) this.instance = new _SectionWorker(worker);
|
|
119933
|
+
}
|
|
119934
|
+
return this.instance;
|
|
119935
|
+
}
|
|
119936
|
+
/** Builds geometry without transferring the input buffers away from the caller. */
|
|
119937
|
+
build(input) {
|
|
119938
|
+
if (!this.worker) return Promise.reject(new Error("Section worker terminated"));
|
|
119939
|
+
return new Promise((resolve, reject) => {
|
|
119940
|
+
const id = this.nextId++;
|
|
119941
|
+
this.pending.set(id, { resolve, reject });
|
|
119942
|
+
this.worker.postMessage({ id, type: "build", input });
|
|
119943
|
+
});
|
|
119944
|
+
}
|
|
119945
|
+
/** Rejects pending builds, terminates the worker, and makes shared() return undefined. */
|
|
119946
|
+
terminate() {
|
|
119947
|
+
this.fail("Section worker terminated");
|
|
119948
|
+
}
|
|
119949
|
+
fail(message) {
|
|
119950
|
+
const error2 = new Error(message);
|
|
119951
|
+
for (const pending of this.pending.values()) pending.reject(error2);
|
|
119952
|
+
this.pending.clear();
|
|
119953
|
+
this.worker?.terminate();
|
|
119954
|
+
this.worker = void 0;
|
|
119955
|
+
_SectionWorker.instance = void 0;
|
|
119956
|
+
}
|
|
119957
|
+
};
|
|
119958
|
+
_SectionWorker.initialized = false;
|
|
119959
|
+
var SectionWorker = _SectionWorker;
|
|
119960
|
+
|
|
119961
|
+
// src/world/SectionMesh.ts
|
|
119962
|
+
var templateCache = /* @__PURE__ */ new WeakMap();
|
|
119963
|
+
function toInput(entries, maxAtlasSize) {
|
|
119964
|
+
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
119965
|
+
const atlases = [];
|
|
119966
|
+
const atlasIds = /* @__PURE__ */ new Map();
|
|
119967
|
+
const templateIds = /* @__PURE__ */ new Map();
|
|
119968
|
+
const input = {
|
|
119969
|
+
count: entries.length,
|
|
119970
|
+
indices: new Uint16Array(entries.length),
|
|
119971
|
+
templates: new Uint16Array(entries.length),
|
|
119972
|
+
cullMasks: new Uint8Array(entries.length),
|
|
119973
|
+
templateData: [],
|
|
119974
|
+
atlases: [],
|
|
119975
|
+
maxAtlasSize
|
|
119976
|
+
};
|
|
119977
|
+
for (let i4 = 0; i4 < entries.length; i4++) {
|
|
119978
|
+
const { index, template, cullMask } = entries[i4];
|
|
119979
|
+
let id = templateIds.get(template);
|
|
119980
|
+
if (id === void 0) {
|
|
119981
|
+
let atlas = atlasIds.get(template.atlas);
|
|
119982
|
+
if (atlas === void 0) {
|
|
119983
|
+
atlas = atlases.length;
|
|
119984
|
+
atlasIds.set(template.atlas, atlas);
|
|
119985
|
+
atlases.push(template.atlas);
|
|
119986
|
+
input.atlases.push({ width: template.atlas.image.width, height: template.atlas.image.height });
|
|
119987
|
+
}
|
|
119988
|
+
let data = templateCache.get(template);
|
|
119989
|
+
if (!data) {
|
|
119990
|
+
data = {
|
|
119991
|
+
positions: new Float32Array(72),
|
|
119992
|
+
normals: new Float32Array(72),
|
|
119993
|
+
uvs: new Float32Array(48),
|
|
119994
|
+
uvBounds: new Float32Array(96),
|
|
119995
|
+
colors: new Float32Array(72),
|
|
119996
|
+
indices: new Uint16Array(36),
|
|
119997
|
+
cullFaces: new Uint8Array(template.cullFaces),
|
|
119998
|
+
atlas: 0
|
|
119999
|
+
};
|
|
120000
|
+
const position = template.geometry.getAttribute("position");
|
|
120001
|
+
const normal = template.geometry.getAttribute("normal");
|
|
120002
|
+
const uv = template.geometry.getAttribute("uv");
|
|
120003
|
+
const bounds = template.geometry.getAttribute("uvBounds");
|
|
120004
|
+
const color3 = template.geometry.getAttribute("color");
|
|
120005
|
+
for (let vertex2 = 0; vertex2 < CUBE_FACES.length * 4; vertex2++) {
|
|
120006
|
+
data.positions.set([position.getX(vertex2), position.getY(vertex2), position.getZ(vertex2)], vertex2 * 3);
|
|
120007
|
+
data.normals.set([normal.getX(vertex2), normal.getY(vertex2), normal.getZ(vertex2)], vertex2 * 3);
|
|
120008
|
+
data.uvs.set([uv.getX(vertex2), uv.getY(vertex2)], vertex2 * 2);
|
|
120009
|
+
data.uvBounds.set([
|
|
120010
|
+
bounds?.getX(vertex2) ?? 0,
|
|
120011
|
+
bounds?.getY(vertex2) ?? 0,
|
|
120012
|
+
bounds?.getZ(vertex2) ?? 1,
|
|
120013
|
+
bounds?.getW(vertex2) ?? 1
|
|
120014
|
+
], vertex2 * 4);
|
|
120015
|
+
data.colors.set([color3?.getX(vertex2) ?? 1, color3?.getY(vertex2) ?? 1, color3?.getZ(vertex2) ?? 1], vertex2 * 3);
|
|
120016
|
+
}
|
|
120017
|
+
const indices = template.geometry.getIndex();
|
|
120018
|
+
for (let i5 = 0; i5 < data.indices.length; i5++) data.indices[i5] = indices.getX(i5);
|
|
120019
|
+
templateCache.set(template, data);
|
|
120020
|
+
}
|
|
120021
|
+
id = input.templateData.length;
|
|
120022
|
+
templateIds.set(template, id);
|
|
120023
|
+
input.templateData.push({ ...data, atlas });
|
|
120024
|
+
}
|
|
120025
|
+
input.indices[i4] = index;
|
|
120026
|
+
input.templates[i4] = id;
|
|
120027
|
+
input.cullMasks[i4] = cullMask;
|
|
120028
|
+
}
|
|
120029
|
+
return { input, atlases };
|
|
120030
|
+
}
|
|
119546
120031
|
var SectionMesh = class _SectionMesh extends Group {
|
|
119547
120032
|
constructor() {
|
|
119548
120033
|
super(...arguments);
|
|
@@ -119550,86 +120035,31 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119550
120035
|
}
|
|
119551
120036
|
/** Builds section-local meshes from visible cube faces. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
119552
120037
|
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);
|
|
120038
|
+
const { input, atlases } = toInput(entries, maxAtlasSize);
|
|
120039
|
+
return this.fromPages(buildSectionGeometry(input), atlases);
|
|
120040
|
+
}
|
|
120041
|
+
/** Builds section-local meshes in a browser worker when available, with synchronous fallback. */
|
|
120042
|
+
static async buildAsync(entries, maxAtlasSize = 2048) {
|
|
120043
|
+
const { input, atlases } = toInput(entries, maxAtlasSize);
|
|
120044
|
+
const worker = SectionWorker.shared();
|
|
120045
|
+
const pages = worker ? await worker.build(input).catch(() => buildSectionGeometry(input)) : buildSectionGeometry(input);
|
|
120046
|
+
return this.fromPages(pages, atlases);
|
|
120047
|
+
}
|
|
120048
|
+
static fromPages(pages, atlases) {
|
|
119586
120049
|
const section = new _SectionMesh();
|
|
119587
120050
|
for (const page of pages) {
|
|
119588
120051
|
const canvas = createCanvas(page.width, page.height);
|
|
119589
120052
|
const context = canvas.getContext("2d");
|
|
119590
120053
|
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
|
-
}
|
|
120054
|
+
context.drawImage(atlases[atlas].image.canvas, x4, y5);
|
|
119625
120055
|
}
|
|
119626
120056
|
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);
|
|
120057
|
+
geometry.setAttribute("position", new Float32BufferAttribute(page.positions.buffer, 3));
|
|
120058
|
+
geometry.setAttribute("normal", new Float32BufferAttribute(page.normals.buffer, 3));
|
|
120059
|
+
geometry.setAttribute("uv", new Float32BufferAttribute(page.uvs.buffer, 2));
|
|
120060
|
+
geometry.setAttribute("uvBounds", new Float32BufferAttribute(page.uvBounds.buffer, 4));
|
|
120061
|
+
geometry.setAttribute("color", new Float32BufferAttribute(page.colors.buffer, 3));
|
|
120062
|
+
geometry.setIndex(new Uint32BufferAttribute(page.indices.buffer, 1));
|
|
119633
120063
|
geometry.computeBoundingBox();
|
|
119634
120064
|
geometry.computeBoundingSphere();
|
|
119635
120065
|
const material = Materials.createShadedCanvasMaterial(canvas, false, false, true);
|
|
@@ -119663,7 +120093,9 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119663
120093
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
119664
120094
|
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
119665
120095
|
this.hiddenBlocks = /* @__PURE__ */ new Set();
|
|
120096
|
+
this.blockPosition = new Vector3();
|
|
119666
120097
|
this.meshDirty = false;
|
|
120098
|
+
this.meshGeneration = 0;
|
|
119667
120099
|
this.scene = scene;
|
|
119668
120100
|
this.x = x4;
|
|
119669
120101
|
this.y = y5;
|
|
@@ -119676,7 +120108,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119676
120108
|
if (isTripleArray(posOrX)) {
|
|
119677
120109
|
return this.getBlockAt(new Vector3(posOrX[0], posOrX[1], posOrX[2]));
|
|
119678
120110
|
}
|
|
119679
|
-
const pos = this.
|
|
120111
|
+
const pos = this.blockPosition.set(posOrX.x - this.x * 16, posOrX.y - this.y * 16, posOrX.z - this.z * 16);
|
|
119680
120112
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
119681
120113
|
return this.renderedBlocks.get(index);
|
|
119682
120114
|
}
|
|
@@ -119700,48 +120132,81 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119700
120132
|
worldPos = this.chunkPosToWorldPos(pos);
|
|
119701
120133
|
}
|
|
119702
120134
|
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
120135
|
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;
|
|
120136
|
+
await this.placeBlocks([{ index, block }]);
|
|
120137
|
+
return this.renderedBlocks.get(index);
|
|
119741
120138
|
} finally {
|
|
119742
120139
|
await onBlocksChanged?.([worldPos]);
|
|
119743
120140
|
}
|
|
119744
120141
|
}
|
|
120142
|
+
/** Places cells in input order and returns changed world positions without refreshing neighbors. */
|
|
120143
|
+
async placeBlocks(blocks) {
|
|
120144
|
+
const resolutions = /* @__PURE__ */ new Map();
|
|
120145
|
+
for (const { block } of blocks) {
|
|
120146
|
+
if (!block || ChunkData.isAir(block)) continue;
|
|
120147
|
+
const key = ChunkData.paletteKey(block);
|
|
120148
|
+
if (resolutions.has(key)) continue;
|
|
120149
|
+
const stored = { type: block.type, properties: block.properties ? { ...block.properties } : void 0 };
|
|
120150
|
+
const resolved = (async () => {
|
|
120151
|
+
const blockState2 = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
|
|
120152
|
+
const perBlock = !blockState2 || !this.sectionModels || !!getFluidKind(blockState2.key, stored.properties) || !!(blockState2.key && BlockEntities.entry(await BlockEntities.getIndex(blockState2.key.root), blockState2.key.toNamespacedString()));
|
|
120153
|
+
if (!perBlock) await this.sectionModels.get(blockState2, stored.properties);
|
|
120154
|
+
return { blockState: blockState2, perBlock };
|
|
120155
|
+
})();
|
|
120156
|
+
resolutions.set(key, resolved);
|
|
120157
|
+
void resolved.catch(() => void 0);
|
|
120158
|
+
}
|
|
120159
|
+
const positions = [];
|
|
120160
|
+
let failed = false, failure;
|
|
120161
|
+
for (const { index, block } of blocks) {
|
|
120162
|
+
this.hiddenBlocks.delete(index);
|
|
120163
|
+
this.data.set(index, block);
|
|
120164
|
+
const readBlock = this.data.snapshot(index);
|
|
120165
|
+
this.renderedBlocks.get(index)?.object?.removeFromScene();
|
|
120166
|
+
if (this.sectionBlocks.delete(index)) this.meshDirty = true;
|
|
120167
|
+
this.renderedBlocks.delete(index);
|
|
120168
|
+
const worldPos = new Vector3(
|
|
120169
|
+
this.x * 16 + index % 16,
|
|
120170
|
+
this.y * 16 + Math.floor(index / 256),
|
|
120171
|
+
this.z * 16 + Math.floor(index / 16) % 16
|
|
120172
|
+
);
|
|
120173
|
+
positions.push(worldPos);
|
|
120174
|
+
let object3;
|
|
120175
|
+
try {
|
|
120176
|
+
if (!readBlock) continue;
|
|
120177
|
+
const stored = readBlock();
|
|
120178
|
+
const key = ChunkData.paletteKey(stored);
|
|
120179
|
+
const { blockState: blockState2, perBlock } = await resolutions.get(key);
|
|
120180
|
+
if (!blockState2) {
|
|
120181
|
+
this.data.set(index, void 0);
|
|
120182
|
+
continue;
|
|
120183
|
+
}
|
|
120184
|
+
const template = perBlock ? void 0 : await this.sectionModels.get(blockState2, stored.properties);
|
|
120185
|
+
if (template) {
|
|
120186
|
+
this.sectionBlocks.set(index, { index, template, cullMask: 0 });
|
|
120187
|
+
this.meshDirty = true;
|
|
120188
|
+
} else {
|
|
120189
|
+
object3 = await this.scene.addBlock(blockState2, {
|
|
120190
|
+
mergeMeshes: true,
|
|
120191
|
+
instanceMeshes: true,
|
|
120192
|
+
maxInstanceCount: 2e3,
|
|
120193
|
+
initialState: stored.properties
|
|
120194
|
+
});
|
|
120195
|
+
object3.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
|
|
120196
|
+
}
|
|
120197
|
+
this.renderedBlocks.set(index, { get block() {
|
|
120198
|
+
return readBlock();
|
|
120199
|
+
}, object: object3 });
|
|
120200
|
+
} catch (error2) {
|
|
120201
|
+
this.data.set(index, void 0);
|
|
120202
|
+
object3?.removeFromScene();
|
|
120203
|
+
if (!failed) failure = error2;
|
|
120204
|
+
failed = true;
|
|
120205
|
+
}
|
|
120206
|
+
}
|
|
120207
|
+
if (failed) throw failure;
|
|
120208
|
+
return positions;
|
|
120209
|
+
}
|
|
119745
120210
|
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
119746
120211
|
async setBlockVisibleAt(pos, visible) {
|
|
119747
120212
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
@@ -119762,15 +120227,24 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119762
120227
|
await this.onBlocksChanged?.([pos]);
|
|
119763
120228
|
}
|
|
119764
120229
|
isBlockVisibleAt(pos) {
|
|
119765
|
-
|
|
120230
|
+
return this.isBlockVisibleIndex(_Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos)));
|
|
120231
|
+
}
|
|
120232
|
+
/** Reports whether a cell has a visible render object or section entry. */
|
|
120233
|
+
isBlockVisibleIndex(index) {
|
|
119766
120234
|
return this.renderedBlocks.has(index) && !this.hiddenBlocks.has(index);
|
|
119767
120235
|
}
|
|
119768
120236
|
isOccludingAt(pos) {
|
|
119769
|
-
|
|
120237
|
+
return this.isOccludingIndex(_Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos)));
|
|
120238
|
+
}
|
|
120239
|
+
/** Reports whether a visible cell hides neighboring cube faces. */
|
|
120240
|
+
isOccludingIndex(index) {
|
|
119770
120241
|
return !this.hiddenBlocks.has(index) && (this.sectionBlocks.has(index) || (this.renderedBlocks.get(index)?.object?.isOccluding ?? false));
|
|
119771
120242
|
}
|
|
119772
120243
|
async setCullMaskAt(pos, mask) {
|
|
119773
|
-
|
|
120244
|
+
await this.setCullMaskIndex(_Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos)), mask);
|
|
120245
|
+
}
|
|
120246
|
+
/** Updates hidden faces for a cell's section entry or individual render object. */
|
|
120247
|
+
async setCullMaskIndex(index, mask) {
|
|
119774
120248
|
const entry = this.sectionBlocks.get(index);
|
|
119775
120249
|
if (entry) {
|
|
119776
120250
|
if (entry.cullMask !== mask) {
|
|
@@ -119781,12 +120255,17 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119781
120255
|
await this.renderedBlocks.get(index)?.object?.setCullMask(mask);
|
|
119782
120256
|
}
|
|
119783
120257
|
}
|
|
119784
|
-
|
|
120258
|
+
/** Rebuilds visible section geometry and discards results superseded by another rebuild or clear. */
|
|
120259
|
+
async rebuildSectionMesh() {
|
|
119785
120260
|
if (!this.meshDirty) return;
|
|
119786
|
-
|
|
119787
|
-
|
|
119788
|
-
|
|
119789
|
-
) : void 0;
|
|
120261
|
+
this.meshDirty = false;
|
|
120262
|
+
const generation = ++this.meshGeneration;
|
|
120263
|
+
const entries = [...this.sectionBlocks.values()].filter((entry) => !this.hiddenBlocks.has(entry.index));
|
|
120264
|
+
const next = entries.length ? await SectionMesh.buildAsync(entries, this.sectionModels.maxAtlasSize) : void 0;
|
|
120265
|
+
if (generation !== this.meshGeneration) {
|
|
120266
|
+
next?.dispose();
|
|
120267
|
+
return;
|
|
120268
|
+
}
|
|
119790
120269
|
this.sectionMesh?.dispose();
|
|
119791
120270
|
this.sectionMesh = next;
|
|
119792
120271
|
if (next) {
|
|
@@ -119794,7 +120273,6 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119794
120273
|
this.scene.add(next);
|
|
119795
120274
|
}
|
|
119796
120275
|
this.scene.dirty = true;
|
|
119797
|
-
this.meshDirty = false;
|
|
119798
120276
|
}
|
|
119799
120277
|
/** Removes stored blocks and their render objects, then notifies the owning world of changed positions. */
|
|
119800
120278
|
async clear(onBlocksChanged = this.onBlocksChanged) {
|
|
@@ -119803,6 +120281,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119803
120281
|
));
|
|
119804
120282
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
119805
120283
|
this.sectionBlocks.clear();
|
|
120284
|
+
this.meshGeneration++;
|
|
119806
120285
|
this.sectionMesh?.dispose();
|
|
119807
120286
|
this.sectionMesh = void 0;
|
|
119808
120287
|
this.meshDirty = false;
|