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/browser/index.d.mts
CHANGED
|
@@ -1310,6 +1310,15 @@ interface MineRenderDatasets {
|
|
|
1310
1310
|
untinted?: number[];
|
|
1311
1311
|
biome?: BiomeColorKind;
|
|
1312
1312
|
}>;
|
|
1313
|
+
blockCulling: {
|
|
1314
|
+
profiles: {
|
|
1315
|
+
type: string;
|
|
1316
|
+
group?: string;
|
|
1317
|
+
kind?: string;
|
|
1318
|
+
}[];
|
|
1319
|
+
blocks: Record<string, number>;
|
|
1320
|
+
groups?: Record<string, string[]>;
|
|
1321
|
+
};
|
|
1313
1322
|
fluids: Record<string, {
|
|
1314
1323
|
kind: "water" | "lava";
|
|
1315
1324
|
renderModel: boolean;
|
|
@@ -3895,6 +3904,8 @@ interface WorldBlockIntersection {
|
|
|
3895
3904
|
distance: number;
|
|
3896
3905
|
}
|
|
3897
3906
|
|
|
3907
|
+
type BlockCullingData = MineRenderDatasets["blockCulling"];
|
|
3908
|
+
|
|
3898
3909
|
/**
|
|
3899
3910
|
* A 16×16×16 block section and its render objects.
|
|
3900
3911
|
* Constructor coordinates identify the section. Block accessors use world block coordinates
|
|
@@ -3971,6 +3982,8 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
3971
3982
|
isBlockVisibleAt(pos: Vector3): boolean;
|
|
3972
3983
|
/** Reports whether a cell has a visible render object or section entry. */
|
|
3973
3984
|
isBlockVisibleIndex(index: number): boolean;
|
|
3985
|
+
/** Stored state of a rendered, visible cell, or `undefined`. */
|
|
3986
|
+
visibleBlockIndex(index: number): Maybe<Pick<Block, "type" | "properties">>;
|
|
3974
3987
|
/** Fluid kind bits and level of a cell, or 0. Hidden cells report 0. */
|
|
3975
3988
|
fluidByteIndex(index: number): number;
|
|
3976
3989
|
/** Whether the cell holds a fluid, merged or per-block. */
|
|
@@ -3979,8 +3992,11 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
3979
3992
|
/** Reports whether a visible cell hides neighboring cube faces. */
|
|
3980
3993
|
isOccludingIndex(index: number): boolean;
|
|
3981
3994
|
setCullMaskAt(pos: Vector3, mask: number): Promise<void>;
|
|
3982
|
-
/**
|
|
3983
|
-
|
|
3995
|
+
/**
|
|
3996
|
+
* Recomputes section masks and returns changed per-block masks. Omit indices to visit every cell.
|
|
3997
|
+
* `culling` supplies neighbor face rules; `blockAt` supplies visible states outside this chunk.
|
|
3998
|
+
*/
|
|
3999
|
+
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][];
|
|
3984
4000
|
/** Updates hidden faces for a cell's section entry or individual render object. */
|
|
3985
4001
|
setCullMaskIndex(index: number, mask: number): Promise<void>;
|
|
3986
4002
|
/** Rebuilds visible section geometry and discards results superseded by another rebuild or clear. */
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -1310,6 +1310,15 @@ interface MineRenderDatasets {
|
|
|
1310
1310
|
untinted?: number[];
|
|
1311
1311
|
biome?: BiomeColorKind;
|
|
1312
1312
|
}>;
|
|
1313
|
+
blockCulling: {
|
|
1314
|
+
profiles: {
|
|
1315
|
+
type: string;
|
|
1316
|
+
group?: string;
|
|
1317
|
+
kind?: string;
|
|
1318
|
+
}[];
|
|
1319
|
+
blocks: Record<string, number>;
|
|
1320
|
+
groups?: Record<string, string[]>;
|
|
1321
|
+
};
|
|
1313
1322
|
fluids: Record<string, {
|
|
1314
1323
|
kind: "water" | "lava";
|
|
1315
1324
|
renderModel: boolean;
|
|
@@ -3895,6 +3904,8 @@ interface WorldBlockIntersection {
|
|
|
3895
3904
|
distance: number;
|
|
3896
3905
|
}
|
|
3897
3906
|
|
|
3907
|
+
type BlockCullingData = MineRenderDatasets["blockCulling"];
|
|
3908
|
+
|
|
3898
3909
|
/**
|
|
3899
3910
|
* A 16×16×16 block section and its render objects.
|
|
3900
3911
|
* Constructor coordinates identify the section. Block accessors use world block coordinates
|
|
@@ -3971,6 +3982,8 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
3971
3982
|
isBlockVisibleAt(pos: Vector3): boolean;
|
|
3972
3983
|
/** Reports whether a cell has a visible render object or section entry. */
|
|
3973
3984
|
isBlockVisibleIndex(index: number): boolean;
|
|
3985
|
+
/** Stored state of a rendered, visible cell, or `undefined`. */
|
|
3986
|
+
visibleBlockIndex(index: number): Maybe<Pick<Block, "type" | "properties">>;
|
|
3974
3987
|
/** Fluid kind bits and level of a cell, or 0. Hidden cells report 0. */
|
|
3975
3988
|
fluidByteIndex(index: number): number;
|
|
3976
3989
|
/** Whether the cell holds a fluid, merged or per-block. */
|
|
@@ -3979,8 +3992,11 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
3979
3992
|
/** Reports whether a visible cell hides neighboring cube faces. */
|
|
3980
3993
|
isOccludingIndex(index: number): boolean;
|
|
3981
3994
|
setCullMaskAt(pos: Vector3, mask: number): Promise<void>;
|
|
3982
|
-
/**
|
|
3983
|
-
|
|
3995
|
+
/**
|
|
3996
|
+
* Recomputes section masks and returns changed per-block masks. Omit indices to visit every cell.
|
|
3997
|
+
* `culling` supplies neighbor face rules; `blockAt` supplies visible states outside this chunk.
|
|
3998
|
+
*/
|
|
3999
|
+
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][];
|
|
3984
4000
|
/** Updates hidden faces for a cell's section entry or individual render object. */
|
|
3985
4001
|
setCullMaskIndex(index: number, mask: number): Promise<void>;
|
|
3986
4002
|
/** Rebuilds visible section geometry and discards results superseded by another rebuild or clear. */
|
package/dist/browser/index.js
CHANGED
|
@@ -1677,6 +1677,7 @@ ${key}` : key, async () => {
|
|
|
1677
1677
|
if (!object(data)) return false;
|
|
1678
1678
|
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)));
|
|
1679
1679
|
if (dataset === "legacyBlocks") return object(data.blocks) && Object.values(data.blocks).every((value) => typeof value === "string");
|
|
1680
|
+
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")));
|
|
1680
1681
|
return Object.values(data).every((value) => {
|
|
1681
1682
|
if (!object(value)) return false;
|
|
1682
1683
|
switch (dataset) {
|
|
@@ -17799,6 +17800,38 @@ function sampleSectionLight(light, index) {
|
|
|
17799
17800
|
};
|
|
17800
17801
|
}
|
|
17801
17802
|
|
|
17803
|
+
// src/world/_culling/BlockCulling.ts
|
|
17804
|
+
init_Assets();
|
|
17805
|
+
init_MineRenderData();
|
|
17806
|
+
init_CubeFace();
|
|
17807
|
+
async function loadBlockCulling(root) {
|
|
17808
|
+
const { manifest } = await MineRenderData.resolve(root);
|
|
17809
|
+
return manifest.datasets.blockCulling ? MineRenderData.get("blockCulling", root) : void 0;
|
|
17810
|
+
}
|
|
17811
|
+
function blockCullingRule(data, type) {
|
|
17812
|
+
if (!type.includes(":")) type = `${DEFAULT_NAMESPACE}:${type}`;
|
|
17813
|
+
return Object.prototype.hasOwnProperty.call(data.blocks, type) ? data.profiles[data.blocks[type]] : void 0;
|
|
17814
|
+
}
|
|
17815
|
+
function skipsBlockFace(data, rule, block, neighbor, face) {
|
|
17816
|
+
const type = block.type.includes(":") ? block.type : `${DEFAULT_NAMESPACE}:${block.type}`;
|
|
17817
|
+
const other = neighbor.type.includes(":") ? neighbor.type : `${DEFAULT_NAMESPACE}:${neighbor.type}`;
|
|
17818
|
+
const same = type === other;
|
|
17819
|
+
const vertical = CUBE_FACES[face] === "up" /* UP */ || CUBE_FACES[face] === "down" /* DOWN */;
|
|
17820
|
+
switch (rule.type) {
|
|
17821
|
+
case "same_block":
|
|
17822
|
+
return same;
|
|
17823
|
+
case "same_block_vertical":
|
|
17824
|
+
return same && vertical;
|
|
17825
|
+
case "connected": {
|
|
17826
|
+
if (vertical) return same;
|
|
17827
|
+
const group = rule.group ? data.groups?.[rule.group] : void 0;
|
|
17828
|
+
return (same || !!group?.includes(type) && group.includes(other)) && String(block.properties?.[CUBE_FACES[face]]) === "true" && String(neighbor.properties?.[CUBE_FACES[face ^ 1]]) === "true";
|
|
17829
|
+
}
|
|
17830
|
+
default:
|
|
17831
|
+
return false;
|
|
17832
|
+
}
|
|
17833
|
+
}
|
|
17834
|
+
|
|
17802
17835
|
// src/world/MineRenderWorld.ts
|
|
17803
17836
|
var MineRenderWorld = class {
|
|
17804
17837
|
constructor(scene, options = {}) {
|
|
@@ -18187,15 +18220,23 @@ var MineRenderWorld = class {
|
|
|
18187
18220
|
return this.culling ?? (this.culling = Promise.resolve().then(async () => {
|
|
18188
18221
|
let sliceStart = performance.now();
|
|
18189
18222
|
try {
|
|
18223
|
+
const culling = await loadBlockCulling();
|
|
18190
18224
|
while (this.pendingCulling.size) {
|
|
18191
18225
|
const batch = [...this.pendingCulling];
|
|
18192
18226
|
this.pendingCulling.clear();
|
|
18193
18227
|
for (const [chunk, indices] of batch) {
|
|
18194
18228
|
const neighbors = CUBE_FACE_OFFSETS.map(([x, y, z]) => this._chunks.get(`${chunk.x + x}_${chunk.y + y}_${chunk.z + z}`));
|
|
18195
|
-
const
|
|
18229
|
+
const neighborAt = (x, y, z) => {
|
|
18196
18230
|
const lx = x - chunk.x * 16, ly = y - chunk.y * 16, lz = z - chunk.z * 16;
|
|
18197
18231
|
const section = neighbors[lx >= 16 ? 0 : lx < 0 ? 1 : ly >= 16 ? 2 : ly < 0 ? 3 : lz >= 16 ? 4 : 5];
|
|
18198
|
-
return section
|
|
18232
|
+
return [section, (ly & 15) * 256 + (lz & 15) * 16 + (lx & 15)];
|
|
18233
|
+
};
|
|
18234
|
+
const masks = chunk.updateCullMasks(indices === "all" ? void 0 : indices, (x, y, z) => {
|
|
18235
|
+
const [section, i] = neighborAt(x, y, z);
|
|
18236
|
+
return section?.isOccludingIndex(i) ?? false;
|
|
18237
|
+
}, culling, (x, y, z) => {
|
|
18238
|
+
const [section, i] = neighborAt(x, y, z);
|
|
18239
|
+
return section?.visibleBlockIndex(i);
|
|
18199
18240
|
});
|
|
18200
18241
|
const fluidIndices = indices === "all" ? function* () {
|
|
18201
18242
|
for (let index = 0; index < 4096; index++) yield index;
|
|
@@ -19310,6 +19351,10 @@ var Chunk = class _Chunk {
|
|
|
19310
19351
|
isBlockVisibleIndex(index) {
|
|
19311
19352
|
return this.renderedBlocks.has(index) && !this.hiddenBlocks.has(index);
|
|
19312
19353
|
}
|
|
19354
|
+
/** Stored state of a rendered, visible cell, or `undefined`. */
|
|
19355
|
+
visibleBlockIndex(index) {
|
|
19356
|
+
return this.isBlockVisibleIndex(index) ? this.data.stateAt(this.data.idAt(index)) : void 0;
|
|
19357
|
+
}
|
|
19313
19358
|
/** Fluid kind bits and level of a cell, or 0. Hidden cells report 0. */
|
|
19314
19359
|
fluidByteIndex(index) {
|
|
19315
19360
|
return this.hiddenBlocks.has(index) ? 0 : this.fluidCells[index];
|
|
@@ -19328,18 +19373,30 @@ var Chunk = class _Chunk {
|
|
|
19328
19373
|
async setCullMaskAt(pos, mask) {
|
|
19329
19374
|
await this.setCullMaskIndex(_Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos)), mask);
|
|
19330
19375
|
}
|
|
19331
|
-
/**
|
|
19332
|
-
|
|
19376
|
+
/**
|
|
19377
|
+
* Recomputes section masks and returns changed per-block masks. Omit indices to visit every cell.
|
|
19378
|
+
* `culling` supplies neighbor face rules; `blockAt` supplies visible states outside this chunk.
|
|
19379
|
+
*/
|
|
19380
|
+
updateCullMasks(indices, occludes, culling, blockAt) {
|
|
19333
19381
|
const changed = [];
|
|
19382
|
+
const rules = [];
|
|
19334
19383
|
for (const index of indices ?? this.fluidCells.keys()) {
|
|
19335
19384
|
if (!this.isBlockVisibleIndex(index)) continue;
|
|
19336
19385
|
const x = index % 16, y = Math.floor(index / 256), z = Math.floor(index / 16) % 16;
|
|
19386
|
+
const id = this.data.idAt(index);
|
|
19387
|
+
let rule = rules[id];
|
|
19388
|
+
if (culling && rule === void 0) rules[id] = rule = blockCullingRule(culling, this.data.stateAt(id).type) ?? null;
|
|
19389
|
+
const block = rule ? this.data.stateAt(id) : void 0;
|
|
19337
19390
|
let mask = 0;
|
|
19338
19391
|
for (let face = 0; face < CUBE_FACE_OFFSETS.length; face++) {
|
|
19339
19392
|
const [dx, dy, dz] = CUBE_FACE_OFFSETS[face];
|
|
19340
19393
|
const nx = x + dx, ny = y + dy, nz = z + dz;
|
|
19341
19394
|
const inner = nx >= 0 && nx < 16 && ny >= 0 && ny < 16 && nz >= 0 && nz < 16;
|
|
19342
19395
|
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;
|
|
19396
|
+
else if (rule) {
|
|
19397
|
+
const neighbor = inner ? this.visibleBlockIndex(ny * 256 + nz * 16 + nx) : blockAt?.(this.x * 16 + nx, this.y * 16 + ny, this.z * 16 + nz);
|
|
19398
|
+
if (neighbor && skipsBlockFace(culling, rule, block, neighbor, face)) mask |= 1 << face;
|
|
19399
|
+
}
|
|
19343
19400
|
}
|
|
19344
19401
|
if (this.fluidCells[index]) this.meshDirty = true;
|
|
19345
19402
|
const entries = this.sectionBlocks.get(index);
|