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/node/index.mjs
CHANGED
|
@@ -290,6 +290,12 @@ var init_Caching = __esm({
|
|
|
290
290
|
static {
|
|
291
291
|
this.entityTextureCache = _Caching.createAssetCache();
|
|
292
292
|
}
|
|
293
|
+
static {
|
|
294
|
+
this.entityAnimationCache = _Caching.createAssetCache();
|
|
295
|
+
}
|
|
296
|
+
static {
|
|
297
|
+
this.blockEntityIndexCache = _Caching.createAssetCache();
|
|
298
|
+
}
|
|
293
299
|
static createAssetCache() {
|
|
294
300
|
return Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
|
|
295
301
|
}
|
|
@@ -314,7 +320,9 @@ var init_Caching = __esm({
|
|
|
314
320
|
this.defaultBlockStatesCache,
|
|
315
321
|
this.blockTintCache,
|
|
316
322
|
this.entityModelCache,
|
|
317
|
-
this.entityTextureCache
|
|
323
|
+
this.entityTextureCache,
|
|
324
|
+
this.entityAnimationCache,
|
|
325
|
+
this.blockEntityIndexCache
|
|
318
326
|
];
|
|
319
327
|
}
|
|
320
328
|
static clear() {
|
|
@@ -843,7 +851,7 @@ var init_Textures = __esm({
|
|
|
843
851
|
});
|
|
844
852
|
|
|
845
853
|
// src/Materials.ts
|
|
846
|
-
import { Color, DoubleSide, FrontSide, MeshBasicMaterial, MeshStandardMaterial, ShaderChunk, ShaderMaterial } from "three";
|
|
854
|
+
import { Color, CustomBlending, DoubleSide, OneFactor, RepeatWrapping, FrontSide, MeshBasicMaterial, MeshStandardMaterial, ShaderChunk, ShaderMaterial, ZeroFactor } from "three";
|
|
847
855
|
var Materials;
|
|
848
856
|
var init_Materials = __esm({
|
|
849
857
|
"src/Materials.ts"() {
|
|
@@ -885,6 +893,71 @@ var init_Materials = __esm({
|
|
|
885
893
|
alphaTest: 0.5
|
|
886
894
|
});
|
|
887
895
|
}
|
|
896
|
+
/** Whether vanilla's render type for the mode culls back faces. */
|
|
897
|
+
static entityModeCulls(mode = "cutout") {
|
|
898
|
+
return mode === "cutout_cull" || mode === "solid" || mode === "eyes" || mode === "water_mask";
|
|
899
|
+
}
|
|
900
|
+
/** UV offset per tick of entity age for the scrolling modes, as vanilla's texture matrix applies it. */
|
|
901
|
+
static entityModeScroll(mode = "cutout") {
|
|
902
|
+
if (mode === "energy_swirl") return [0.01, 0.01];
|
|
903
|
+
if (mode === "breeze_wind") return [0.02, 0];
|
|
904
|
+
return void 0;
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Entity material for one of vanilla's render types. Entities are unlit here, so the lit and full-bright modes
|
|
908
|
+
* differ only in blending and depth state. Culling is not a material property: {@link entityModeCulls} decides
|
|
909
|
+
* whether the geometry gets inward faces.
|
|
910
|
+
*/
|
|
911
|
+
static createEntityCanvasMaterial(canvas, mode = "cutout", tint) {
|
|
912
|
+
const material = _Materials.createBasicCanvasMaterial(canvas);
|
|
913
|
+
switch (mode) {
|
|
914
|
+
case "cutout":
|
|
915
|
+
case "cutout_cull":
|
|
916
|
+
break;
|
|
917
|
+
case "cutout_z_offset":
|
|
918
|
+
material.polygonOffset = true;
|
|
919
|
+
material.polygonOffsetFactor = -1;
|
|
920
|
+
material.polygonOffsetUnits = -10;
|
|
921
|
+
break;
|
|
922
|
+
case "solid":
|
|
923
|
+
material.alphaTest = 0;
|
|
924
|
+
break;
|
|
925
|
+
case "translucent":
|
|
926
|
+
case "breeze_wind":
|
|
927
|
+
material.transparent = true;
|
|
928
|
+
material.alphaTest = 0.1;
|
|
929
|
+
break;
|
|
930
|
+
case "translucent_emissive":
|
|
931
|
+
material.transparent = true;
|
|
932
|
+
material.alphaTest = 0.1;
|
|
933
|
+
material.depthWrite = false;
|
|
934
|
+
break;
|
|
935
|
+
case "eyes":
|
|
936
|
+
material.transparent = true;
|
|
937
|
+
material.alphaTest = 0;
|
|
938
|
+
material.depthWrite = false;
|
|
939
|
+
break;
|
|
940
|
+
case "energy_swirl":
|
|
941
|
+
material.transparent = true;
|
|
942
|
+
material.alphaTest = 0.1;
|
|
943
|
+
material.blending = CustomBlending;
|
|
944
|
+
material.blendSrc = OneFactor;
|
|
945
|
+
material.blendDst = OneFactor;
|
|
946
|
+
material.blendSrcAlpha = ZeroFactor;
|
|
947
|
+
material.blendDstAlpha = OneFactor;
|
|
948
|
+
material.color.set(8421504);
|
|
949
|
+
break;
|
|
950
|
+
case "water_mask":
|
|
951
|
+
material.alphaTest = 0;
|
|
952
|
+
material.colorWrite = false;
|
|
953
|
+
break;
|
|
954
|
+
}
|
|
955
|
+
if (_Materials.entityModeScroll(mode)) {
|
|
956
|
+
material.map.wrapS = material.map.wrapT = RepeatWrapping;
|
|
957
|
+
}
|
|
958
|
+
if (tint !== void 0) material.color.multiply(new Color(tint));
|
|
959
|
+
return material;
|
|
960
|
+
}
|
|
888
961
|
static createGuiCanvasMaterial(canvas) {
|
|
889
962
|
const material = new MeshBasicMaterial({
|
|
890
963
|
map: Textures.createCanvasTexture(canvas),
|
|
@@ -3096,7 +3169,7 @@ var init_InstanceReference = __esm({
|
|
|
3096
3169
|
});
|
|
3097
3170
|
|
|
3098
3171
|
// src/renderer/SceneObject.ts
|
|
3099
|
-
import { Color as Color2, Euler as Euler3, InstancedBufferAttribute, InstancedMesh, MathUtils, Matrix4 as
|
|
3172
|
+
import { Color as Color2, Euler as Euler3, InstancedBufferAttribute, InstancedMesh, MathUtils, Matrix4 as Matrix44, Mesh as Mesh3, Object3D as Object3D2, Quaternion as Quaternion3, Vector3 as Vector35 } from "three";
|
|
3100
3173
|
function isSceneObject(obj) {
|
|
3101
3174
|
return obj.isSceneObject;
|
|
3102
3175
|
}
|
|
@@ -3312,7 +3385,7 @@ var init_SceneObject = __esm({
|
|
|
3312
3385
|
mesh.instanceColor.needsUpdate = true;
|
|
3313
3386
|
}
|
|
3314
3387
|
if (this._scene) this._scene.stats.instanceCount++;
|
|
3315
|
-
this.setMatrixAt(index, new
|
|
3388
|
+
this.setMatrixAt(index, new Matrix44());
|
|
3316
3389
|
return reference;
|
|
3317
3390
|
}
|
|
3318
3391
|
/** Returns the live reference for a raycast hit on this object's instance mesh. */
|
|
@@ -3325,7 +3398,7 @@ var init_SceneObject = __esm({
|
|
|
3325
3398
|
removeInstanceAt(index) {
|
|
3326
3399
|
if (!this.instanceReferences.has(index)) return;
|
|
3327
3400
|
const mesh = this.instanceMesh;
|
|
3328
|
-
this.setMatrixAt(index, new
|
|
3401
|
+
this.setMatrixAt(index, new Matrix44().makeScale(0, 0, 0));
|
|
3329
3402
|
this.instanceReferences.delete(index);
|
|
3330
3403
|
this.freeInstanceIndices.push(index);
|
|
3331
3404
|
this._instanceCounter = this.instanceReferences.size;
|
|
@@ -3355,7 +3428,7 @@ var init_SceneObject = __esm({
|
|
|
3355
3428
|
}
|
|
3356
3429
|
//</editor-fold>
|
|
3357
3430
|
//<editor-fold desc="TRANSFORMATION">
|
|
3358
|
-
getMatrixAt(index, matrix = new
|
|
3431
|
+
getMatrixAt(index, matrix = new Matrix44()) {
|
|
3359
3432
|
if (!this.instanceReferences.has(index)) throw new MineRenderError("Instance is not active");
|
|
3360
3433
|
this.instanceMesh.getMatrixAt(index, matrix);
|
|
3361
3434
|
return matrix;
|
|
@@ -3374,7 +3447,7 @@ var init_SceneObject = __esm({
|
|
|
3374
3447
|
const oldPosition = new Vector35();
|
|
3375
3448
|
const oldRotation = new Quaternion3();
|
|
3376
3449
|
const oldScale = new Vector35();
|
|
3377
|
-
const matrix = new
|
|
3450
|
+
const matrix = new Matrix44();
|
|
3378
3451
|
if (!scale || !rotation || !position) {
|
|
3379
3452
|
this.getMatrixAt(index, matrix).decompose(oldPosition, oldRotation, oldScale);
|
|
3380
3453
|
}
|
|
@@ -4122,7 +4195,7 @@ var init_ModelCulling = __esm({
|
|
|
4122
4195
|
});
|
|
4123
4196
|
|
|
4124
4197
|
// src/model/scene/ModelObject.ts
|
|
4125
|
-
import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as
|
|
4198
|
+
import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color8, Euler as Euler6, Matrix4 as Matrix48 } from "three";
|
|
4126
4199
|
function isModelObject(obj) {
|
|
4127
4200
|
return obj.isModelObject;
|
|
4128
4201
|
}
|
|
@@ -4188,7 +4261,7 @@ var init_ModelObject = __esm({
|
|
|
4188
4261
|
elGeo.clearGroups();
|
|
4189
4262
|
}
|
|
4190
4263
|
if (this.options.uvLockRotation) {
|
|
4191
|
-
UVMapper.lockUvs(elGeo, el.faces, this.atlas, new
|
|
4264
|
+
UVMapper.lockUvs(elGeo, el.faces, this.atlas, new Euler6(...this.options.uvLockRotation));
|
|
4192
4265
|
}
|
|
4193
4266
|
if (this.options.tints) {
|
|
4194
4267
|
const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
|
|
@@ -4197,19 +4270,19 @@ var init_ModelObject = __esm({
|
|
|
4197
4270
|
if (tintIndex === void 0 || tintIndex < 0) continue;
|
|
4198
4271
|
const tint = this.options.tints[tintIndex];
|
|
4199
4272
|
if (tint === void 0) continue;
|
|
4200
|
-
const color = new
|
|
4273
|
+
const color = new Color8(tint);
|
|
4201
4274
|
for (let vertex = 0; vertex < 4; vertex++) {
|
|
4202
4275
|
color.toArray(colors, (faceIndex * 4 + vertex) * 3);
|
|
4203
4276
|
}
|
|
4204
4277
|
}
|
|
4205
4278
|
elGeo.setAttribute("color", new BufferAttribute5(colors, 3));
|
|
4206
4279
|
}
|
|
4207
|
-
elGeo.applyMatrix4(new
|
|
4208
|
-
elGeo.applyMatrix4(new
|
|
4280
|
+
elGeo.applyMatrix4(new Matrix48().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
|
|
4281
|
+
elGeo.applyMatrix4(new Matrix48().makeTranslation(el.from[0], el.from[1], el.from[2]));
|
|
4209
4282
|
if (el.rotation) {
|
|
4210
4283
|
applyElementRotation(el.rotation, elGeo);
|
|
4211
4284
|
}
|
|
4212
|
-
elGeo.applyMatrix4(new
|
|
4285
|
+
elGeo.applyMatrix4(new Matrix48().makeTranslation(-8, -8, -8));
|
|
4213
4286
|
if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
|
|
4214
4287
|
if (this.options.mergeMeshes) {
|
|
4215
4288
|
allGeos.push(elGeo);
|
|
@@ -4461,7 +4534,7 @@ __export(FluidModelObject_exports, {
|
|
|
4461
4534
|
FluidModelObject: () => FluidModelObject,
|
|
4462
4535
|
sampleFluid: () => sampleFluid
|
|
4463
4536
|
});
|
|
4464
|
-
import { BufferAttribute as BufferAttribute6, Color as
|
|
4537
|
+
import { BufferAttribute as BufferAttribute6, Color as Color9, DoubleSide as DoubleSide3 } from "three";
|
|
4465
4538
|
function sampleFluid(kind, sample) {
|
|
4466
4539
|
const cells = [];
|
|
4467
4540
|
const key = [];
|
|
@@ -4512,7 +4585,7 @@ var init_FluidModelObject = __esm({
|
|
|
4512
4585
|
}
|
|
4513
4586
|
}
|
|
4514
4587
|
geometry.clearGroups();
|
|
4515
|
-
const color = new
|
|
4588
|
+
const color = new Color9(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
|
|
4516
4589
|
const colors = new Float32Array(geometry.getAttribute("position").count * 3);
|
|
4517
4590
|
for (let i = 0; i < colors.length; i += 3) color.toArray(colors, i);
|
|
4518
4591
|
geometry.setAttribute("color", new BufferAttribute6(colors, 3));
|
|
@@ -4778,6 +4851,59 @@ function shutdown() {
|
|
|
4778
4851
|
init_AssetKey();
|
|
4779
4852
|
init_AssetLoader();
|
|
4780
4853
|
init_Assets();
|
|
4854
|
+
|
|
4855
|
+
// src/assets/BlockEntities.ts
|
|
4856
|
+
init_AssetKey();
|
|
4857
|
+
init_AssetLoader();
|
|
4858
|
+
init_source();
|
|
4859
|
+
init_Caching();
|
|
4860
|
+
import { Matrix4 as Matrix43 } from "three";
|
|
4861
|
+
var BlockEntities = class {
|
|
4862
|
+
/**
|
|
4863
|
+
* Loads the block index of a version. Versions and sources without one yield an empty index, and so does
|
|
4864
|
+
* a failed load: the index is optional, and blocks must not retry or fail with it one by one. The empty
|
|
4865
|
+
* result is cached like any other; `Caching.clear()` or `AssetLoader.setVersion()` forces a new attempt.
|
|
4866
|
+
*/
|
|
4867
|
+
static async getIndex(root) {
|
|
4868
|
+
const key = new AssetKey("entity-models", "blocks", void 0, void 0, void 0, ".json", root);
|
|
4869
|
+
key.rootType = void 0;
|
|
4870
|
+
const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {
|
|
4871
|
+
try {
|
|
4872
|
+
return await AssetLoader.get(key, "json" /* JSON */) ?? {};
|
|
4873
|
+
} catch (error) {
|
|
4874
|
+
console.warn("Could not load the block entity index; block entities are drawn as plain block models", error);
|
|
4875
|
+
return {};
|
|
4876
|
+
}
|
|
4877
|
+
});
|
|
4878
|
+
return index ?? {};
|
|
4879
|
+
}
|
|
4880
|
+
/** The index entry of a block ID such as `minecraft:chest`. */
|
|
4881
|
+
static entry(index, block) {
|
|
4882
|
+
const entry = Object.prototype.hasOwnProperty.call(index, block) ? index[block] : void 0;
|
|
4883
|
+
return Array.isArray(entry?.parts) ? entry : void 0;
|
|
4884
|
+
}
|
|
4885
|
+
/** Selects the parts and placement for a block ID such as `minecraft:chest`; undefined when nothing is drawn. */
|
|
4886
|
+
static resolve(index, block, state = {}) {
|
|
4887
|
+
const entry = this.entry(index, block);
|
|
4888
|
+
if (!entry) return void 0;
|
|
4889
|
+
const value = (property) => String(state[property]).toLowerCase();
|
|
4890
|
+
const parts = entry.parts.filter((part) => Object.entries(part.when ?? {}).every(([property, values]) => String(values).split("|").includes(value(property))));
|
|
4891
|
+
if (!parts.length) return void 0;
|
|
4892
|
+
let rotation = 0;
|
|
4893
|
+
if (entry.rotation) {
|
|
4894
|
+
const selected = value(entry.rotation.property);
|
|
4895
|
+
rotation = "degrees" in entry.rotation ? entry.rotation.degrees[selected] : Number(selected) * entry.rotation.step;
|
|
4896
|
+
if (!Number.isFinite(rotation)) rotation = 0;
|
|
4897
|
+
}
|
|
4898
|
+
return { parts, rotation, translation: entry.translation ?? [0, 0, 0] };
|
|
4899
|
+
}
|
|
4900
|
+
/** Placement in block space (0..16 per axis), applied on top of the model's own transform. */
|
|
4901
|
+
static matrix(resolved, matrix = new Matrix43()) {
|
|
4902
|
+
return matrix.makeTranslation(8, 0, 8).multiply(new Matrix43().makeRotationY(resolved.rotation * Math.PI / 180)).multiply(new Matrix43().makeTranslation(resolved.translation[0] - 8, resolved.translation[1], resolved.translation[2] - 8));
|
|
4903
|
+
}
|
|
4904
|
+
};
|
|
4905
|
+
|
|
4906
|
+
// src/assets/index.ts
|
|
4781
4907
|
init_BlockStates();
|
|
4782
4908
|
|
|
4783
4909
|
// src/assets/Entities.ts
|
|
@@ -4809,32 +4935,53 @@ var Entities = class {
|
|
|
4809
4935
|
static async getLayerList(modelKey) {
|
|
4810
4936
|
return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
|
|
4811
4937
|
}
|
|
4938
|
+
/** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */
|
|
4939
|
+
static async getPassList(modelKey) {
|
|
4940
|
+
return (await this.getModelFile(modelKey))?.passes ?? [];
|
|
4941
|
+
}
|
|
4812
4942
|
static async getEntity(modelKey, textureKey, options) {
|
|
4813
4943
|
const model = await this.getModelFile(modelKey);
|
|
4814
4944
|
if (!model) return void 0;
|
|
4815
|
-
const
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4945
|
+
const passes = options?.layers || options?.layer !== void 0 ? [] : (model.passes ?? []).filter((pass) => pass.when === void 0 || options?.when?.includes(pass.when));
|
|
4946
|
+
const draws = [...new Set(options?.layers ?? [options?.layer ?? "main"])].map((layer) => ({ layer }));
|
|
4947
|
+
if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
|
|
4948
|
+
draws.push(...passes);
|
|
4949
|
+
const names = [];
|
|
4950
|
+
const selected = draws.map((pass) => {
|
|
4951
|
+
const layer = model.layers[pass.layer];
|
|
4819
4952
|
if (!layer) {
|
|
4820
|
-
throw new MineRenderError(`Entity ${model.id} has no layer "${
|
|
4953
|
+
throw new MineRenderError(`Entity ${model.id} has no layer "${pass.layer}". Available layers: ${Object.keys(model.layers).join(", ")}`);
|
|
4821
4954
|
}
|
|
4822
|
-
|
|
4955
|
+
let name = pass.layer;
|
|
4956
|
+
for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;
|
|
4957
|
+
names.push(name);
|
|
4958
|
+
return { name, layer, pass };
|
|
4823
4959
|
});
|
|
4824
|
-
const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer }, index) => {
|
|
4960
|
+
const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {
|
|
4825
4961
|
const override = options?.textures?.[name] ?? (index === 0 ? textureKey : void 0);
|
|
4962
|
+
const textureLocation = pass.textureLocation ?? layer.textureLocation;
|
|
4826
4963
|
let texture;
|
|
4827
4964
|
if (override) {
|
|
4828
4965
|
const path = isAssetKey(override) ? override.getFullPath() : override.path;
|
|
4829
4966
|
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);
|
|
4830
|
-
} else if (
|
|
4831
|
-
texture = AssetKey.parse("textures",
|
|
4967
|
+
} else if (textureLocation !== void 0) {
|
|
4968
|
+
texture = AssetKey.parse("textures", textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
|
|
4832
4969
|
} else {
|
|
4833
4970
|
texture = await this.resolveTexture(modelKey);
|
|
4834
4971
|
}
|
|
4835
|
-
|
|
4972
|
+
const render = pass.render ?? layer.render;
|
|
4973
|
+
return [name, { key: override ?? modelKey, texture, layer, ...render && { render }, ...pass.tint && { tint: pass.tint } }];
|
|
4836
4974
|
})));
|
|
4837
|
-
return { ...layers[names[0]], id: model.id, layers };
|
|
4975
|
+
return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
|
|
4976
|
+
}
|
|
4977
|
+
/**
|
|
4978
|
+
* Vanilla's keyframe animations of a model by name, or undefined when the model or the selected version has none.
|
|
4979
|
+
*/
|
|
4980
|
+
static async getAnimations(modelKey) {
|
|
4981
|
+
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
4982
|
+
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json");
|
|
4983
|
+
const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
4984
|
+
return file?.animations;
|
|
4838
4985
|
}
|
|
4839
4986
|
static async resolveTexture(modelKey) {
|
|
4840
4987
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
@@ -4912,15 +5059,129 @@ function trimCanvas(source) {
|
|
|
4912
5059
|
return canvas;
|
|
4913
5060
|
}
|
|
4914
5061
|
|
|
5062
|
+
// src/entity/EntityAnimation.ts
|
|
5063
|
+
var ENTITY_ANIMATION_CHANNELS = ["position", "rotation", "scale"];
|
|
5064
|
+
function catmullRom(delta, p0, p1, p22, p32) {
|
|
5065
|
+
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);
|
|
5066
|
+
}
|
|
5067
|
+
function sampleEntityKeyframes(keyframes, time) {
|
|
5068
|
+
if (keyframes.length === 0) return [0, 0, 0];
|
|
5069
|
+
let low = 0, high = keyframes.length;
|
|
5070
|
+
while (low < high) {
|
|
5071
|
+
const middle = low + high >>> 1;
|
|
5072
|
+
if (time <= keyframes[middle].time) high = middle;
|
|
5073
|
+
else low = middle + 1;
|
|
5074
|
+
}
|
|
5075
|
+
const a = Math.max(0, low - 1);
|
|
5076
|
+
const b = Math.min(keyframes.length - 1, a + 1);
|
|
5077
|
+
const from = keyframes[a];
|
|
5078
|
+
const to = keyframes[b];
|
|
5079
|
+
const delta = a === b ? 0 : Math.min(1, Math.max(0, (time - from.time) / (to.time - from.time)));
|
|
5080
|
+
if (to.interpolation === "catmullrom") {
|
|
5081
|
+
const before = keyframes[Math.max(0, a - 1)].value;
|
|
5082
|
+
const after = keyframes[Math.min(keyframes.length - 1, b + 1)].value;
|
|
5083
|
+
return [0, 1, 2].map((i) => catmullRom(delta, before[i], from.value[i], to.value[i], after[i]));
|
|
5084
|
+
}
|
|
5085
|
+
const target = to.pre ?? to.value;
|
|
5086
|
+
return [0, 1, 2].map((i) => from.value[i] + (target[i] - from.value[i]) * delta);
|
|
5087
|
+
}
|
|
5088
|
+
function entityAnimationTime(animation, time, loop = animation.loop) {
|
|
5089
|
+
return loop && animation.length > 0 ? time % animation.length : time;
|
|
5090
|
+
}
|
|
5091
|
+
function sampleEntityAnimation(animation, time, loop = animation.loop) {
|
|
5092
|
+
const elapsed = entityAnimationTime(animation, time, loop);
|
|
5093
|
+
const pose = {};
|
|
5094
|
+
for (const [name, bone] of Object.entries(animation.bones)) {
|
|
5095
|
+
const sampled = pose[name] = {};
|
|
5096
|
+
for (const channel of ENTITY_ANIMATION_CHANNELS) {
|
|
5097
|
+
const keyframes = bone[channel];
|
|
5098
|
+
if (keyframes?.length) sampled[channel] = sampleEntityKeyframes(keyframes, elapsed);
|
|
5099
|
+
}
|
|
5100
|
+
}
|
|
5101
|
+
return pose;
|
|
5102
|
+
}
|
|
5103
|
+
|
|
5104
|
+
// src/entity/scene/EntityAnimationPlayer.ts
|
|
5105
|
+
var ZERO = [0, 0, 0];
|
|
5106
|
+
var EntityAnimationPlayer = class {
|
|
5107
|
+
constructor() {
|
|
5108
|
+
this.parts = [];
|
|
5109
|
+
this._time = 0;
|
|
5110
|
+
this.loop = false;
|
|
5111
|
+
this.speed = 1;
|
|
5112
|
+
}
|
|
5113
|
+
get animation() {
|
|
5114
|
+
return this._animation;
|
|
5115
|
+
}
|
|
5116
|
+
get time() {
|
|
5117
|
+
return this._time;
|
|
5118
|
+
}
|
|
5119
|
+
/**
|
|
5120
|
+
* Starts an animation on the named parts below each layer root. The current pose of a part becomes its default;
|
|
5121
|
+
* bones without a matching part are skipped.
|
|
5122
|
+
*/
|
|
5123
|
+
play(layers, animation, options = {}) {
|
|
5124
|
+
this.stop();
|
|
5125
|
+
this._animation = animation;
|
|
5126
|
+
this._time = options.time ?? 0;
|
|
5127
|
+
this.loop = options.loop ?? animation.loop;
|
|
5128
|
+
this.speed = options.speed ?? 1;
|
|
5129
|
+
for (const layer of layers) {
|
|
5130
|
+
for (const bone of Object.keys(animation.bones)) {
|
|
5131
|
+
const object = layer.getObjectByName(`group:${bone}`);
|
|
5132
|
+
if (!object) continue;
|
|
5133
|
+
this.parts.push({ bone, object, position: object.position.clone(), rotation: object.rotation.clone(), scale: object.scale.clone() });
|
|
5134
|
+
}
|
|
5135
|
+
}
|
|
5136
|
+
this.apply();
|
|
5137
|
+
}
|
|
5138
|
+
/** Restores the default poses. Returns whether an animation was active. */
|
|
5139
|
+
stop() {
|
|
5140
|
+
if (!this._animation) return false;
|
|
5141
|
+
for (const part of this.parts) {
|
|
5142
|
+
part.object.position.copy(part.position);
|
|
5143
|
+
part.object.rotation.copy(part.rotation);
|
|
5144
|
+
part.object.scale.copy(part.scale);
|
|
5145
|
+
}
|
|
5146
|
+
this.clear();
|
|
5147
|
+
return true;
|
|
5148
|
+
}
|
|
5149
|
+
/** Forgets the animation without touching the parts, for parts that no longer exist. */
|
|
5150
|
+
clear() {
|
|
5151
|
+
this.parts = [];
|
|
5152
|
+
this._animation = void 0;
|
|
5153
|
+
this._time = 0;
|
|
5154
|
+
}
|
|
5155
|
+
setTime(seconds) {
|
|
5156
|
+
if (!this._animation) return false;
|
|
5157
|
+
this._time = seconds;
|
|
5158
|
+
this.apply();
|
|
5159
|
+
return true;
|
|
5160
|
+
}
|
|
5161
|
+
advance(deltaSeconds) {
|
|
5162
|
+
return this.setTime(this._time + deltaSeconds * this.speed);
|
|
5163
|
+
}
|
|
5164
|
+
apply() {
|
|
5165
|
+
const pose = sampleEntityAnimation(this._animation, this._time, this.loop);
|
|
5166
|
+
for (const part of this.parts) {
|
|
5167
|
+
const { position = ZERO, rotation = ZERO, scale = ZERO } = pose[part.bone];
|
|
5168
|
+
part.object.position.set(part.position.x + position[0], part.position.y + position[1], part.position.z + position[2]);
|
|
5169
|
+
part.object.rotation.set(part.rotation.x + rotation[0], part.rotation.y + rotation[1], part.rotation.z + rotation[2], part.rotation.order);
|
|
5170
|
+
part.object.scale.set(part.scale.x + scale[0], part.scale.y + scale[1], part.scale.z + scale[2]);
|
|
5171
|
+
}
|
|
5172
|
+
}
|
|
5173
|
+
};
|
|
5174
|
+
|
|
4915
5175
|
// src/entity/scene/EntityObject.ts
|
|
4916
5176
|
init_SceneObject();
|
|
4917
5177
|
init_Caching();
|
|
4918
5178
|
var import_ts_deepmerge4 = __toESM(require_dist());
|
|
5179
|
+
init_Ticker();
|
|
4919
5180
|
init_model();
|
|
4920
5181
|
init_ModelTextures();
|
|
4921
5182
|
init_AssetKey();
|
|
4922
5183
|
init_Materials();
|
|
4923
|
-
import { Object3D as Object3D3 } from "three";
|
|
5184
|
+
import { Color as Color3, Euler as Euler4, Matrix4 as Matrix45, Object3D as Object3D3 } from "three";
|
|
4924
5185
|
init_three();
|
|
4925
5186
|
var EntityObject = class _EntityObject extends SceneObject {
|
|
4926
5187
|
constructor(entity, options) {
|
|
@@ -4928,10 +5189,15 @@ var EntityObject = class _EntityObject extends SceneObject {
|
|
|
4928
5189
|
this.entity = entity;
|
|
4929
5190
|
this.isEntityObject = true;
|
|
4930
5191
|
this.meshesCreated = false;
|
|
5192
|
+
/** Scrolling materials are owned: their texture offset follows this entity's age. */
|
|
5193
|
+
this.scrollMaterials = [];
|
|
5194
|
+
/** Entity age in ticks, as vanilla's `ageInTicks`; drives the scrolling render modes. */
|
|
5195
|
+
this.age = 0;
|
|
5196
|
+
this.animationPlayer = new EntityAnimationPlayer();
|
|
4931
5197
|
this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
|
|
4932
5198
|
}
|
|
4933
5199
|
static {
|
|
4934
|
-
this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS
|
|
5200
|
+
this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS);
|
|
4935
5201
|
}
|
|
4936
5202
|
async init() {
|
|
4937
5203
|
this.createMeshes();
|
|
@@ -4940,6 +5206,59 @@ var EntityObject = class _EntityObject extends SceneObject {
|
|
|
4940
5206
|
dispose() {
|
|
4941
5207
|
super.dispose();
|
|
4942
5208
|
}
|
|
5209
|
+
disposeAndRemoveAllChildren() {
|
|
5210
|
+
this.clearScrollMaterials();
|
|
5211
|
+
this.animationPlayer.clear();
|
|
5212
|
+
super.disposeAndRemoveAllChildren();
|
|
5213
|
+
}
|
|
5214
|
+
clearScrollMaterials() {
|
|
5215
|
+
Ticker.remove(this.scrollTicker);
|
|
5216
|
+
this.scrollTicker = void 0;
|
|
5217
|
+
for (const { material } of this.scrollMaterials.splice(0)) {
|
|
5218
|
+
material.map?.dispose();
|
|
5219
|
+
material.dispose();
|
|
5220
|
+
}
|
|
5221
|
+
}
|
|
5222
|
+
/** Applies the entity age to the scrolling materials; the ticker calls this 20 times per second. */
|
|
5223
|
+
updateScroll() {
|
|
5224
|
+
for (const { offset, speed } of this.scrollMaterials) {
|
|
5225
|
+
offset.set(this.age * speed[0] % 1, 0 - this.age * speed[1] % 1);
|
|
5226
|
+
}
|
|
5227
|
+
this.notifyDirty();
|
|
5228
|
+
}
|
|
5229
|
+
//<editor-fold desc="ANIMATION">
|
|
5230
|
+
/** The animation started by {@link playAnimation}, until {@link stopAnimation} or disposal. */
|
|
5231
|
+
get animation() {
|
|
5232
|
+
return this.animationPlayer.animation;
|
|
5233
|
+
}
|
|
5234
|
+
/** Seconds since the animation started, before looping. */
|
|
5235
|
+
get animationTime() {
|
|
5236
|
+
return this.animationPlayer.time;
|
|
5237
|
+
}
|
|
5238
|
+
/**
|
|
5239
|
+
* Poses the object from a keyframe animation of {@link Entities.getAnimations}, replacing the current one.
|
|
5240
|
+
* Parts of every layer are matched by name and their current pose is the default the offsets add to.
|
|
5241
|
+
* The object owns no clock: call {@link advanceAnimation} per frame, or {@link setAnimationTime}.
|
|
5242
|
+
*/
|
|
5243
|
+
playAnimation(animation, options) {
|
|
5244
|
+
this.createMeshes();
|
|
5245
|
+
const layers = Object.keys(this.entityLayers).map((name) => this.getLayerGroup(name)).filter((layer) => !!layer);
|
|
5246
|
+
this.animationPlayer.play(layers, animation, options);
|
|
5247
|
+
this.notifyDirty();
|
|
5248
|
+
}
|
|
5249
|
+
/** Stops the animation and restores the default pose. */
|
|
5250
|
+
stopAnimation() {
|
|
5251
|
+
if (this.animationPlayer.stop()) this.notifyDirty();
|
|
5252
|
+
}
|
|
5253
|
+
/** Poses the object at an explicit time in seconds. Has no effect without an animation. */
|
|
5254
|
+
setAnimationTime(seconds) {
|
|
5255
|
+
if (this.animationPlayer.setTime(seconds)) this.notifyDirty();
|
|
5256
|
+
}
|
|
5257
|
+
/** Advances the animation by a frame delta in seconds, scaled by its speed. Has no effect without an animation. */
|
|
5258
|
+
advanceAnimation(deltaSeconds) {
|
|
5259
|
+
if (this.animationPlayer.advance(deltaSeconds)) this.notifyDirty();
|
|
5260
|
+
}
|
|
5261
|
+
//</editor-fold>
|
|
4943
5262
|
getLayerGroup(name) {
|
|
4944
5263
|
return super.getGroupByName(`layer:${name}`);
|
|
4945
5264
|
}
|
|
@@ -4970,16 +5289,29 @@ var EntityObject = class _EntityObject extends SceneObject {
|
|
|
4970
5289
|
createMeshes(force = false) {
|
|
4971
5290
|
if (this.meshesCreated && !force) return;
|
|
4972
5291
|
const modelRoot = new Object3D3();
|
|
4973
|
-
|
|
5292
|
+
const transform = this.options.flip === void 0 ? this.entity.transform : void 0;
|
|
5293
|
+
if (transform) {
|
|
5294
|
+
for (const op of transform) {
|
|
5295
|
+
const matrix = new Matrix45();
|
|
5296
|
+
if ("scale" in op) matrix.makeScale(...op.scale);
|
|
5297
|
+
else if ("translate" in op) matrix.makeTranslation(...op.translate);
|
|
5298
|
+
else matrix.makeRotationFromEuler(new Euler4(...op.rotate, "ZYX"));
|
|
5299
|
+
modelRoot.matrix.multiply(matrix);
|
|
5300
|
+
}
|
|
5301
|
+
modelRoot.matrixAutoUpdate = false;
|
|
5302
|
+
} else if (this.options.flip ?? true) {
|
|
5303
|
+
modelRoot.scale.set(-1, -1, 1);
|
|
5304
|
+
}
|
|
4974
5305
|
this.add(modelRoot);
|
|
4975
5306
|
Object.entries(this.entityLayers).forEach(([name, layer], index) => {
|
|
4976
5307
|
const group = this.createGroup(`layer:${name}`);
|
|
4977
5308
|
modelRoot.add(group);
|
|
4978
|
-
|
|
5309
|
+
const inward = !Materials.entityModeCulls(layer.render ?? layer.layer.render);
|
|
5310
|
+
this.createPart("root", layer.layer.root, group, layer.layer.texture, Materials.MISSING_TEXTURE, index, inward);
|
|
4979
5311
|
});
|
|
4980
5312
|
this.meshesCreated = true;
|
|
4981
5313
|
}
|
|
4982
|
-
createPart(name, part, parent, textureSize, material, renderOrder) {
|
|
5314
|
+
createPart(name, part, parent, textureSize, material, renderOrder, inward = true) {
|
|
4983
5315
|
const anchor = this.createGroup(name);
|
|
4984
5316
|
anchor.position.fromArray(part.pose.offset);
|
|
4985
5317
|
anchor.rotation.set(...part.pose.rotation, "ZYX");
|
|
@@ -4998,7 +5330,7 @@ var EntityObject = class _EntityObject extends SceneObject {
|
|
|
4998
5330
|
uv
|
|
4999
5331
|
).clone();
|
|
5000
5332
|
geometry.translate(cube.origin[0] + width / 2, cube.origin[1] + height / 2, cube.origin[2] + depth / 2);
|
|
5001
|
-
if (Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
|
|
5333
|
+
if (inward && Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
|
|
5002
5334
|
const index = Array.from(geometry.getIndex().array);
|
|
5003
5335
|
geometry.setIndex(index.concat(index.slice().reverse()));
|
|
5004
5336
|
}
|
|
@@ -5008,26 +5340,42 @@ var EntityObject = class _EntityObject extends SceneObject {
|
|
|
5008
5340
|
if (this.options.wireframe) addWireframeToMesh(geometry, mesh);
|
|
5009
5341
|
}
|
|
5010
5342
|
for (const [childName, child] of Object.entries(part.children)) {
|
|
5011
|
-
this.createPart(childName, child, anchor, size, material, renderOrder);
|
|
5343
|
+
this.createPart(childName, child, anchor, size, material, renderOrder, inward);
|
|
5012
5344
|
}
|
|
5013
5345
|
}
|
|
5014
5346
|
async applyTextures() {
|
|
5347
|
+
this.clearScrollMaterials();
|
|
5015
5348
|
await Promise.all(Object.entries(this.entityLayers).map(async ([name, layer]) => {
|
|
5349
|
+
const mode = layer.render ?? layer.layer.render ?? "cutout";
|
|
5350
|
+
const tint = layer.tint === void 0 ? void 0 : this.options.tints?.[layer.tint];
|
|
5351
|
+
const scroll = Materials.entityModeScroll(mode);
|
|
5016
5352
|
const assetKeyStr = this.getTextureKey(layer).serialize();
|
|
5017
|
-
const keyStr = `entity:${assetKeyStr}`;
|
|
5018
|
-
let mat = Caching.materialCache.getIfPresent(keyStr);
|
|
5353
|
+
const keyStr = `entity:${mode}:${tint === void 0 ? "" : new Color3(tint).getHexString()}:${assetKeyStr}`;
|
|
5354
|
+
let mat = scroll ? void 0 : Caching.materialCache.getIfPresent(keyStr);
|
|
5019
5355
|
if (!mat) {
|
|
5020
5356
|
const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
|
|
5021
5357
|
const imageData = await this.loadTextures(layer);
|
|
5022
5358
|
if (!imageData) return;
|
|
5023
5359
|
const canvas = imageData.data.canvas;
|
|
5024
|
-
const createMaterial = () => Materials.
|
|
5025
|
-
mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
|
|
5360
|
+
const createMaterial = () => Materials.createEntityCanvasMaterial(canvas, mode, tint);
|
|
5361
|
+
mat = !scroll && cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
|
|
5362
|
+
if (scroll) {
|
|
5363
|
+
this.scrollMaterials.push({ material: mat, offset: mat.map.offset, speed: scroll });
|
|
5364
|
+
}
|
|
5026
5365
|
}
|
|
5027
5366
|
this.getLayerGroup(name)?.traverse((object) => {
|
|
5028
5367
|
if (isMesh(object)) object.material = mat;
|
|
5029
5368
|
});
|
|
5030
5369
|
}));
|
|
5370
|
+
if (!this.children.length) {
|
|
5371
|
+
this.clearScrollMaterials();
|
|
5372
|
+
} else if (this.scrollMaterials.length) {
|
|
5373
|
+
this.updateScroll();
|
|
5374
|
+
this.scrollTicker = Ticker.add(() => {
|
|
5375
|
+
this.age++;
|
|
5376
|
+
this.updateScroll();
|
|
5377
|
+
});
|
|
5378
|
+
}
|
|
5031
5379
|
this.notifyDirty();
|
|
5032
5380
|
}
|
|
5033
5381
|
};
|
|
@@ -5039,11 +5387,11 @@ function isEntityObject(obj) {
|
|
|
5039
5387
|
init_MineRenderError();
|
|
5040
5388
|
|
|
5041
5389
|
// src/export/SceneExporter.ts
|
|
5042
|
-
import { ClampToEdgeWrapping as ClampToEdgeWrapping2, Color as
|
|
5390
|
+
import { ClampToEdgeWrapping as ClampToEdgeWrapping2, Color as Color7, Float32BufferAttribute as Float32BufferAttribute3, Matrix4 as Matrix47, Mesh as Mesh5, MeshBasicMaterial as MeshBasicMaterial2, NearestFilter as NearestFilter3, RGBAFormat as RGBAFormat3, Scene as Scene4, Source as Source2, Texture as Texture4, UnsignedByteType } from "three";
|
|
5043
5391
|
|
|
5044
5392
|
// ../../node_modules/three/examples/jsm/exporters/OBJExporter.js
|
|
5045
5393
|
import {
|
|
5046
|
-
Color as
|
|
5394
|
+
Color as Color4,
|
|
5047
5395
|
Matrix3,
|
|
5048
5396
|
Vector2 as Vector22,
|
|
5049
5397
|
Vector3 as Vector36
|
|
@@ -5055,7 +5403,7 @@ var OBJExporter = class {
|
|
|
5055
5403
|
let indexVertexUvs = 0;
|
|
5056
5404
|
let indexNormals = 0;
|
|
5057
5405
|
const vertex = new Vector36();
|
|
5058
|
-
const color = new
|
|
5406
|
+
const color = new Color4();
|
|
5059
5407
|
const normal = new Vector36();
|
|
5060
5408
|
const uv = new Vector22();
|
|
5061
5409
|
const face = [];
|
|
@@ -5186,7 +5534,7 @@ var OBJExporter = class {
|
|
|
5186
5534
|
import {
|
|
5187
5535
|
Matrix3 as Matrix32,
|
|
5188
5536
|
Vector3 as Vector37,
|
|
5189
|
-
Color as
|
|
5537
|
+
Color as Color5
|
|
5190
5538
|
} from "three";
|
|
5191
5539
|
var PLYExporter = class {
|
|
5192
5540
|
parse(object, onDone, options = {}) {
|
|
@@ -5244,7 +5592,7 @@ var PLYExporter = class {
|
|
|
5244
5592
|
includeIndices = false;
|
|
5245
5593
|
}
|
|
5246
5594
|
});
|
|
5247
|
-
const tempColor = new
|
|
5595
|
+
const tempColor = new Color5();
|
|
5248
5596
|
includeIndices = includeIndices && excludeAttributes.indexOf("index") === -1;
|
|
5249
5597
|
includeNormals = includeNormals && excludeAttributes.indexOf("normal") === -1;
|
|
5250
5598
|
includeColors = includeColors && excludeAttributes.indexOf("color") === -1;
|
|
@@ -5456,7 +5804,7 @@ property list uchar int vertex_index
|
|
|
5456
5804
|
import {
|
|
5457
5805
|
BufferAttribute as BufferAttribute3,
|
|
5458
5806
|
ClampToEdgeWrapping,
|
|
5459
|
-
Color as
|
|
5807
|
+
Color as Color6,
|
|
5460
5808
|
DoubleSide as DoubleSide2,
|
|
5461
5809
|
InterpolateDiscrete,
|
|
5462
5810
|
InterpolateLinear,
|
|
@@ -5465,14 +5813,14 @@ import {
|
|
|
5465
5813
|
LinearMipmapLinearFilter,
|
|
5466
5814
|
LinearMipmapNearestFilter,
|
|
5467
5815
|
MathUtils as MathUtils2,
|
|
5468
|
-
Matrix4 as
|
|
5816
|
+
Matrix4 as Matrix46,
|
|
5469
5817
|
MirroredRepeatWrapping,
|
|
5470
5818
|
NearestFilter as NearestFilter2,
|
|
5471
5819
|
NearestMipmapLinearFilter,
|
|
5472
5820
|
NearestMipmapNearestFilter,
|
|
5473
5821
|
PropertyBinding,
|
|
5474
5822
|
RGBAFormat as RGBAFormat2,
|
|
5475
|
-
RepeatWrapping,
|
|
5823
|
+
RepeatWrapping as RepeatWrapping2,
|
|
5476
5824
|
Scene as Scene3,
|
|
5477
5825
|
Source,
|
|
5478
5826
|
SRGBColorSpace as SRGBColorSpace4,
|
|
@@ -5690,7 +6038,7 @@ THREE_TO_WEBGL[LinearFilter] = WEBGL_CONSTANTS.LINEAR;
|
|
|
5690
6038
|
THREE_TO_WEBGL[LinearMipmapNearestFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST;
|
|
5691
6039
|
THREE_TO_WEBGL[LinearMipmapLinearFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR;
|
|
5692
6040
|
THREE_TO_WEBGL[ClampToEdgeWrapping] = WEBGL_CONSTANTS.CLAMP_TO_EDGE;
|
|
5693
|
-
THREE_TO_WEBGL[
|
|
6041
|
+
THREE_TO_WEBGL[RepeatWrapping2] = WEBGL_CONSTANTS.REPEAT;
|
|
5694
6042
|
THREE_TO_WEBGL[MirroredRepeatWrapping] = WEBGL_CONSTANTS.MIRRORED_REPEAT;
|
|
5695
6043
|
var PATH_PROPERTIES = {
|
|
5696
6044
|
scale: "scale",
|
|
@@ -5698,7 +6046,7 @@ var PATH_PROPERTIES = {
|
|
|
5698
6046
|
quaternion: "rotation",
|
|
5699
6047
|
morphTargetInfluences: "weights"
|
|
5700
6048
|
};
|
|
5701
|
-
var DEFAULT_SPECULAR_COLOR = new
|
|
6049
|
+
var DEFAULT_SPECULAR_COLOR = new Color6();
|
|
5702
6050
|
var GLB_HEADER_BYTES = 12;
|
|
5703
6051
|
var GLB_HEADER_MAGIC = 1179937895;
|
|
5704
6052
|
var GLB_VERSION = 2;
|
|
@@ -6755,7 +7103,7 @@ var GLTFWriter = class {
|
|
|
6755
7103
|
if (rootJoint === void 0) return null;
|
|
6756
7104
|
const joints = [];
|
|
6757
7105
|
const inverseBindMatrices = new Float32Array(skeleton.bones.length * 16);
|
|
6758
|
-
const temporaryBoneInverse = new
|
|
7106
|
+
const temporaryBoneInverse = new Matrix46();
|
|
6759
7107
|
for (let i = 0; i < skeleton.bones.length; ++i) {
|
|
6760
7108
|
joints.push(nodeMap.get(skeleton.bones[i]));
|
|
6761
7109
|
temporaryBoneInverse.copy(skeleton.boneInverses[i]);
|
|
@@ -7221,7 +7569,7 @@ var GLTFMeshGpuInstancing = class {
|
|
|
7221
7569
|
const translationAttr = new Float32Array(mesh.count * 3);
|
|
7222
7570
|
const rotationAttr = new Float32Array(mesh.count * 4);
|
|
7223
7571
|
const scaleAttr = new Float32Array(mesh.count * 3);
|
|
7224
|
-
const matrix = new
|
|
7572
|
+
const matrix = new Matrix46();
|
|
7225
7573
|
const position = new Vector38();
|
|
7226
7574
|
const quaternion = new Quaternion4();
|
|
7227
7575
|
const scale = new Vector38();
|
|
@@ -7395,7 +7743,7 @@ var SceneExporter = class {
|
|
|
7395
7743
|
}
|
|
7396
7744
|
};
|
|
7397
7745
|
function localMatrix(object) {
|
|
7398
|
-
return object.matrixAutoUpdate ? new
|
|
7746
|
+
return object.matrixAutoUpdate ? new Matrix47().compose(object.position, object.quaternion, object.scale) : object.matrix.clone();
|
|
7399
7747
|
}
|
|
7400
7748
|
function createSnapshot(root, gltf, bakeColors = false) {
|
|
7401
7749
|
const scene = new Scene4();
|
|
@@ -7480,7 +7828,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
|
|
|
7480
7828
|
const material = copyMaterial(sourceMaterial, geometry);
|
|
7481
7829
|
if (!sourceMaterial.vertexColors) geometry.deleteAttribute("color");
|
|
7482
7830
|
if (bakeColors || instanceColor) {
|
|
7483
|
-
const tint = (material.color ?? new
|
|
7831
|
+
const tint = (material.color ?? new Color7()).clone();
|
|
7484
7832
|
if (instanceColor) tint.multiply(instanceColor);
|
|
7485
7833
|
if (bakeColors) {
|
|
7486
7834
|
const original = geometry.getAttribute("color");
|
|
@@ -7507,9 +7855,9 @@ function createSnapshot(root, gltf, bakeColors = false) {
|
|
|
7507
7855
|
const instanced = mesh;
|
|
7508
7856
|
if (instanced.isInstancedMesh) {
|
|
7509
7857
|
for (let i = 0; i < instanced.count; i++) {
|
|
7510
|
-
const matrix = new
|
|
7858
|
+
const matrix = new Matrix47();
|
|
7511
7859
|
instanced.getMatrixAt(i, matrix);
|
|
7512
|
-
const color = instanced.instanceColor ? new
|
|
7860
|
+
const color = instanced.instanceColor ? new Color7().fromBufferAttribute(instanced.instanceColor, i) : void 0;
|
|
7513
7861
|
addMesh(mesh, world.clone().multiply(matrix), color);
|
|
7514
7862
|
}
|
|
7515
7863
|
} else {
|
|
@@ -7521,7 +7869,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
|
|
|
7521
7869
|
try {
|
|
7522
7870
|
const ancestors = [];
|
|
7523
7871
|
for (let parent = root.parent; parent; parent = parent.parent) ancestors.unshift(parent);
|
|
7524
|
-
const world = new
|
|
7872
|
+
const world = new Matrix47();
|
|
7525
7873
|
for (const ancestor of ancestors) {
|
|
7526
7874
|
if (!ancestor.visible) return { scene, dispose };
|
|
7527
7875
|
world.multiply(localMatrix(ancestor));
|
|
@@ -7588,11 +7936,69 @@ function copyDataTexture(source) {
|
|
|
7588
7936
|
}
|
|
7589
7937
|
|
|
7590
7938
|
// src/gui/GuiHelper.ts
|
|
7939
|
+
init_AssetKey();
|
|
7591
7940
|
var GuiHelper = class {
|
|
7592
7941
|
static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
|
|
7593
7942
|
const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
|
|
7594
7943
|
return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
|
|
7595
7944
|
}
|
|
7945
|
+
/** Creates crafting-table layers for ingredients and the result; stack counts are not drawn. */
|
|
7946
|
+
static recipe(recipe, options = {}) {
|
|
7947
|
+
const layers = [
|
|
7948
|
+
{ name: "background", texture: "minecraft:gui/container/crafting_table", crop: [0, 0, 176, 166] }
|
|
7949
|
+
];
|
|
7950
|
+
const itemKey = (ingredient) => {
|
|
7951
|
+
const item = typeof ingredient === "string" && !ingredient.startsWith("#") ? ingredient : typeof ingredient === "object" && "item" in ingredient ? ingredient.item : options.resolveIngredient?.(ingredient);
|
|
7952
|
+
if (isAssetKey(item)) return item;
|
|
7953
|
+
if (!item || item.startsWith("#")) {
|
|
7954
|
+
throw new Error(`Select a concrete item for recipe ingredient ${JSON.stringify(ingredient)}`);
|
|
7955
|
+
}
|
|
7956
|
+
const key = AssetKey.parse("models", item);
|
|
7957
|
+
return new AssetKey(key.namespace, key.getFullPath(), "models", "item");
|
|
7958
|
+
};
|
|
7959
|
+
const addIngredient = (ingredient, slot) => {
|
|
7960
|
+
layers.push({
|
|
7961
|
+
name: `ingredient-${slot}`,
|
|
7962
|
+
item: itemKey(ingredient),
|
|
7963
|
+
position: this.inventorySlot(slot, [30, 17], [18, 18], 3)
|
|
7964
|
+
});
|
|
7965
|
+
};
|
|
7966
|
+
switch (recipe.type) {
|
|
7967
|
+
case "minecraft:crafting_shaped":
|
|
7968
|
+
case "crafting_shaped": {
|
|
7969
|
+
const pattern = recipe.pattern;
|
|
7970
|
+
if (!pattern.length || pattern.length > 3 || !pattern[0].length || pattern[0].length > 3 || pattern.some((row) => row.length !== pattern[0].length)) {
|
|
7971
|
+
throw new Error("Crafting patterns must be rectangular, with 1\u20133 rows and columns");
|
|
7972
|
+
}
|
|
7973
|
+
const cells = pattern.flatMap((row, y) => row.split("").map((symbol, x) => ({ symbol, x, y }))).filter((cell) => cell.symbol !== " ");
|
|
7974
|
+
if (!cells.length) throw new Error("Crafting patterns must contain an ingredient");
|
|
7975
|
+
const minX = Math.min(...cells.map((cell) => cell.x)), maxX = Math.max(...cells.map((cell) => cell.x));
|
|
7976
|
+
const minY = Math.min(...cells.map((cell) => cell.y)), maxY = Math.max(...cells.map((cell) => cell.y));
|
|
7977
|
+
const offsetX = minX === maxX ? 1 : 0, offsetY = minY === maxY ? 1 : 0;
|
|
7978
|
+
for (const { symbol, x, y } of cells) {
|
|
7979
|
+
const ingredient = recipe.key[symbol];
|
|
7980
|
+
if (!ingredient) throw new Error(`Missing recipe ingredient for symbol ${JSON.stringify(symbol)}`);
|
|
7981
|
+
addIngredient(ingredient, (y - minY + offsetY) * 3 + x - minX + offsetX);
|
|
7982
|
+
}
|
|
7983
|
+
break;
|
|
7984
|
+
}
|
|
7985
|
+
case "minecraft:crafting_shapeless":
|
|
7986
|
+
case "crafting_shapeless":
|
|
7987
|
+
if (!recipe.ingredients.length || recipe.ingredients.length > 9) {
|
|
7988
|
+
throw new Error("Shapeless crafting recipes require 1\u20139 ingredients");
|
|
7989
|
+
}
|
|
7990
|
+
recipe.ingredients.forEach(addIngredient);
|
|
7991
|
+
break;
|
|
7992
|
+
default:
|
|
7993
|
+
throw new Error(`Unsupported crafting recipe type: ${recipe.type}`);
|
|
7994
|
+
}
|
|
7995
|
+
layers.push({
|
|
7996
|
+
name: "result",
|
|
7997
|
+
item: itemKey("id" in recipe.result ? recipe.result.id : recipe.result.item),
|
|
7998
|
+
position: [124, 35]
|
|
7999
|
+
});
|
|
8000
|
+
return layers;
|
|
8001
|
+
}
|
|
7596
8002
|
};
|
|
7597
8003
|
|
|
7598
8004
|
// src/gui/scene/GuiObject.ts
|
|
@@ -8180,7 +8586,7 @@ init_ModelMerger();
|
|
|
8180
8586
|
init_BlockStates();
|
|
8181
8587
|
init_MineRenderError();
|
|
8182
8588
|
init_util();
|
|
8183
|
-
import { Euler as
|
|
8589
|
+
import { Euler as Euler7 } from "three";
|
|
8184
8590
|
function matchesCondition(condition, state) {
|
|
8185
8591
|
return Object.entries(condition).every(([key, value]) => {
|
|
8186
8592
|
if (Array.isArray(value)) {
|
|
@@ -8255,7 +8661,7 @@ var BlockStateResolver = class {
|
|
|
8255
8661
|
return variants[variants.length - 1];
|
|
8256
8662
|
}
|
|
8257
8663
|
static rotation(variant) {
|
|
8258
|
-
const rotation = new
|
|
8664
|
+
const rotation = new Euler7();
|
|
8259
8665
|
if (typeof variant.x !== "undefined") {
|
|
8260
8666
|
rotation.x = toRadians(clampRotationDegrees(variant.x));
|
|
8261
8667
|
}
|
|
@@ -8365,7 +8771,7 @@ var import_ts_deepmerge6 = __toESM(require_dist());
|
|
|
8365
8771
|
init_MineRenderError();
|
|
8366
8772
|
init_InstanceReference();
|
|
8367
8773
|
init_AssetKey();
|
|
8368
|
-
import { Euler as
|
|
8774
|
+
import { Euler as Euler8, Matrix4 as Matrix49, Quaternion as Quaternion5, Vector3 as Vector311 } from "three";
|
|
8369
8775
|
init_ModelCulling();
|
|
8370
8776
|
init_FluidGeometry();
|
|
8371
8777
|
var BlockObject = class _BlockObject extends SceneObject {
|
|
@@ -8382,6 +8788,9 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
8382
8788
|
this._variants = [];
|
|
8383
8789
|
this._models = [];
|
|
8384
8790
|
this._cullMask = 0;
|
|
8791
|
+
this._entities = [];
|
|
8792
|
+
this._entityPlacement = new Matrix49();
|
|
8793
|
+
this._entityGeneration = 0;
|
|
8385
8794
|
this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
|
|
8386
8795
|
}
|
|
8387
8796
|
static {
|
|
@@ -8406,6 +8815,8 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
8406
8815
|
}
|
|
8407
8816
|
clearModels() {
|
|
8408
8817
|
this.removeModels(this._models.splice(0));
|
|
8818
|
+
this._entityGeneration++;
|
|
8819
|
+
this.removeEntities(this._entities.splice(0));
|
|
8409
8820
|
this._fluidKey = void 0;
|
|
8410
8821
|
this._fluidModel = void 0;
|
|
8411
8822
|
this._isInstanced = false;
|
|
@@ -8417,6 +8828,57 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
8417
8828
|
if (!isInstanceReference(model)) model.dispose();
|
|
8418
8829
|
}
|
|
8419
8830
|
}
|
|
8831
|
+
removeEntities(entities) {
|
|
8832
|
+
for (const entity of entities) {
|
|
8833
|
+
entity.removeFromScene();
|
|
8834
|
+
entity.dispose();
|
|
8835
|
+
}
|
|
8836
|
+
}
|
|
8837
|
+
/** Entity models drawn for this block instead of its block model; they are scene children, unlike the block. */
|
|
8838
|
+
get blockEntities() {
|
|
8839
|
+
return this._entities;
|
|
8840
|
+
}
|
|
8841
|
+
/**
|
|
8842
|
+
* Draws the block through the dataset's block-entity index. Returns false, leaving nothing behind,
|
|
8843
|
+
* when the block is not listed or one of its models cannot be loaded.
|
|
8844
|
+
*/
|
|
8845
|
+
async createBlockEntities() {
|
|
8846
|
+
const key = this.blockState.key;
|
|
8847
|
+
if (!key || this.options.displayPosition) return false;
|
|
8848
|
+
const generation = this._entityGeneration;
|
|
8849
|
+
const created = [];
|
|
8850
|
+
let resolved;
|
|
8851
|
+
try {
|
|
8852
|
+
resolved = BlockEntities.resolve(await BlockEntities.getIndex(key.root), key.toNamespacedString(), this.state);
|
|
8853
|
+
if (!resolved) return false;
|
|
8854
|
+
for (const part of resolved.parts) {
|
|
8855
|
+
const [namespace, path] = part.model.includes(":") ? part.model.split(":") : [key.namespace, part.model];
|
|
8856
|
+
const texture = part.textureLocation === void 0 ? void 0 : AssetKey.parse("textures", part.textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
|
|
8857
|
+
if (texture) texture.root = key.root;
|
|
8858
|
+
const entity = await Entities.getEntity(new BasicAssetKey(namespace, path), texture, { layer: part.layer });
|
|
8859
|
+
if (!entity) throw new MineRenderError(`Missing entity model ${part.model}`);
|
|
8860
|
+
created.push(await this.scene.addEntity(entity, { wireframe: this.options.wireframe }));
|
|
8861
|
+
}
|
|
8862
|
+
} catch (error) {
|
|
8863
|
+
console.warn(`Could not draw block entity ${key.toNamespacedString()}, using its block model`, error);
|
|
8864
|
+
this.removeEntities(created);
|
|
8865
|
+
return false;
|
|
8866
|
+
}
|
|
8867
|
+
if (generation !== this._entityGeneration) {
|
|
8868
|
+
this.removeEntities(created);
|
|
8869
|
+
return true;
|
|
8870
|
+
}
|
|
8871
|
+
BlockEntities.matrix(resolved, this._entityPlacement);
|
|
8872
|
+
this._entities = created;
|
|
8873
|
+
this.placeEntities();
|
|
8874
|
+
return true;
|
|
8875
|
+
}
|
|
8876
|
+
placeEntities() {
|
|
8877
|
+
const matrix = new Matrix49().makeTranslation(this.position.x - 8, this.position.y - 8, this.position.z - 8).multiply(this._entityPlacement);
|
|
8878
|
+
for (const entity of this._entities) {
|
|
8879
|
+
matrix.decompose(entity.position, entity.quaternion, entity.scale);
|
|
8880
|
+
}
|
|
8881
|
+
}
|
|
8420
8882
|
get isOccluding() {
|
|
8421
8883
|
return this._models.some((model) => {
|
|
8422
8884
|
const object = isInstanceReference(model) ? model.instanceable : model;
|
|
@@ -8436,7 +8898,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
8436
8898
|
const scale = new Vector311();
|
|
8437
8899
|
this.getModelMatrix(model).decompose(position, rotation, scale);
|
|
8438
8900
|
if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector311(1, 1, 1)) > 1e-10) return 0;
|
|
8439
|
-
return ModelCulling.toLocalMask(worldMask, new
|
|
8901
|
+
return ModelCulling.toLocalMask(worldMask, new Euler8().setFromQuaternion(rotation));
|
|
8440
8902
|
}
|
|
8441
8903
|
async setCullMask(worldMask) {
|
|
8442
8904
|
worldMask &= 63;
|
|
@@ -8498,7 +8960,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
8498
8960
|
() => new FluidModelObject2(kind, surface.sample, this.blockState.key, this.options)
|
|
8499
8961
|
);
|
|
8500
8962
|
const previous = this._fluidModel;
|
|
8501
|
-
const matrix = previous ? this.getModelMatrix(previous) : new
|
|
8963
|
+
const matrix = previous ? this.getModelMatrix(previous) : new Matrix49().makeTranslation(...this.position.toArray());
|
|
8502
8964
|
if (isInstanceReference(replacement)) replacement.setMatrix(matrix);
|
|
8503
8965
|
else matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
|
|
8504
8966
|
this._models = this._models.filter((model) => model !== previous);
|
|
@@ -8528,13 +8990,20 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
8528
8990
|
await this.updateFluid(this._fluidSampler);
|
|
8529
8991
|
return;
|
|
8530
8992
|
}
|
|
8993
|
+
const hasEntities = await this.createBlockEntities();
|
|
8531
8994
|
const variantsToCreate = await this.mapStateToVariant(this.state);
|
|
8532
8995
|
this._variants = variantsToCreate;
|
|
8533
8996
|
for (let blockStateVariant of variantsToCreate) {
|
|
8997
|
+
if (hasEntities && !await this.hasGeometry(blockStateVariant)) continue;
|
|
8534
8998
|
this._models.push(await this.createVariant(blockStateVariant));
|
|
8535
8999
|
}
|
|
8536
9000
|
await this.updateFluid(this._fluidSampler);
|
|
8537
9001
|
}
|
|
9002
|
+
async hasGeometry(variant) {
|
|
9003
|
+
const modelKey = AssetKey.parse("models", variant.model);
|
|
9004
|
+
modelKey.root = this.blockState.key?.root;
|
|
9005
|
+
return !!(await Models.getMerged(modelKey))?.elements?.length;
|
|
9006
|
+
}
|
|
8538
9007
|
getSingleVariant(variants) {
|
|
8539
9008
|
return BlockStateResolver.choose(variants);
|
|
8540
9009
|
}
|
|
@@ -8629,7 +9098,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
8629
9098
|
setPositionRotationScaleAt(index, position, rotation, scale) {
|
|
8630
9099
|
super.setPositionRotationScaleAt(index, position, rotation, scale);
|
|
8631
9100
|
}
|
|
8632
|
-
getMatrixAt(index, matrix = new
|
|
9101
|
+
getMatrixAt(index, matrix = new Matrix49()) {
|
|
8633
9102
|
if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
|
|
8634
9103
|
const child = this._models[0];
|
|
8635
9104
|
if (child && isModelObject(child)) {
|
|
@@ -8654,6 +9123,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
8654
9123
|
for (let model of this._models) {
|
|
8655
9124
|
model.setPosition(position);
|
|
8656
9125
|
}
|
|
9126
|
+
this.placeEntities();
|
|
8657
9127
|
this.notifyDirty();
|
|
8658
9128
|
}
|
|
8659
9129
|
//TODO: should override rotation + scale methods
|
|
@@ -13191,7 +13661,7 @@ init_CubeFace();
|
|
|
13191
13661
|
init_AssetKey();
|
|
13192
13662
|
init_Models();
|
|
13193
13663
|
init_CubeFace();
|
|
13194
|
-
import { Matrix4 as
|
|
13664
|
+
import { Matrix4 as Matrix410, Vector3 as Vector314 } from "three";
|
|
13195
13665
|
init_ModelCulling();
|
|
13196
13666
|
init_ModelObject();
|
|
13197
13667
|
init_UVMapper();
|
|
@@ -13254,7 +13724,7 @@ var SectionModels = class {
|
|
|
13254
13724
|
});
|
|
13255
13725
|
await object.init();
|
|
13256
13726
|
const geometry = object.children[0].geometry;
|
|
13257
|
-
geometry.applyMatrix4(new
|
|
13727
|
+
geometry.applyMatrix4(new Matrix410().makeRotationFromEuler(rotation));
|
|
13258
13728
|
object.clear();
|
|
13259
13729
|
const cullFaces = CUBE_FACES.map((face) => {
|
|
13260
13730
|
const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
|
|
@@ -13666,7 +14136,8 @@ var Chunk = class _Chunk {
|
|
|
13666
14136
|
this.data.set(index, void 0);
|
|
13667
14137
|
return void 0;
|
|
13668
14138
|
}
|
|
13669
|
-
const
|
|
14139
|
+
const perBlock = !this.sectionModels || getFluidKind(blockState.key, stored.properties) || blockState.key && BlockEntities.entry(await BlockEntities.getIndex(blockState.key.root), blockState.key.toNamespacedString());
|
|
14140
|
+
const template = perBlock ? void 0 : await this.sectionModels.get(blockState, stored.properties);
|
|
13670
14141
|
if (template) {
|
|
13671
14142
|
this.sectionBlocks.set(index, { index, template, cullMask: 0 });
|
|
13672
14143
|
this.meshDirty = true;
|
|
@@ -13775,6 +14246,7 @@ export {
|
|
|
13775
14246
|
BUILTIN_GENERATED,
|
|
13776
14247
|
BasicAssetKey,
|
|
13777
14248
|
BatchedExecutor,
|
|
14249
|
+
BlockEntities,
|
|
13778
14250
|
BlockObject,
|
|
13779
14251
|
BlockStateResolver,
|
|
13780
14252
|
BlockStates,
|
|
@@ -13796,7 +14268,9 @@ export {
|
|
|
13796
14268
|
DefaultBlockStates,
|
|
13797
14269
|
DisplayPosition,
|
|
13798
14270
|
DisplayTransforms,
|
|
14271
|
+
ENTITY_ANIMATION_CHANNELS,
|
|
13799
14272
|
Entities,
|
|
14273
|
+
EntityAnimationPlayer,
|
|
13800
14274
|
EntityObject,
|
|
13801
14275
|
Env,
|
|
13802
14276
|
FluidModelObject,
|
|
@@ -13872,6 +14346,7 @@ export {
|
|
|
13872
14346
|
createCanvas2 as createCanvas,
|
|
13873
14347
|
createFluidGeometry,
|
|
13874
14348
|
createImage,
|
|
14349
|
+
entityAnimationTime,
|
|
13875
14350
|
estimateBytesUsed,
|
|
13876
14351
|
getBlockFluidState,
|
|
13877
14352
|
getFluidKind,
|
|
@@ -13904,6 +14379,8 @@ export {
|
|
|
13904
14379
|
mergeVertices,
|
|
13905
14380
|
prefix,
|
|
13906
14381
|
registerNodeEnv,
|
|
14382
|
+
sampleEntityAnimation,
|
|
14383
|
+
sampleEntityKeyframes,
|
|
13907
14384
|
sampleFluid,
|
|
13908
14385
|
serializeBoxGeometryKey,
|
|
13909
14386
|
serializeImageKey,
|