minerender 2.1.0-alpha.53 → 2.1.0-alpha.55
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 +297 -39
- package/dist/browser/index.d.ts +297 -39
- package/dist/browser/index.js +752 -279
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +536 -63
- package/dist/browser/index.mjs.map +1 -1
- package/dist/bundle.js +505 -23
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +297 -39
- package/dist/node/index.d.ts +297 -39
- package/dist/node/index.js +762 -279
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +540 -63
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/bundle.js
CHANGED
|
@@ -32176,7 +32176,9 @@ var MineRender = (() => {
|
|
|
32176
32176
|
this.defaultBlockStatesCache,
|
|
32177
32177
|
this.blockTintCache,
|
|
32178
32178
|
this.entityModelCache,
|
|
32179
|
-
this.entityTextureCache
|
|
32179
|
+
this.entityTextureCache,
|
|
32180
|
+
this.entityAnimationCache,
|
|
32181
|
+
this.blockEntityIndexCache
|
|
32180
32182
|
];
|
|
32181
32183
|
}
|
|
32182
32184
|
static clear() {
|
|
@@ -32221,6 +32223,8 @@ var MineRender = (() => {
|
|
|
32221
32223
|
_Caching.blockTintCache = _Caching.createAssetCache();
|
|
32222
32224
|
_Caching.entityModelCache = _Caching.createAssetCache();
|
|
32223
32225
|
_Caching.entityTextureCache = _Caching.createAssetCache();
|
|
32226
|
+
_Caching.entityAnimationCache = _Caching.createAssetCache();
|
|
32227
|
+
_Caching.blockEntityIndexCache = _Caching.createAssetCache();
|
|
32224
32228
|
Caching = _Caching;
|
|
32225
32229
|
}
|
|
32226
32230
|
});
|
|
@@ -33153,6 +33157,71 @@ var MineRender = (() => {
|
|
|
33153
33157
|
alphaTest: 0.5
|
|
33154
33158
|
});
|
|
33155
33159
|
}
|
|
33160
|
+
/** Whether vanilla's render type for the mode culls back faces. */
|
|
33161
|
+
static entityModeCulls(mode2 = "cutout") {
|
|
33162
|
+
return mode2 === "cutout_cull" || mode2 === "solid" || mode2 === "eyes" || mode2 === "water_mask";
|
|
33163
|
+
}
|
|
33164
|
+
/** UV offset per tick of entity age for the scrolling modes, as vanilla's texture matrix applies it. */
|
|
33165
|
+
static entityModeScroll(mode2 = "cutout") {
|
|
33166
|
+
if (mode2 === "energy_swirl") return [0.01, 0.01];
|
|
33167
|
+
if (mode2 === "breeze_wind") return [0.02, 0];
|
|
33168
|
+
return void 0;
|
|
33169
|
+
}
|
|
33170
|
+
/**
|
|
33171
|
+
* Entity material for one of vanilla's render types. Entities are unlit here, so the lit and full-bright modes
|
|
33172
|
+
* differ only in blending and depth state. Culling is not a material property: {@link entityModeCulls} decides
|
|
33173
|
+
* whether the geometry gets inward faces.
|
|
33174
|
+
*/
|
|
33175
|
+
static createEntityCanvasMaterial(canvas, mode2 = "cutout", tint) {
|
|
33176
|
+
const material = _Materials.createBasicCanvasMaterial(canvas);
|
|
33177
|
+
switch (mode2) {
|
|
33178
|
+
case "cutout":
|
|
33179
|
+
case "cutout_cull":
|
|
33180
|
+
break;
|
|
33181
|
+
case "cutout_z_offset":
|
|
33182
|
+
material.polygonOffset = true;
|
|
33183
|
+
material.polygonOffsetFactor = -1;
|
|
33184
|
+
material.polygonOffsetUnits = -10;
|
|
33185
|
+
break;
|
|
33186
|
+
case "solid":
|
|
33187
|
+
material.alphaTest = 0;
|
|
33188
|
+
break;
|
|
33189
|
+
case "translucent":
|
|
33190
|
+
case "breeze_wind":
|
|
33191
|
+
material.transparent = true;
|
|
33192
|
+
material.alphaTest = 0.1;
|
|
33193
|
+
break;
|
|
33194
|
+
case "translucent_emissive":
|
|
33195
|
+
material.transparent = true;
|
|
33196
|
+
material.alphaTest = 0.1;
|
|
33197
|
+
material.depthWrite = false;
|
|
33198
|
+
break;
|
|
33199
|
+
case "eyes":
|
|
33200
|
+
material.transparent = true;
|
|
33201
|
+
material.alphaTest = 0;
|
|
33202
|
+
material.depthWrite = false;
|
|
33203
|
+
break;
|
|
33204
|
+
case "energy_swirl":
|
|
33205
|
+
material.transparent = true;
|
|
33206
|
+
material.alphaTest = 0.1;
|
|
33207
|
+
material.blending = CustomBlending;
|
|
33208
|
+
material.blendSrc = OneFactor;
|
|
33209
|
+
material.blendDst = OneFactor;
|
|
33210
|
+
material.blendSrcAlpha = ZeroFactor;
|
|
33211
|
+
material.blendDstAlpha = OneFactor;
|
|
33212
|
+
material.color.set(8421504);
|
|
33213
|
+
break;
|
|
33214
|
+
case "water_mask":
|
|
33215
|
+
material.alphaTest = 0;
|
|
33216
|
+
material.colorWrite = false;
|
|
33217
|
+
break;
|
|
33218
|
+
}
|
|
33219
|
+
if (_Materials.entityModeScroll(mode2)) {
|
|
33220
|
+
material.map.wrapS = material.map.wrapT = RepeatWrapping;
|
|
33221
|
+
}
|
|
33222
|
+
if (tint !== void 0) material.color.multiply(new Color(tint));
|
|
33223
|
+
return material;
|
|
33224
|
+
}
|
|
33156
33225
|
static createGuiCanvasMaterial(canvas) {
|
|
33157
33226
|
const material = new MeshBasicMaterial({
|
|
33158
33227
|
map: Textures.createCanvasTexture(canvas),
|
|
@@ -82977,6 +83046,7 @@ ${key}` : key;
|
|
|
82977
83046
|
BUILTIN_GENERATED: () => BUILTIN_GENERATED,
|
|
82978
83047
|
BasicAssetKey: () => BasicAssetKey,
|
|
82979
83048
|
BatchedExecutor: () => BatchedExecutor,
|
|
83049
|
+
BlockEntities: () => BlockEntities,
|
|
82980
83050
|
BlockObject: () => BlockObject,
|
|
82981
83051
|
BlockStateResolver: () => BlockStateResolver,
|
|
82982
83052
|
BlockStates: () => BlockStates,
|
|
@@ -83000,7 +83070,9 @@ ${key}` : key;
|
|
|
83000
83070
|
DefaultBlockStates: () => DefaultBlockStates,
|
|
83001
83071
|
DisplayPosition: () => DisplayPosition,
|
|
83002
83072
|
DisplayTransforms: () => DisplayTransforms,
|
|
83073
|
+
ENTITY_ANIMATION_CHANNELS: () => ENTITY_ANIMATION_CHANNELS,
|
|
83003
83074
|
Entities: () => Entities,
|
|
83075
|
+
EntityAnimationPlayer: () => EntityAnimationPlayer,
|
|
83004
83076
|
EntityObject: () => EntityObject,
|
|
83005
83077
|
Env: () => Env,
|
|
83006
83078
|
FluidModelObject: () => FluidModelObject,
|
|
@@ -83074,6 +83146,7 @@ ${key}` : key;
|
|
|
83074
83146
|
createCanvas: () => createCanvas,
|
|
83075
83147
|
createFluidGeometry: () => createFluidGeometry,
|
|
83076
83148
|
createImage: () => createImage,
|
|
83149
|
+
entityAnimationTime: () => entityAnimationTime,
|
|
83077
83150
|
estimateBytesUsed: () => estimateBytesUsed,
|
|
83078
83151
|
getBlockFluidState: () => getBlockFluidState,
|
|
83079
83152
|
getFluidKind: () => getFluidKind,
|
|
@@ -83107,6 +83180,8 @@ ${key}` : key;
|
|
|
83107
83180
|
prefix: () => prefix,
|
|
83108
83181
|
probeImageSize: () => probeImageSize,
|
|
83109
83182
|
registerBrowserEnv: () => registerBrowserEnv,
|
|
83183
|
+
sampleEntityAnimation: () => sampleEntityAnimation,
|
|
83184
|
+
sampleEntityKeyframes: () => sampleEntityKeyframes,
|
|
83110
83185
|
sampleFluid: () => sampleFluid,
|
|
83111
83186
|
serializeBoxGeometryKey: () => serializeBoxGeometryKey,
|
|
83112
83187
|
serializeImageKey: () => serializeImageKey,
|
|
@@ -83478,6 +83553,62 @@ ${key}` : key;
|
|
|
83478
83553
|
init_AssetKey();
|
|
83479
83554
|
init_AssetLoader();
|
|
83480
83555
|
init_Assets();
|
|
83556
|
+
|
|
83557
|
+
// src/assets/BlockEntities.ts
|
|
83558
|
+
init_dirname();
|
|
83559
|
+
init_buffer2();
|
|
83560
|
+
init_process2();
|
|
83561
|
+
init_three_module();
|
|
83562
|
+
init_AssetKey();
|
|
83563
|
+
init_AssetLoader();
|
|
83564
|
+
init_source();
|
|
83565
|
+
init_Caching();
|
|
83566
|
+
var BlockEntities = class {
|
|
83567
|
+
/**
|
|
83568
|
+
* Loads the block index of a version. Versions and sources without one yield an empty index, and so does
|
|
83569
|
+
* a failed load: the index is optional, and blocks must not retry or fail with it one by one. The empty
|
|
83570
|
+
* result is cached like any other; `Caching.clear()` or `AssetLoader.setVersion()` forces a new attempt.
|
|
83571
|
+
*/
|
|
83572
|
+
static async getIndex(root) {
|
|
83573
|
+
const key = new AssetKey("entity-models", "blocks", void 0, void 0, void 0, ".json", root);
|
|
83574
|
+
key.rootType = void 0;
|
|
83575
|
+
const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {
|
|
83576
|
+
try {
|
|
83577
|
+
return await AssetLoader.get(key, "json" /* JSON */) ?? {};
|
|
83578
|
+
} catch (error) {
|
|
83579
|
+
console.warn("Could not load the block entity index; block entities are drawn as plain block models", error);
|
|
83580
|
+
return {};
|
|
83581
|
+
}
|
|
83582
|
+
});
|
|
83583
|
+
return index ?? {};
|
|
83584
|
+
}
|
|
83585
|
+
/** The index entry of a block ID such as `minecraft:chest`. */
|
|
83586
|
+
static entry(index, block) {
|
|
83587
|
+
const entry = Object.prototype.hasOwnProperty.call(index, block) ? index[block] : void 0;
|
|
83588
|
+
return Array.isArray(entry?.parts) ? entry : void 0;
|
|
83589
|
+
}
|
|
83590
|
+
/** Selects the parts and placement for a block ID such as `minecraft:chest`; undefined when nothing is drawn. */
|
|
83591
|
+
static resolve(index, block, state = {}) {
|
|
83592
|
+
const entry = this.entry(index, block);
|
|
83593
|
+
if (!entry) return void 0;
|
|
83594
|
+
const value = (property) => String(state[property]).toLowerCase();
|
|
83595
|
+
const parts = entry.parts.filter((part) => Object.entries(part.when ?? {}).every(([property, values]) => String(values).split("|").includes(value(property))));
|
|
83596
|
+
if (!parts.length) return void 0;
|
|
83597
|
+
let rotation = 0;
|
|
83598
|
+
if (entry.rotation) {
|
|
83599
|
+
const selected = value(entry.rotation.property);
|
|
83600
|
+
rotation = "degrees" in entry.rotation ? entry.rotation.degrees[selected] : Number(selected) * entry.rotation.step;
|
|
83601
|
+
if (!Number.isFinite(rotation)) rotation = 0;
|
|
83602
|
+
}
|
|
83603
|
+
return { parts, rotation, translation: entry.translation ?? [0, 0, 0] };
|
|
83604
|
+
}
|
|
83605
|
+
/** Placement in block space (0..16 per axis), applied on top of the model's own transform. */
|
|
83606
|
+
static matrix(resolved, matrix = new Matrix4()) {
|
|
83607
|
+
return matrix.makeTranslation(8, 0, 8).multiply(new Matrix4().makeRotationY(resolved.rotation * Math.PI / 180)).multiply(new Matrix4().makeTranslation(resolved.translation[0] - 8, resolved.translation[1], resolved.translation[2] - 8));
|
|
83608
|
+
}
|
|
83609
|
+
};
|
|
83610
|
+
|
|
83611
|
+
// src/assets/index.ts
|
|
83481
83612
|
init_BlockStates();
|
|
83482
83613
|
|
|
83483
83614
|
// src/assets/Entities.ts
|
|
@@ -83512,32 +83643,53 @@ ${key}` : key;
|
|
|
83512
83643
|
static async getLayerList(modelKey) {
|
|
83513
83644
|
return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
|
|
83514
83645
|
}
|
|
83646
|
+
/** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */
|
|
83647
|
+
static async getPassList(modelKey) {
|
|
83648
|
+
return (await this.getModelFile(modelKey))?.passes ?? [];
|
|
83649
|
+
}
|
|
83515
83650
|
static async getEntity(modelKey, textureKey, options) {
|
|
83516
83651
|
const model = await this.getModelFile(modelKey);
|
|
83517
83652
|
if (!model) return void 0;
|
|
83518
|
-
const
|
|
83519
|
-
|
|
83520
|
-
|
|
83521
|
-
|
|
83653
|
+
const passes = options?.layers || options?.layer !== void 0 ? [] : (model.passes ?? []).filter((pass) => pass.when === void 0 || options?.when?.includes(pass.when));
|
|
83654
|
+
const draws = [...new Set(options?.layers ?? [options?.layer ?? "main"])].map((layer) => ({ layer }));
|
|
83655
|
+
if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
|
|
83656
|
+
draws.push(...passes);
|
|
83657
|
+
const names = [];
|
|
83658
|
+
const selected = draws.map((pass) => {
|
|
83659
|
+
const layer = model.layers[pass.layer];
|
|
83522
83660
|
if (!layer) {
|
|
83523
|
-
throw new MineRenderError(`Entity ${model.id} has no layer "${
|
|
83661
|
+
throw new MineRenderError(`Entity ${model.id} has no layer "${pass.layer}". Available layers: ${Object.keys(model.layers).join(", ")}`);
|
|
83524
83662
|
}
|
|
83525
|
-
|
|
83663
|
+
let name2 = pass.layer;
|
|
83664
|
+
for (let n4 = 2; names.includes(name2); n4++) name2 = `${pass.layer}#${n4}`;
|
|
83665
|
+
names.push(name2);
|
|
83666
|
+
return { name: name2, layer, pass };
|
|
83526
83667
|
});
|
|
83527
|
-
const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name: name2, layer }, index) => {
|
|
83668
|
+
const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name: name2, layer, pass }, index) => {
|
|
83528
83669
|
const override = options?.textures?.[name2] ?? (index === 0 ? textureKey : void 0);
|
|
83670
|
+
const textureLocation = pass.textureLocation ?? layer.textureLocation;
|
|
83529
83671
|
let texture;
|
|
83530
83672
|
if (override) {
|
|
83531
83673
|
const path = isAssetKey(override) ? override.getFullPath() : override.path;
|
|
83532
83674
|
texture = isAssetKey(override) && override.assetType === "textures" && path.startsWith("entity/") ? override : new AssetKey(override.namespace, path, "textures", "entity", "assets", ".png", isAssetKey(override) ? override.root : void 0);
|
|
83533
|
-
} else if (
|
|
83534
|
-
texture = AssetKey.parse("textures",
|
|
83675
|
+
} else if (textureLocation !== void 0) {
|
|
83676
|
+
texture = AssetKey.parse("textures", textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
|
|
83535
83677
|
} else {
|
|
83536
83678
|
texture = await this.resolveTexture(modelKey);
|
|
83537
83679
|
}
|
|
83538
|
-
|
|
83680
|
+
const render = pass.render ?? layer.render;
|
|
83681
|
+
return [name2, { key: override ?? modelKey, texture, layer, ...render && { render }, ...pass.tint && { tint: pass.tint } }];
|
|
83539
83682
|
})));
|
|
83540
|
-
return { ...layers[names[0]], id: model.id, layers };
|
|
83683
|
+
return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
|
|
83684
|
+
}
|
|
83685
|
+
/**
|
|
83686
|
+
* Vanilla's keyframe animations of a model by name, or undefined when the model or the selected version has none.
|
|
83687
|
+
*/
|
|
83688
|
+
static async getAnimations(modelKey) {
|
|
83689
|
+
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
83690
|
+
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json");
|
|
83691
|
+
const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
83692
|
+
return file?.animations;
|
|
83541
83693
|
}
|
|
83542
83694
|
static async resolveTexture(modelKey) {
|
|
83543
83695
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
@@ -83654,6 +83806,51 @@ ${key}` : key;
|
|
|
83654
83806
|
init_buffer2();
|
|
83655
83807
|
init_process2();
|
|
83656
83808
|
|
|
83809
|
+
// src/entity/EntityAnimation.ts
|
|
83810
|
+
init_dirname();
|
|
83811
|
+
init_buffer2();
|
|
83812
|
+
init_process2();
|
|
83813
|
+
var ENTITY_ANIMATION_CHANNELS = ["position", "rotation", "scale"];
|
|
83814
|
+
function catmullRom(delta, p0, p1, p22, p32) {
|
|
83815
|
+
return 0.5 * (2 * p1 + (p22 - p0) * delta + (2 * p0 - 5 * p1 + 4 * p22 - p32) * delta * delta + (3 * p1 - p0 - 3 * p22 + p32) * delta * delta * delta);
|
|
83816
|
+
}
|
|
83817
|
+
function sampleEntityKeyframes(keyframes, time) {
|
|
83818
|
+
if (keyframes.length === 0) return [0, 0, 0];
|
|
83819
|
+
let low = 0, high = keyframes.length;
|
|
83820
|
+
while (low < high) {
|
|
83821
|
+
const middle = low + high >>> 1;
|
|
83822
|
+
if (time <= keyframes[middle].time) high = middle;
|
|
83823
|
+
else low = middle + 1;
|
|
83824
|
+
}
|
|
83825
|
+
const a4 = Math.max(0, low - 1);
|
|
83826
|
+
const b4 = Math.min(keyframes.length - 1, a4 + 1);
|
|
83827
|
+
const from = keyframes[a4];
|
|
83828
|
+
const to = keyframes[b4];
|
|
83829
|
+
const delta = a4 === b4 ? 0 : Math.min(1, Math.max(0, (time - from.time) / (to.time - from.time)));
|
|
83830
|
+
if (to.interpolation === "catmullrom") {
|
|
83831
|
+
const before = keyframes[Math.max(0, a4 - 1)].value;
|
|
83832
|
+
const after = keyframes[Math.min(keyframes.length - 1, b4 + 1)].value;
|
|
83833
|
+
return [0, 1, 2].map((i4) => catmullRom(delta, before[i4], from.value[i4], to.value[i4], after[i4]));
|
|
83834
|
+
}
|
|
83835
|
+
const target = to.pre ?? to.value;
|
|
83836
|
+
return [0, 1, 2].map((i4) => from.value[i4] + (target[i4] - from.value[i4]) * delta);
|
|
83837
|
+
}
|
|
83838
|
+
function entityAnimationTime(animation, time, loop = animation.loop) {
|
|
83839
|
+
return loop && animation.length > 0 ? time % animation.length : time;
|
|
83840
|
+
}
|
|
83841
|
+
function sampleEntityAnimation(animation, time, loop = animation.loop) {
|
|
83842
|
+
const elapsed = entityAnimationTime(animation, time, loop);
|
|
83843
|
+
const pose = {};
|
|
83844
|
+
for (const [name2, bone] of Object.entries(animation.bones)) {
|
|
83845
|
+
const sampled = pose[name2] = {};
|
|
83846
|
+
for (const channel of ENTITY_ANIMATION_CHANNELS) {
|
|
83847
|
+
const keyframes = bone[channel];
|
|
83848
|
+
if (keyframes?.length) sampled[channel] = sampleEntityKeyframes(keyframes, elapsed);
|
|
83849
|
+
}
|
|
83850
|
+
}
|
|
83851
|
+
return pose;
|
|
83852
|
+
}
|
|
83853
|
+
|
|
83657
83854
|
// src/entity/EntityModel.ts
|
|
83658
83855
|
init_dirname();
|
|
83659
83856
|
init_buffer2();
|
|
@@ -83664,6 +83861,80 @@ ${key}` : key;
|
|
|
83664
83861
|
init_buffer2();
|
|
83665
83862
|
init_process2();
|
|
83666
83863
|
|
|
83864
|
+
// src/entity/scene/EntityAnimationPlayer.ts
|
|
83865
|
+
init_dirname();
|
|
83866
|
+
init_buffer2();
|
|
83867
|
+
init_process2();
|
|
83868
|
+
var ZERO = [0, 0, 0];
|
|
83869
|
+
var EntityAnimationPlayer = class {
|
|
83870
|
+
constructor() {
|
|
83871
|
+
this.parts = [];
|
|
83872
|
+
this._time = 0;
|
|
83873
|
+
this.loop = false;
|
|
83874
|
+
this.speed = 1;
|
|
83875
|
+
}
|
|
83876
|
+
get animation() {
|
|
83877
|
+
return this._animation;
|
|
83878
|
+
}
|
|
83879
|
+
get time() {
|
|
83880
|
+
return this._time;
|
|
83881
|
+
}
|
|
83882
|
+
/**
|
|
83883
|
+
* Starts an animation on the named parts below each layer root. The current pose of a part becomes its default;
|
|
83884
|
+
* bones without a matching part are skipped.
|
|
83885
|
+
*/
|
|
83886
|
+
play(layers, animation, options = {}) {
|
|
83887
|
+
this.stop();
|
|
83888
|
+
this._animation = animation;
|
|
83889
|
+
this._time = options.time ?? 0;
|
|
83890
|
+
this.loop = options.loop ?? animation.loop;
|
|
83891
|
+
this.speed = options.speed ?? 1;
|
|
83892
|
+
for (const layer of layers) {
|
|
83893
|
+
for (const bone of Object.keys(animation.bones)) {
|
|
83894
|
+
const object = layer.getObjectByName(`group:${bone}`);
|
|
83895
|
+
if (!object) continue;
|
|
83896
|
+
this.parts.push({ bone, object, position: object.position.clone(), rotation: object.rotation.clone(), scale: object.scale.clone() });
|
|
83897
|
+
}
|
|
83898
|
+
}
|
|
83899
|
+
this.apply();
|
|
83900
|
+
}
|
|
83901
|
+
/** Restores the default poses. Returns whether an animation was active. */
|
|
83902
|
+
stop() {
|
|
83903
|
+
if (!this._animation) return false;
|
|
83904
|
+
for (const part of this.parts) {
|
|
83905
|
+
part.object.position.copy(part.position);
|
|
83906
|
+
part.object.rotation.copy(part.rotation);
|
|
83907
|
+
part.object.scale.copy(part.scale);
|
|
83908
|
+
}
|
|
83909
|
+
this.clear();
|
|
83910
|
+
return true;
|
|
83911
|
+
}
|
|
83912
|
+
/** Forgets the animation without touching the parts, for parts that no longer exist. */
|
|
83913
|
+
clear() {
|
|
83914
|
+
this.parts = [];
|
|
83915
|
+
this._animation = void 0;
|
|
83916
|
+
this._time = 0;
|
|
83917
|
+
}
|
|
83918
|
+
setTime(seconds) {
|
|
83919
|
+
if (!this._animation) return false;
|
|
83920
|
+
this._time = seconds;
|
|
83921
|
+
this.apply();
|
|
83922
|
+
return true;
|
|
83923
|
+
}
|
|
83924
|
+
advance(deltaSeconds) {
|
|
83925
|
+
return this.setTime(this._time + deltaSeconds * this.speed);
|
|
83926
|
+
}
|
|
83927
|
+
apply() {
|
|
83928
|
+
const pose = sampleEntityAnimation(this._animation, this._time, this.loop);
|
|
83929
|
+
for (const part of this.parts) {
|
|
83930
|
+
const { position = ZERO, rotation = ZERO, scale = ZERO } = pose[part.bone];
|
|
83931
|
+
part.object.position.set(part.position.x + position[0], part.position.y + position[1], part.position.z + position[2]);
|
|
83932
|
+
part.object.rotation.set(part.rotation.x + rotation[0], part.rotation.y + rotation[1], part.rotation.z + rotation[2], part.rotation.order);
|
|
83933
|
+
part.object.scale.set(part.scale.x + scale[0], part.scale.y + scale[1], part.scale.z + scale[2]);
|
|
83934
|
+
}
|
|
83935
|
+
}
|
|
83936
|
+
};
|
|
83937
|
+
|
|
83667
83938
|
// src/entity/scene/EntityObject.ts
|
|
83668
83939
|
init_dirname();
|
|
83669
83940
|
init_buffer2();
|
|
@@ -83672,6 +83943,7 @@ ${key}` : key;
|
|
|
83672
83943
|
init_Caching();
|
|
83673
83944
|
var import_ts_deepmerge4 = __toESM(require_dist());
|
|
83674
83945
|
init_three_module();
|
|
83946
|
+
init_Ticker();
|
|
83675
83947
|
init_model();
|
|
83676
83948
|
init_ModelTextures();
|
|
83677
83949
|
init_AssetKey();
|
|
@@ -83683,6 +83955,11 @@ ${key}` : key;
|
|
|
83683
83955
|
this.entity = entity;
|
|
83684
83956
|
this.isEntityObject = true;
|
|
83685
83957
|
this.meshesCreated = false;
|
|
83958
|
+
/** Scrolling materials are owned: their texture offset follows this entity's age. */
|
|
83959
|
+
this.scrollMaterials = [];
|
|
83960
|
+
/** Entity age in ticks, as vanilla's `ageInTicks`; drives the scrolling render modes. */
|
|
83961
|
+
this.age = 0;
|
|
83962
|
+
this.animationPlayer = new EntityAnimationPlayer();
|
|
83686
83963
|
this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
|
|
83687
83964
|
}
|
|
83688
83965
|
async init() {
|
|
@@ -83692,6 +83969,59 @@ ${key}` : key;
|
|
|
83692
83969
|
dispose() {
|
|
83693
83970
|
super.dispose();
|
|
83694
83971
|
}
|
|
83972
|
+
disposeAndRemoveAllChildren() {
|
|
83973
|
+
this.clearScrollMaterials();
|
|
83974
|
+
this.animationPlayer.clear();
|
|
83975
|
+
super.disposeAndRemoveAllChildren();
|
|
83976
|
+
}
|
|
83977
|
+
clearScrollMaterials() {
|
|
83978
|
+
Ticker.remove(this.scrollTicker);
|
|
83979
|
+
this.scrollTicker = void 0;
|
|
83980
|
+
for (const { material } of this.scrollMaterials.splice(0)) {
|
|
83981
|
+
material.map?.dispose();
|
|
83982
|
+
material.dispose();
|
|
83983
|
+
}
|
|
83984
|
+
}
|
|
83985
|
+
/** Applies the entity age to the scrolling materials; the ticker calls this 20 times per second. */
|
|
83986
|
+
updateScroll() {
|
|
83987
|
+
for (const { offset, speed } of this.scrollMaterials) {
|
|
83988
|
+
offset.set(this.age * speed[0] % 1, 0 - this.age * speed[1] % 1);
|
|
83989
|
+
}
|
|
83990
|
+
this.notifyDirty();
|
|
83991
|
+
}
|
|
83992
|
+
//<editor-fold desc="ANIMATION">
|
|
83993
|
+
/** The animation started by {@link playAnimation}, until {@link stopAnimation} or disposal. */
|
|
83994
|
+
get animation() {
|
|
83995
|
+
return this.animationPlayer.animation;
|
|
83996
|
+
}
|
|
83997
|
+
/** Seconds since the animation started, before looping. */
|
|
83998
|
+
get animationTime() {
|
|
83999
|
+
return this.animationPlayer.time;
|
|
84000
|
+
}
|
|
84001
|
+
/**
|
|
84002
|
+
* Poses the object from a keyframe animation of {@link Entities.getAnimations}, replacing the current one.
|
|
84003
|
+
* Parts of every layer are matched by name and their current pose is the default the offsets add to.
|
|
84004
|
+
* The object owns no clock: call {@link advanceAnimation} per frame, or {@link setAnimationTime}.
|
|
84005
|
+
*/
|
|
84006
|
+
playAnimation(animation, options) {
|
|
84007
|
+
this.createMeshes();
|
|
84008
|
+
const layers = Object.keys(this.entityLayers).map((name2) => this.getLayerGroup(name2)).filter((layer) => !!layer);
|
|
84009
|
+
this.animationPlayer.play(layers, animation, options);
|
|
84010
|
+
this.notifyDirty();
|
|
84011
|
+
}
|
|
84012
|
+
/** Stops the animation and restores the default pose. */
|
|
84013
|
+
stopAnimation() {
|
|
84014
|
+
if (this.animationPlayer.stop()) this.notifyDirty();
|
|
84015
|
+
}
|
|
84016
|
+
/** Poses the object at an explicit time in seconds. Has no effect without an animation. */
|
|
84017
|
+
setAnimationTime(seconds) {
|
|
84018
|
+
if (this.animationPlayer.setTime(seconds)) this.notifyDirty();
|
|
84019
|
+
}
|
|
84020
|
+
/** Advances the animation by a frame delta in seconds, scaled by its speed. Has no effect without an animation. */
|
|
84021
|
+
advanceAnimation(deltaSeconds) {
|
|
84022
|
+
if (this.animationPlayer.advance(deltaSeconds)) this.notifyDirty();
|
|
84023
|
+
}
|
|
84024
|
+
//</editor-fold>
|
|
83695
84025
|
getLayerGroup(name2) {
|
|
83696
84026
|
return super.getGroupByName(`layer:${name2}`);
|
|
83697
84027
|
}
|
|
@@ -83722,16 +84052,29 @@ ${key}` : key;
|
|
|
83722
84052
|
createMeshes(force = false) {
|
|
83723
84053
|
if (this.meshesCreated && !force) return;
|
|
83724
84054
|
const modelRoot = new Object3D();
|
|
83725
|
-
|
|
84055
|
+
const transform = this.options.flip === void 0 ? this.entity.transform : void 0;
|
|
84056
|
+
if (transform) {
|
|
84057
|
+
for (const op of transform) {
|
|
84058
|
+
const matrix = new Matrix4();
|
|
84059
|
+
if ("scale" in op) matrix.makeScale(...op.scale);
|
|
84060
|
+
else if ("translate" in op) matrix.makeTranslation(...op.translate);
|
|
84061
|
+
else matrix.makeRotationFromEuler(new Euler(...op.rotate, "ZYX"));
|
|
84062
|
+
modelRoot.matrix.multiply(matrix);
|
|
84063
|
+
}
|
|
84064
|
+
modelRoot.matrixAutoUpdate = false;
|
|
84065
|
+
} else if (this.options.flip ?? true) {
|
|
84066
|
+
modelRoot.scale.set(-1, -1, 1);
|
|
84067
|
+
}
|
|
83726
84068
|
this.add(modelRoot);
|
|
83727
84069
|
Object.entries(this.entityLayers).forEach(([name2, layer], index) => {
|
|
83728
84070
|
const group = this.createGroup(`layer:${name2}`);
|
|
83729
84071
|
modelRoot.add(group);
|
|
83730
|
-
|
|
84072
|
+
const inward = !Materials.entityModeCulls(layer.render ?? layer.layer.render);
|
|
84073
|
+
this.createPart("root", layer.layer.root, group, layer.layer.texture, Materials.MISSING_TEXTURE, index, inward);
|
|
83731
84074
|
});
|
|
83732
84075
|
this.meshesCreated = true;
|
|
83733
84076
|
}
|
|
83734
|
-
createPart(name2, part, parent, textureSize, material, renderOrder) {
|
|
84077
|
+
createPart(name2, part, parent, textureSize, material, renderOrder, inward = true) {
|
|
83735
84078
|
const anchor = this.createGroup(name2);
|
|
83736
84079
|
anchor.position.fromArray(part.pose.offset);
|
|
83737
84080
|
anchor.rotation.set(...part.pose.rotation, "ZYX");
|
|
@@ -83750,7 +84093,7 @@ ${key}` : key;
|
|
|
83750
84093
|
uv
|
|
83751
84094
|
).clone();
|
|
83752
84095
|
geometry.translate(cube.origin[0] + width / 2, cube.origin[1] + height / 2, cube.origin[2] + depth / 2);
|
|
83753
|
-
if (Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
|
|
84096
|
+
if (inward && Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
|
|
83754
84097
|
const index = Array.from(geometry.getIndex().array);
|
|
83755
84098
|
geometry.setIndex(index.concat(index.slice().reverse()));
|
|
83756
84099
|
}
|
|
@@ -83760,30 +84103,46 @@ ${key}` : key;
|
|
|
83760
84103
|
if (this.options.wireframe) addWireframeToMesh(geometry, mesh);
|
|
83761
84104
|
}
|
|
83762
84105
|
for (const [childName, child] of Object.entries(part.children)) {
|
|
83763
|
-
this.createPart(childName, child, anchor, size, material, renderOrder);
|
|
84106
|
+
this.createPart(childName, child, anchor, size, material, renderOrder, inward);
|
|
83764
84107
|
}
|
|
83765
84108
|
}
|
|
83766
84109
|
async applyTextures() {
|
|
84110
|
+
this.clearScrollMaterials();
|
|
83767
84111
|
await Promise.all(Object.entries(this.entityLayers).map(async ([name2, layer]) => {
|
|
84112
|
+
const mode2 = layer.render ?? layer.layer.render ?? "cutout";
|
|
84113
|
+
const tint = layer.tint === void 0 ? void 0 : this.options.tints?.[layer.tint];
|
|
84114
|
+
const scroll = Materials.entityModeScroll(mode2);
|
|
83768
84115
|
const assetKeyStr = this.getTextureKey(layer).serialize();
|
|
83769
|
-
const keyStr = `entity:${assetKeyStr}`;
|
|
83770
|
-
let mat = Caching.materialCache.getIfPresent(keyStr);
|
|
84116
|
+
const keyStr = `entity:${mode2}:${tint === void 0 ? "" : new Color(tint).getHexString()}:${assetKeyStr}`;
|
|
84117
|
+
let mat = scroll ? void 0 : Caching.materialCache.getIfPresent(keyStr);
|
|
83771
84118
|
if (!mat) {
|
|
83772
84119
|
const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
|
|
83773
84120
|
const imageData = await this.loadTextures(layer);
|
|
83774
84121
|
if (!imageData) return;
|
|
83775
84122
|
const canvas = imageData.data.canvas;
|
|
83776
|
-
const createMaterial = () => Materials.
|
|
83777
|
-
mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
|
|
84123
|
+
const createMaterial = () => Materials.createEntityCanvasMaterial(canvas, mode2, tint);
|
|
84124
|
+
mat = !scroll && cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
|
|
84125
|
+
if (scroll) {
|
|
84126
|
+
this.scrollMaterials.push({ material: mat, offset: mat.map.offset, speed: scroll });
|
|
84127
|
+
}
|
|
83778
84128
|
}
|
|
83779
84129
|
this.getLayerGroup(name2)?.traverse((object) => {
|
|
83780
84130
|
if (isMesh(object)) object.material = mat;
|
|
83781
84131
|
});
|
|
83782
84132
|
}));
|
|
84133
|
+
if (!this.children.length) {
|
|
84134
|
+
this.clearScrollMaterials();
|
|
84135
|
+
} else if (this.scrollMaterials.length) {
|
|
84136
|
+
this.updateScroll();
|
|
84137
|
+
this.scrollTicker = Ticker.add(() => {
|
|
84138
|
+
this.age++;
|
|
84139
|
+
this.updateScroll();
|
|
84140
|
+
});
|
|
84141
|
+
}
|
|
83783
84142
|
this.notifyDirty();
|
|
83784
84143
|
}
|
|
83785
84144
|
};
|
|
83786
|
-
_EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS
|
|
84145
|
+
_EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS);
|
|
83787
84146
|
var EntityObject = _EntityObject;
|
|
83788
84147
|
function isEntityObject(obj) {
|
|
83789
84148
|
return obj.isEntityObject;
|
|
@@ -86328,11 +86687,69 @@ property list uchar int vertex_index
|
|
|
86328
86687
|
init_dirname();
|
|
86329
86688
|
init_buffer2();
|
|
86330
86689
|
init_process2();
|
|
86690
|
+
init_AssetKey();
|
|
86331
86691
|
var GuiHelper = class {
|
|
86332
86692
|
static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
|
|
86333
86693
|
const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
|
|
86334
86694
|
return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
|
|
86335
86695
|
}
|
|
86696
|
+
/** Creates crafting-table layers for ingredients and the result; stack counts are not drawn. */
|
|
86697
|
+
static recipe(recipe, options = {}) {
|
|
86698
|
+
const layers = [
|
|
86699
|
+
{ name: "background", texture: "minecraft:gui/container/crafting_table", crop: [0, 0, 176, 166] }
|
|
86700
|
+
];
|
|
86701
|
+
const itemKey = (ingredient) => {
|
|
86702
|
+
const item = typeof ingredient === "string" && !ingredient.startsWith("#") ? ingredient : typeof ingredient === "object" && "item" in ingredient ? ingredient.item : options.resolveIngredient?.(ingredient);
|
|
86703
|
+
if (isAssetKey(item)) return item;
|
|
86704
|
+
if (!item || item.startsWith("#")) {
|
|
86705
|
+
throw new Error(`Select a concrete item for recipe ingredient ${JSON.stringify(ingredient)}`);
|
|
86706
|
+
}
|
|
86707
|
+
const key = AssetKey.parse("models", item);
|
|
86708
|
+
return new AssetKey(key.namespace, key.getFullPath(), "models", "item");
|
|
86709
|
+
};
|
|
86710
|
+
const addIngredient = (ingredient, slot) => {
|
|
86711
|
+
layers.push({
|
|
86712
|
+
name: `ingredient-${slot}`,
|
|
86713
|
+
item: itemKey(ingredient),
|
|
86714
|
+
position: this.inventorySlot(slot, [30, 17], [18, 18], 3)
|
|
86715
|
+
});
|
|
86716
|
+
};
|
|
86717
|
+
switch (recipe.type) {
|
|
86718
|
+
case "minecraft:crafting_shaped":
|
|
86719
|
+
case "crafting_shaped": {
|
|
86720
|
+
const pattern = recipe.pattern;
|
|
86721
|
+
if (!pattern.length || pattern.length > 3 || !pattern[0].length || pattern[0].length > 3 || pattern.some((row) => row.length !== pattern[0].length)) {
|
|
86722
|
+
throw new Error("Crafting patterns must be rectangular, with 1\u20133 rows and columns");
|
|
86723
|
+
}
|
|
86724
|
+
const cells = pattern.flatMap((row, y5) => row.split("").map((symbol, x4) => ({ symbol, x: x4, y: y5 }))).filter((cell) => cell.symbol !== " ");
|
|
86725
|
+
if (!cells.length) throw new Error("Crafting patterns must contain an ingredient");
|
|
86726
|
+
const minX = Math.min(...cells.map((cell) => cell.x)), maxX = Math.max(...cells.map((cell) => cell.x));
|
|
86727
|
+
const minY = Math.min(...cells.map((cell) => cell.y)), maxY = Math.max(...cells.map((cell) => cell.y));
|
|
86728
|
+
const offsetX = minX === maxX ? 1 : 0, offsetY = minY === maxY ? 1 : 0;
|
|
86729
|
+
for (const { symbol, x: x4, y: y5 } of cells) {
|
|
86730
|
+
const ingredient = recipe.key[symbol];
|
|
86731
|
+
if (!ingredient) throw new Error(`Missing recipe ingredient for symbol ${JSON.stringify(symbol)}`);
|
|
86732
|
+
addIngredient(ingredient, (y5 - minY + offsetY) * 3 + x4 - minX + offsetX);
|
|
86733
|
+
}
|
|
86734
|
+
break;
|
|
86735
|
+
}
|
|
86736
|
+
case "minecraft:crafting_shapeless":
|
|
86737
|
+
case "crafting_shapeless":
|
|
86738
|
+
if (!recipe.ingredients.length || recipe.ingredients.length > 9) {
|
|
86739
|
+
throw new Error("Shapeless crafting recipes require 1\u20139 ingredients");
|
|
86740
|
+
}
|
|
86741
|
+
recipe.ingredients.forEach(addIngredient);
|
|
86742
|
+
break;
|
|
86743
|
+
default:
|
|
86744
|
+
throw new Error(`Unsupported crafting recipe type: ${recipe.type}`);
|
|
86745
|
+
}
|
|
86746
|
+
layers.push({
|
|
86747
|
+
name: "result",
|
|
86748
|
+
item: itemKey("id" in recipe.result ? recipe.result.id : recipe.result.item),
|
|
86749
|
+
position: [124, 35]
|
|
86750
|
+
});
|
|
86751
|
+
return layers;
|
|
86752
|
+
}
|
|
86336
86753
|
};
|
|
86337
86754
|
|
|
86338
86755
|
// src/gui/GuiLayer.ts
|
|
@@ -87212,6 +87629,9 @@ property list uchar int vertex_index
|
|
|
87212
87629
|
this._variants = [];
|
|
87213
87630
|
this._models = [];
|
|
87214
87631
|
this._cullMask = 0;
|
|
87632
|
+
this._entities = [];
|
|
87633
|
+
this._entityPlacement = new Matrix4();
|
|
87634
|
+
this._entityGeneration = 0;
|
|
87215
87635
|
this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
|
|
87216
87636
|
}
|
|
87217
87637
|
async init() {
|
|
@@ -87231,6 +87651,8 @@ property list uchar int vertex_index
|
|
|
87231
87651
|
}
|
|
87232
87652
|
clearModels() {
|
|
87233
87653
|
this.removeModels(this._models.splice(0));
|
|
87654
|
+
this._entityGeneration++;
|
|
87655
|
+
this.removeEntities(this._entities.splice(0));
|
|
87234
87656
|
this._fluidKey = void 0;
|
|
87235
87657
|
this._fluidModel = void 0;
|
|
87236
87658
|
this._isInstanced = false;
|
|
@@ -87242,6 +87664,57 @@ property list uchar int vertex_index
|
|
|
87242
87664
|
if (!isInstanceReference(model)) model.dispose();
|
|
87243
87665
|
}
|
|
87244
87666
|
}
|
|
87667
|
+
removeEntities(entities) {
|
|
87668
|
+
for (const entity of entities) {
|
|
87669
|
+
entity.removeFromScene();
|
|
87670
|
+
entity.dispose();
|
|
87671
|
+
}
|
|
87672
|
+
}
|
|
87673
|
+
/** Entity models drawn for this block instead of its block model; they are scene children, unlike the block. */
|
|
87674
|
+
get blockEntities() {
|
|
87675
|
+
return this._entities;
|
|
87676
|
+
}
|
|
87677
|
+
/**
|
|
87678
|
+
* Draws the block through the dataset's block-entity index. Returns false, leaving nothing behind,
|
|
87679
|
+
* when the block is not listed or one of its models cannot be loaded.
|
|
87680
|
+
*/
|
|
87681
|
+
async createBlockEntities() {
|
|
87682
|
+
const key = this.blockState.key;
|
|
87683
|
+
if (!key || this.options.displayPosition) return false;
|
|
87684
|
+
const generation = this._entityGeneration;
|
|
87685
|
+
const created = [];
|
|
87686
|
+
let resolved;
|
|
87687
|
+
try {
|
|
87688
|
+
resolved = BlockEntities.resolve(await BlockEntities.getIndex(key.root), key.toNamespacedString(), this.state);
|
|
87689
|
+
if (!resolved) return false;
|
|
87690
|
+
for (const part of resolved.parts) {
|
|
87691
|
+
const [namespace, path] = part.model.includes(":") ? part.model.split(":") : [key.namespace, part.model];
|
|
87692
|
+
const texture = part.textureLocation === void 0 ? void 0 : AssetKey.parse("textures", part.textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
|
|
87693
|
+
if (texture) texture.root = key.root;
|
|
87694
|
+
const entity = await Entities.getEntity(new BasicAssetKey(namespace, path), texture, { layer: part.layer });
|
|
87695
|
+
if (!entity) throw new MineRenderError(`Missing entity model ${part.model}`);
|
|
87696
|
+
created.push(await this.scene.addEntity(entity, { wireframe: this.options.wireframe }));
|
|
87697
|
+
}
|
|
87698
|
+
} catch (error) {
|
|
87699
|
+
console.warn(`Could not draw block entity ${key.toNamespacedString()}, using its block model`, error);
|
|
87700
|
+
this.removeEntities(created);
|
|
87701
|
+
return false;
|
|
87702
|
+
}
|
|
87703
|
+
if (generation !== this._entityGeneration) {
|
|
87704
|
+
this.removeEntities(created);
|
|
87705
|
+
return true;
|
|
87706
|
+
}
|
|
87707
|
+
BlockEntities.matrix(resolved, this._entityPlacement);
|
|
87708
|
+
this._entities = created;
|
|
87709
|
+
this.placeEntities();
|
|
87710
|
+
return true;
|
|
87711
|
+
}
|
|
87712
|
+
placeEntities() {
|
|
87713
|
+
const matrix = new Matrix4().makeTranslation(this.position.x - 8, this.position.y - 8, this.position.z - 8).multiply(this._entityPlacement);
|
|
87714
|
+
for (const entity of this._entities) {
|
|
87715
|
+
matrix.decompose(entity.position, entity.quaternion, entity.scale);
|
|
87716
|
+
}
|
|
87717
|
+
}
|
|
87245
87718
|
get isOccluding() {
|
|
87246
87719
|
return this._models.some((model) => {
|
|
87247
87720
|
const object = isInstanceReference(model) ? model.instanceable : model;
|
|
@@ -87353,13 +87826,20 @@ property list uchar int vertex_index
|
|
|
87353
87826
|
await this.updateFluid(this._fluidSampler);
|
|
87354
87827
|
return;
|
|
87355
87828
|
}
|
|
87829
|
+
const hasEntities = await this.createBlockEntities();
|
|
87356
87830
|
const variantsToCreate = await this.mapStateToVariant(this.state);
|
|
87357
87831
|
this._variants = variantsToCreate;
|
|
87358
87832
|
for (let blockStateVariant of variantsToCreate) {
|
|
87833
|
+
if (hasEntities && !await this.hasGeometry(blockStateVariant)) continue;
|
|
87359
87834
|
this._models.push(await this.createVariant(blockStateVariant));
|
|
87360
87835
|
}
|
|
87361
87836
|
await this.updateFluid(this._fluidSampler);
|
|
87362
87837
|
}
|
|
87838
|
+
async hasGeometry(variant) {
|
|
87839
|
+
const modelKey = AssetKey.parse("models", variant.model);
|
|
87840
|
+
modelKey.root = this.blockState.key?.root;
|
|
87841
|
+
return !!(await Models.getMerged(modelKey))?.elements?.length;
|
|
87842
|
+
}
|
|
87363
87843
|
getSingleVariant(variants) {
|
|
87364
87844
|
return BlockStateResolver.choose(variants);
|
|
87365
87845
|
}
|
|
@@ -87479,6 +87959,7 @@ property list uchar int vertex_index
|
|
|
87479
87959
|
for (let model of this._models) {
|
|
87480
87960
|
model.setPosition(position);
|
|
87481
87961
|
}
|
|
87962
|
+
this.placeEntities();
|
|
87482
87963
|
this.notifyDirty();
|
|
87483
87964
|
}
|
|
87484
87965
|
//TODO: should override rotation + scale methods
|
|
@@ -94365,7 +94846,8 @@ uniform float opacity;varying vec2 vUv;void main(){vec4 texel=texture2D(inputBuf
|
|
|
94365
94846
|
this.data.set(index, void 0);
|
|
94366
94847
|
return void 0;
|
|
94367
94848
|
}
|
|
94368
|
-
const
|
|
94849
|
+
const perBlock = !this.sectionModels || getFluidKind(blockState.key, stored.properties) || blockState.key && BlockEntities.entry(await BlockEntities.getIndex(blockState.key.root), blockState.key.toNamespacedString());
|
|
94850
|
+
const template = perBlock ? void 0 : await this.sectionModels.get(blockState, stored.properties);
|
|
94369
94851
|
if (template) {
|
|
94370
94852
|
this.sectionBlocks.set(index, { index, template, cullMask: 0 });
|
|
94371
94853
|
this.meshDirty = true;
|