minerender 2.1.0-alpha.126 → 2.1.0-alpha.127
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 +18 -2
- package/dist/browser/index.d.ts +18 -2
- package/dist/browser/index.js +61 -4
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +61 -4
- package/dist/browser/index.mjs.map +1 -1
- package/dist/bundle.js +64 -4
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +18 -2
- package/dist/node/index.d.ts +18 -2
- package/dist/node/index.js +61 -4
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +61 -4
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/node/index.d.mts
CHANGED
|
@@ -1312,6 +1312,15 @@ interface MineRenderDatasets {
|
|
|
1312
1312
|
untinted?: number[];
|
|
1313
1313
|
biome?: BiomeColorKind;
|
|
1314
1314
|
}>;
|
|
1315
|
+
blockCulling: {
|
|
1316
|
+
profiles: {
|
|
1317
|
+
type: string;
|
|
1318
|
+
group?: string;
|
|
1319
|
+
kind?: string;
|
|
1320
|
+
}[];
|
|
1321
|
+
blocks: Record<string, number>;
|
|
1322
|
+
groups?: Record<string, string[]>;
|
|
1323
|
+
};
|
|
1315
1324
|
fluids: Record<string, {
|
|
1316
1325
|
kind: "water" | "lava";
|
|
1317
1326
|
renderModel: boolean;
|
|
@@ -3897,6 +3906,8 @@ interface WorldBlockIntersection {
|
|
|
3897
3906
|
distance: number;
|
|
3898
3907
|
}
|
|
3899
3908
|
|
|
3909
|
+
type BlockCullingData = MineRenderDatasets["blockCulling"];
|
|
3910
|
+
|
|
3900
3911
|
/**
|
|
3901
3912
|
* A 16×16×16 block section and its render objects.
|
|
3902
3913
|
* Constructor coordinates identify the section. Block accessors use world block coordinates
|
|
@@ -3973,6 +3984,8 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
3973
3984
|
isBlockVisibleAt(pos: Vector3): boolean;
|
|
3974
3985
|
/** Reports whether a cell has a visible render object or section entry. */
|
|
3975
3986
|
isBlockVisibleIndex(index: number): boolean;
|
|
3987
|
+
/** Stored state of a rendered, visible cell, or `undefined`. */
|
|
3988
|
+
visibleBlockIndex(index: number): Maybe<Pick<Block, "type" | "properties">>;
|
|
3976
3989
|
/** Fluid kind bits and level of a cell, or 0. Hidden cells report 0. */
|
|
3977
3990
|
fluidByteIndex(index: number): number;
|
|
3978
3991
|
/** Whether the cell holds a fluid, merged or per-block. */
|
|
@@ -3981,8 +3994,11 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
3981
3994
|
/** Reports whether a visible cell hides neighboring cube faces. */
|
|
3982
3995
|
isOccludingIndex(index: number): boolean;
|
|
3983
3996
|
setCullMaskAt(pos: Vector3, mask: number): Promise<void>;
|
|
3984
|
-
/**
|
|
3985
|
-
|
|
3997
|
+
/**
|
|
3998
|
+
* Recomputes section masks and returns changed per-block masks. Omit indices to visit every cell.
|
|
3999
|
+
* `culling` supplies neighbor face rules; `blockAt` supplies visible states outside this chunk.
|
|
4000
|
+
*/
|
|
4001
|
+
updateCullMasks(indices: Iterable<number> | undefined, occludes: (x: number, y: number, z: number) => boolean, culling?: BlockCullingData, blockAt?: (x: number, y: number, z: number) => Maybe<Pick<Block, "type" | "properties">>): [number, number][];
|
|
3986
4002
|
/** Updates hidden faces for a cell's section entry or individual render object. */
|
|
3987
4003
|
setCullMaskIndex(index: number, mask: number): Promise<void>;
|
|
3988
4004
|
/** Rebuilds visible section geometry and discards results superseded by another rebuild or clear. */
|
package/dist/node/index.d.ts
CHANGED
|
@@ -1312,6 +1312,15 @@ interface MineRenderDatasets {
|
|
|
1312
1312
|
untinted?: number[];
|
|
1313
1313
|
biome?: BiomeColorKind;
|
|
1314
1314
|
}>;
|
|
1315
|
+
blockCulling: {
|
|
1316
|
+
profiles: {
|
|
1317
|
+
type: string;
|
|
1318
|
+
group?: string;
|
|
1319
|
+
kind?: string;
|
|
1320
|
+
}[];
|
|
1321
|
+
blocks: Record<string, number>;
|
|
1322
|
+
groups?: Record<string, string[]>;
|
|
1323
|
+
};
|
|
1315
1324
|
fluids: Record<string, {
|
|
1316
1325
|
kind: "water" | "lava";
|
|
1317
1326
|
renderModel: boolean;
|
|
@@ -3897,6 +3906,8 @@ interface WorldBlockIntersection {
|
|
|
3897
3906
|
distance: number;
|
|
3898
3907
|
}
|
|
3899
3908
|
|
|
3909
|
+
type BlockCullingData = MineRenderDatasets["blockCulling"];
|
|
3910
|
+
|
|
3900
3911
|
/**
|
|
3901
3912
|
* A 16×16×16 block section and its render objects.
|
|
3902
3913
|
* Constructor coordinates identify the section. Block accessors use world block coordinates
|
|
@@ -3973,6 +3984,8 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
3973
3984
|
isBlockVisibleAt(pos: Vector3): boolean;
|
|
3974
3985
|
/** Reports whether a cell has a visible render object or section entry. */
|
|
3975
3986
|
isBlockVisibleIndex(index: number): boolean;
|
|
3987
|
+
/** Stored state of a rendered, visible cell, or `undefined`. */
|
|
3988
|
+
visibleBlockIndex(index: number): Maybe<Pick<Block, "type" | "properties">>;
|
|
3976
3989
|
/** Fluid kind bits and level of a cell, or 0. Hidden cells report 0. */
|
|
3977
3990
|
fluidByteIndex(index: number): number;
|
|
3978
3991
|
/** Whether the cell holds a fluid, merged or per-block. */
|
|
@@ -3981,8 +3994,11 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
3981
3994
|
/** Reports whether a visible cell hides neighboring cube faces. */
|
|
3982
3995
|
isOccludingIndex(index: number): boolean;
|
|
3983
3996
|
setCullMaskAt(pos: Vector3, mask: number): Promise<void>;
|
|
3984
|
-
/**
|
|
3985
|
-
|
|
3997
|
+
/**
|
|
3998
|
+
* Recomputes section masks and returns changed per-block masks. Omit indices to visit every cell.
|
|
3999
|
+
* `culling` supplies neighbor face rules; `blockAt` supplies visible states outside this chunk.
|
|
4000
|
+
*/
|
|
4001
|
+
updateCullMasks(indices: Iterable<number> | undefined, occludes: (x: number, y: number, z: number) => boolean, culling?: BlockCullingData, blockAt?: (x: number, y: number, z: number) => Maybe<Pick<Block, "type" | "properties">>): [number, number][];
|
|
3986
4002
|
/** Updates hidden faces for a cell's section entry or individual render object. */
|
|
3987
4003
|
setCullMaskIndex(index: number, mask: number): Promise<void>;
|
|
3988
4004
|
/** Rebuilds visible section geometry and discards results superseded by another rebuild or clear. */
|
package/dist/node/index.js
CHANGED
|
@@ -1733,6 +1733,7 @@ ${key}` : key, async () => {
|
|
|
1733
1733
|
if (!object(data)) return false;
|
|
1734
1734
|
if (dataset === "potionColors") return object(data.effects) && Object.values(data.effects).every(Number.isInteger) && object(data.potions) && Object.values(data.potions).every((effects) => Array.isArray(effects) && effects.every((effect) => object(effect) && typeof effect.id === "string" && Number.isInteger(effect.amplifier)));
|
|
1735
1735
|
if (dataset === "legacyBlocks") return object(data.blocks) && Object.values(data.blocks).every((value) => typeof value === "string");
|
|
1736
|
+
if (dataset === "blockCulling") return Array.isArray(data.profiles) && data.profiles.every((profile) => object(profile) && typeof profile.type === "string") && object(data.blocks) && Object.values(data.blocks).every((index) => Number.isInteger(index) && index >= 0 && index < data.profiles.length) && (data.groups === void 0 || object(data.groups) && Object.values(data.groups).every((group) => Array.isArray(group) && group.every((type) => typeof type === "string")));
|
|
1736
1737
|
return Object.values(data).every((value) => {
|
|
1737
1738
|
if (!object(value)) return false;
|
|
1738
1739
|
switch (dataset) {
|
|
@@ -17834,6 +17835,38 @@ function sampleSectionLight(light, index) {
|
|
|
17834
17835
|
};
|
|
17835
17836
|
}
|
|
17836
17837
|
|
|
17838
|
+
// src/world/_culling/BlockCulling.ts
|
|
17839
|
+
init_Assets();
|
|
17840
|
+
init_MineRenderData();
|
|
17841
|
+
init_CubeFace();
|
|
17842
|
+
async function loadBlockCulling(root) {
|
|
17843
|
+
const { manifest } = await MineRenderData.resolve(root);
|
|
17844
|
+
return manifest.datasets.blockCulling ? MineRenderData.get("blockCulling", root) : void 0;
|
|
17845
|
+
}
|
|
17846
|
+
function blockCullingRule(data, type) {
|
|
17847
|
+
if (!type.includes(":")) type = `${DEFAULT_NAMESPACE}:${type}`;
|
|
17848
|
+
return Object.prototype.hasOwnProperty.call(data.blocks, type) ? data.profiles[data.blocks[type]] : void 0;
|
|
17849
|
+
}
|
|
17850
|
+
function skipsBlockFace(data, rule, block, neighbor, face) {
|
|
17851
|
+
const type = block.type.includes(":") ? block.type : `${DEFAULT_NAMESPACE}:${block.type}`;
|
|
17852
|
+
const other = neighbor.type.includes(":") ? neighbor.type : `${DEFAULT_NAMESPACE}:${neighbor.type}`;
|
|
17853
|
+
const same = type === other;
|
|
17854
|
+
const vertical = CUBE_FACES[face] === "up" /* UP */ || CUBE_FACES[face] === "down" /* DOWN */;
|
|
17855
|
+
switch (rule.type) {
|
|
17856
|
+
case "same_block":
|
|
17857
|
+
return same;
|
|
17858
|
+
case "same_block_vertical":
|
|
17859
|
+
return same && vertical;
|
|
17860
|
+
case "connected": {
|
|
17861
|
+
if (vertical) return same;
|
|
17862
|
+
const group = rule.group ? data.groups?.[rule.group] : void 0;
|
|
17863
|
+
return (same || !!group?.includes(type) && group.includes(other)) && String(block.properties?.[CUBE_FACES[face]]) === "true" && String(neighbor.properties?.[CUBE_FACES[face ^ 1]]) === "true";
|
|
17864
|
+
}
|
|
17865
|
+
default:
|
|
17866
|
+
return false;
|
|
17867
|
+
}
|
|
17868
|
+
}
|
|
17869
|
+
|
|
17837
17870
|
// src/world/MineRenderWorld.ts
|
|
17838
17871
|
var MineRenderWorld = class {
|
|
17839
17872
|
constructor(scene, options = {}) {
|
|
@@ -18222,15 +18255,23 @@ var MineRenderWorld = class {
|
|
|
18222
18255
|
return this.culling ??= Promise.resolve().then(async () => {
|
|
18223
18256
|
let sliceStart = performance.now();
|
|
18224
18257
|
try {
|
|
18258
|
+
const culling = await loadBlockCulling();
|
|
18225
18259
|
while (this.pendingCulling.size) {
|
|
18226
18260
|
const batch = [...this.pendingCulling];
|
|
18227
18261
|
this.pendingCulling.clear();
|
|
18228
18262
|
for (const [chunk, indices] of batch) {
|
|
18229
18263
|
const neighbors = CUBE_FACE_OFFSETS.map(([x, y, z]) => this._chunks.get(`${chunk.x + x}_${chunk.y + y}_${chunk.z + z}`));
|
|
18230
|
-
const
|
|
18264
|
+
const neighborAt = (x, y, z) => {
|
|
18231
18265
|
const lx = x - chunk.x * 16, ly = y - chunk.y * 16, lz = z - chunk.z * 16;
|
|
18232
18266
|
const section = neighbors[lx >= 16 ? 0 : lx < 0 ? 1 : ly >= 16 ? 2 : ly < 0 ? 3 : lz >= 16 ? 4 : 5];
|
|
18233
|
-
return section
|
|
18267
|
+
return [section, (ly & 15) * 256 + (lz & 15) * 16 + (lx & 15)];
|
|
18268
|
+
};
|
|
18269
|
+
const masks = chunk.updateCullMasks(indices === "all" ? void 0 : indices, (x, y, z) => {
|
|
18270
|
+
const [section, i] = neighborAt(x, y, z);
|
|
18271
|
+
return section?.isOccludingIndex(i) ?? false;
|
|
18272
|
+
}, culling, (x, y, z) => {
|
|
18273
|
+
const [section, i] = neighborAt(x, y, z);
|
|
18274
|
+
return section?.visibleBlockIndex(i);
|
|
18234
18275
|
});
|
|
18235
18276
|
const fluidIndices = indices === "all" ? function* () {
|
|
18236
18277
|
for (let index = 0; index < 4096; index++) yield index;
|
|
@@ -19346,6 +19387,10 @@ var Chunk = class _Chunk {
|
|
|
19346
19387
|
isBlockVisibleIndex(index) {
|
|
19347
19388
|
return this.renderedBlocks.has(index) && !this.hiddenBlocks.has(index);
|
|
19348
19389
|
}
|
|
19390
|
+
/** Stored state of a rendered, visible cell, or `undefined`. */
|
|
19391
|
+
visibleBlockIndex(index) {
|
|
19392
|
+
return this.isBlockVisibleIndex(index) ? this.data.stateAt(this.data.idAt(index)) : void 0;
|
|
19393
|
+
}
|
|
19349
19394
|
/** Fluid kind bits and level of a cell, or 0. Hidden cells report 0. */
|
|
19350
19395
|
fluidByteIndex(index) {
|
|
19351
19396
|
return this.hiddenBlocks.has(index) ? 0 : this.fluidCells[index];
|
|
@@ -19364,18 +19409,30 @@ var Chunk = class _Chunk {
|
|
|
19364
19409
|
async setCullMaskAt(pos, mask) {
|
|
19365
19410
|
await this.setCullMaskIndex(_Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos)), mask);
|
|
19366
19411
|
}
|
|
19367
|
-
/**
|
|
19368
|
-
|
|
19412
|
+
/**
|
|
19413
|
+
* Recomputes section masks and returns changed per-block masks. Omit indices to visit every cell.
|
|
19414
|
+
* `culling` supplies neighbor face rules; `blockAt` supplies visible states outside this chunk.
|
|
19415
|
+
*/
|
|
19416
|
+
updateCullMasks(indices, occludes, culling, blockAt) {
|
|
19369
19417
|
const changed = [];
|
|
19418
|
+
const rules = [];
|
|
19370
19419
|
for (const index of indices ?? this.fluidCells.keys()) {
|
|
19371
19420
|
if (!this.isBlockVisibleIndex(index)) continue;
|
|
19372
19421
|
const x = index % 16, y = Math.floor(index / 256), z = Math.floor(index / 16) % 16;
|
|
19422
|
+
const id = this.data.idAt(index);
|
|
19423
|
+
let rule = rules[id];
|
|
19424
|
+
if (culling && rule === void 0) rules[id] = rule = blockCullingRule(culling, this.data.stateAt(id).type) ?? null;
|
|
19425
|
+
const block = rule ? this.data.stateAt(id) : void 0;
|
|
19373
19426
|
let mask = 0;
|
|
19374
19427
|
for (let face = 0; face < CUBE_FACE_OFFSETS.length; face++) {
|
|
19375
19428
|
const [dx, dy, dz] = CUBE_FACE_OFFSETS[face];
|
|
19376
19429
|
const nx = x + dx, ny = y + dy, nz = z + dz;
|
|
19377
19430
|
const inner = nx >= 0 && nx < 16 && ny >= 0 && ny < 16 && nz >= 0 && nz < 16;
|
|
19378
19431
|
if (inner ? this.isOccludingIndex(ny * 256 + nz * 16 + nx) : occludes(this.x * 16 + nx, this.y * 16 + ny, this.z * 16 + nz)) mask |= 1 << face;
|
|
19432
|
+
else if (rule) {
|
|
19433
|
+
const neighbor = inner ? this.visibleBlockIndex(ny * 256 + nz * 16 + nx) : blockAt?.(this.x * 16 + nx, this.y * 16 + ny, this.z * 16 + nz);
|
|
19434
|
+
if (neighbor && skipsBlockFace(culling, rule, block, neighbor, face)) mask |= 1 << face;
|
|
19435
|
+
}
|
|
19379
19436
|
}
|
|
19380
19437
|
if (this.fluidCells[index]) this.meshDirty = true;
|
|
19381
19438
|
const entries = this.sectionBlocks.get(index);
|