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/browser/index.mjs
CHANGED
|
@@ -256,7 +256,9 @@ var init_Caching = __esm({
|
|
|
256
256
|
this.defaultBlockStatesCache,
|
|
257
257
|
this.blockTintCache,
|
|
258
258
|
this.entityModelCache,
|
|
259
|
-
this.entityTextureCache
|
|
259
|
+
this.entityTextureCache,
|
|
260
|
+
this.entityAnimationCache,
|
|
261
|
+
this.blockEntityIndexCache
|
|
260
262
|
];
|
|
261
263
|
}
|
|
262
264
|
static clear() {
|
|
@@ -301,6 +303,8 @@ var init_Caching = __esm({
|
|
|
301
303
|
_Caching.blockTintCache = _Caching.createAssetCache();
|
|
302
304
|
_Caching.entityModelCache = _Caching.createAssetCache();
|
|
303
305
|
_Caching.entityTextureCache = _Caching.createAssetCache();
|
|
306
|
+
_Caching.entityAnimationCache = _Caching.createAssetCache();
|
|
307
|
+
_Caching.blockEntityIndexCache = _Caching.createAssetCache();
|
|
304
308
|
Caching = _Caching;
|
|
305
309
|
}
|
|
306
310
|
});
|
|
@@ -799,7 +803,7 @@ var init_Textures = __esm({
|
|
|
799
803
|
});
|
|
800
804
|
|
|
801
805
|
// src/Materials.ts
|
|
802
|
-
import { Color, DoubleSide, FrontSide, MeshBasicMaterial, MeshStandardMaterial, ShaderChunk, ShaderMaterial } from "three";
|
|
806
|
+
import { Color, CustomBlending, DoubleSide, OneFactor, RepeatWrapping, FrontSide, MeshBasicMaterial, MeshStandardMaterial, ShaderChunk, ShaderMaterial, ZeroFactor } from "three";
|
|
803
807
|
var _Materials, Materials;
|
|
804
808
|
var init_Materials = __esm({
|
|
805
809
|
"src/Materials.ts"() {
|
|
@@ -838,6 +842,71 @@ var init_Materials = __esm({
|
|
|
838
842
|
alphaTest: 0.5
|
|
839
843
|
});
|
|
840
844
|
}
|
|
845
|
+
/** Whether vanilla's render type for the mode culls back faces. */
|
|
846
|
+
static entityModeCulls(mode = "cutout") {
|
|
847
|
+
return mode === "cutout_cull" || mode === "solid" || mode === "eyes" || mode === "water_mask";
|
|
848
|
+
}
|
|
849
|
+
/** UV offset per tick of entity age for the scrolling modes, as vanilla's texture matrix applies it. */
|
|
850
|
+
static entityModeScroll(mode = "cutout") {
|
|
851
|
+
if (mode === "energy_swirl") return [0.01, 0.01];
|
|
852
|
+
if (mode === "breeze_wind") return [0.02, 0];
|
|
853
|
+
return void 0;
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Entity material for one of vanilla's render types. Entities are unlit here, so the lit and full-bright modes
|
|
857
|
+
* differ only in blending and depth state. Culling is not a material property: {@link entityModeCulls} decides
|
|
858
|
+
* whether the geometry gets inward faces.
|
|
859
|
+
*/
|
|
860
|
+
static createEntityCanvasMaterial(canvas, mode = "cutout", tint) {
|
|
861
|
+
const material = _Materials.createBasicCanvasMaterial(canvas);
|
|
862
|
+
switch (mode) {
|
|
863
|
+
case "cutout":
|
|
864
|
+
case "cutout_cull":
|
|
865
|
+
break;
|
|
866
|
+
case "cutout_z_offset":
|
|
867
|
+
material.polygonOffset = true;
|
|
868
|
+
material.polygonOffsetFactor = -1;
|
|
869
|
+
material.polygonOffsetUnits = -10;
|
|
870
|
+
break;
|
|
871
|
+
case "solid":
|
|
872
|
+
material.alphaTest = 0;
|
|
873
|
+
break;
|
|
874
|
+
case "translucent":
|
|
875
|
+
case "breeze_wind":
|
|
876
|
+
material.transparent = true;
|
|
877
|
+
material.alphaTest = 0.1;
|
|
878
|
+
break;
|
|
879
|
+
case "translucent_emissive":
|
|
880
|
+
material.transparent = true;
|
|
881
|
+
material.alphaTest = 0.1;
|
|
882
|
+
material.depthWrite = false;
|
|
883
|
+
break;
|
|
884
|
+
case "eyes":
|
|
885
|
+
material.transparent = true;
|
|
886
|
+
material.alphaTest = 0;
|
|
887
|
+
material.depthWrite = false;
|
|
888
|
+
break;
|
|
889
|
+
case "energy_swirl":
|
|
890
|
+
material.transparent = true;
|
|
891
|
+
material.alphaTest = 0.1;
|
|
892
|
+
material.blending = CustomBlending;
|
|
893
|
+
material.blendSrc = OneFactor;
|
|
894
|
+
material.blendDst = OneFactor;
|
|
895
|
+
material.blendSrcAlpha = ZeroFactor;
|
|
896
|
+
material.blendDstAlpha = OneFactor;
|
|
897
|
+
material.color.set(8421504);
|
|
898
|
+
break;
|
|
899
|
+
case "water_mask":
|
|
900
|
+
material.alphaTest = 0;
|
|
901
|
+
material.colorWrite = false;
|
|
902
|
+
break;
|
|
903
|
+
}
|
|
904
|
+
if (_Materials.entityModeScroll(mode)) {
|
|
905
|
+
material.map.wrapS = material.map.wrapT = RepeatWrapping;
|
|
906
|
+
}
|
|
907
|
+
if (tint !== void 0) material.color.multiply(new Color(tint));
|
|
908
|
+
return material;
|
|
909
|
+
}
|
|
841
910
|
static createGuiCanvasMaterial(canvas) {
|
|
842
911
|
const material = new MeshBasicMaterial({
|
|
843
912
|
map: Textures.createCanvasTexture(canvas),
|
|
@@ -3014,7 +3083,7 @@ var init_InstanceReference = __esm({
|
|
|
3014
3083
|
});
|
|
3015
3084
|
|
|
3016
3085
|
// src/renderer/SceneObject.ts
|
|
3017
|
-
import { Color as Color2, Euler as Euler3, InstancedBufferAttribute, InstancedMesh, MathUtils, Matrix4 as
|
|
3086
|
+
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";
|
|
3018
3087
|
function isSceneObject(obj) {
|
|
3019
3088
|
return obj.isSceneObject;
|
|
3020
3089
|
}
|
|
@@ -3222,7 +3291,7 @@ var init_SceneObject = __esm({
|
|
|
3222
3291
|
mesh.instanceColor.needsUpdate = true;
|
|
3223
3292
|
}
|
|
3224
3293
|
if (this._scene) this._scene.stats.instanceCount++;
|
|
3225
|
-
this.setMatrixAt(index, new
|
|
3294
|
+
this.setMatrixAt(index, new Matrix44());
|
|
3226
3295
|
return reference;
|
|
3227
3296
|
}
|
|
3228
3297
|
/** Returns the live reference for a raycast hit on this object's instance mesh. */
|
|
@@ -3235,7 +3304,7 @@ var init_SceneObject = __esm({
|
|
|
3235
3304
|
removeInstanceAt(index) {
|
|
3236
3305
|
if (!this.instanceReferences.has(index)) return;
|
|
3237
3306
|
const mesh = this.instanceMesh;
|
|
3238
|
-
this.setMatrixAt(index, new
|
|
3307
|
+
this.setMatrixAt(index, new Matrix44().makeScale(0, 0, 0));
|
|
3239
3308
|
this.instanceReferences.delete(index);
|
|
3240
3309
|
this.freeInstanceIndices.push(index);
|
|
3241
3310
|
this._instanceCounter = this.instanceReferences.size;
|
|
@@ -3265,7 +3334,7 @@ var init_SceneObject = __esm({
|
|
|
3265
3334
|
}
|
|
3266
3335
|
//</editor-fold>
|
|
3267
3336
|
//<editor-fold desc="TRANSFORMATION">
|
|
3268
|
-
getMatrixAt(index, matrix = new
|
|
3337
|
+
getMatrixAt(index, matrix = new Matrix44()) {
|
|
3269
3338
|
if (!this.instanceReferences.has(index)) throw new MineRenderError("Instance is not active");
|
|
3270
3339
|
this.instanceMesh.getMatrixAt(index, matrix);
|
|
3271
3340
|
return matrix;
|
|
@@ -3284,7 +3353,7 @@ var init_SceneObject = __esm({
|
|
|
3284
3353
|
const oldPosition = new Vector35();
|
|
3285
3354
|
const oldRotation = new Quaternion3();
|
|
3286
3355
|
const oldScale = new Vector35();
|
|
3287
|
-
const matrix = new
|
|
3356
|
+
const matrix = new Matrix44();
|
|
3288
3357
|
if (!scale || !rotation || !position) {
|
|
3289
3358
|
this.getMatrixAt(index, matrix).decompose(oldPosition, oldRotation, oldScale);
|
|
3290
3359
|
}
|
|
@@ -4039,7 +4108,7 @@ var init_ModelCulling = __esm({
|
|
|
4039
4108
|
});
|
|
4040
4109
|
|
|
4041
4110
|
// src/model/scene/ModelObject.ts
|
|
4042
|
-
import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as
|
|
4111
|
+
import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color8, Euler as Euler6, Matrix4 as Matrix48 } from "three";
|
|
4043
4112
|
function isModelObject(obj) {
|
|
4044
4113
|
return obj.isModelObject;
|
|
4045
4114
|
}
|
|
@@ -4102,7 +4171,7 @@ var init_ModelObject = __esm({
|
|
|
4102
4171
|
elGeo.clearGroups();
|
|
4103
4172
|
}
|
|
4104
4173
|
if (this.options.uvLockRotation) {
|
|
4105
|
-
UVMapper.lockUvs(elGeo, el.faces, this.atlas, new
|
|
4174
|
+
UVMapper.lockUvs(elGeo, el.faces, this.atlas, new Euler6(...this.options.uvLockRotation));
|
|
4106
4175
|
}
|
|
4107
4176
|
if (this.options.tints) {
|
|
4108
4177
|
const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
|
|
@@ -4111,19 +4180,19 @@ var init_ModelObject = __esm({
|
|
|
4111
4180
|
if (tintIndex === void 0 || tintIndex < 0) continue;
|
|
4112
4181
|
const tint = this.options.tints[tintIndex];
|
|
4113
4182
|
if (tint === void 0) continue;
|
|
4114
|
-
const color = new
|
|
4183
|
+
const color = new Color8(tint);
|
|
4115
4184
|
for (let vertex = 0; vertex < 4; vertex++) {
|
|
4116
4185
|
color.toArray(colors, (faceIndex * 4 + vertex) * 3);
|
|
4117
4186
|
}
|
|
4118
4187
|
}
|
|
4119
4188
|
elGeo.setAttribute("color", new BufferAttribute5(colors, 3));
|
|
4120
4189
|
}
|
|
4121
|
-
elGeo.applyMatrix4(new
|
|
4122
|
-
elGeo.applyMatrix4(new
|
|
4190
|
+
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));
|
|
4191
|
+
elGeo.applyMatrix4(new Matrix48().makeTranslation(el.from[0], el.from[1], el.from[2]));
|
|
4123
4192
|
if (el.rotation) {
|
|
4124
4193
|
applyElementRotation(el.rotation, elGeo);
|
|
4125
4194
|
}
|
|
4126
|
-
elGeo.applyMatrix4(new
|
|
4195
|
+
elGeo.applyMatrix4(new Matrix48().makeTranslation(-8, -8, -8));
|
|
4127
4196
|
if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
|
|
4128
4197
|
if (this.options.mergeMeshes) {
|
|
4129
4198
|
allGeos.push(elGeo);
|
|
@@ -4377,7 +4446,7 @@ __export(FluidModelObject_exports, {
|
|
|
4377
4446
|
FluidModelObject: () => FluidModelObject,
|
|
4378
4447
|
sampleFluid: () => sampleFluid
|
|
4379
4448
|
});
|
|
4380
|
-
import { BufferAttribute as BufferAttribute6, Color as
|
|
4449
|
+
import { BufferAttribute as BufferAttribute6, Color as Color9, DoubleSide as DoubleSide3 } from "three";
|
|
4381
4450
|
function sampleFluid(kind, sample) {
|
|
4382
4451
|
const cells = [];
|
|
4383
4452
|
const key = [];
|
|
@@ -4428,7 +4497,7 @@ var init_FluidModelObject = __esm({
|
|
|
4428
4497
|
}
|
|
4429
4498
|
}
|
|
4430
4499
|
geometry.clearGroups();
|
|
4431
|
-
const color = new
|
|
4500
|
+
const color = new Color9(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
|
|
4432
4501
|
const colors = new Float32Array(geometry.getAttribute("position").count * 3);
|
|
4433
4502
|
for (let i = 0; i < colors.length; i += 3) color.toArray(colors, i);
|
|
4434
4503
|
geometry.setAttribute("color", new BufferAttribute6(colors, 3));
|
|
@@ -4732,6 +4801,59 @@ function shutdown() {
|
|
|
4732
4801
|
init_AssetKey();
|
|
4733
4802
|
init_AssetLoader();
|
|
4734
4803
|
init_Assets();
|
|
4804
|
+
|
|
4805
|
+
// src/assets/BlockEntities.ts
|
|
4806
|
+
init_AssetKey();
|
|
4807
|
+
init_AssetLoader();
|
|
4808
|
+
init_source();
|
|
4809
|
+
init_Caching();
|
|
4810
|
+
import { Matrix4 as Matrix43 } from "three";
|
|
4811
|
+
var BlockEntities = class {
|
|
4812
|
+
/**
|
|
4813
|
+
* Loads the block index of a version. Versions and sources without one yield an empty index, and so does
|
|
4814
|
+
* a failed load: the index is optional, and blocks must not retry or fail with it one by one. The empty
|
|
4815
|
+
* result is cached like any other; `Caching.clear()` or `AssetLoader.setVersion()` forces a new attempt.
|
|
4816
|
+
*/
|
|
4817
|
+
static async getIndex(root) {
|
|
4818
|
+
const key = new AssetKey("entity-models", "blocks", void 0, void 0, void 0, ".json", root);
|
|
4819
|
+
key.rootType = void 0;
|
|
4820
|
+
const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {
|
|
4821
|
+
try {
|
|
4822
|
+
return await AssetLoader.get(key, "json" /* JSON */) ?? {};
|
|
4823
|
+
} catch (error) {
|
|
4824
|
+
console.warn("Could not load the block entity index; block entities are drawn as plain block models", error);
|
|
4825
|
+
return {};
|
|
4826
|
+
}
|
|
4827
|
+
});
|
|
4828
|
+
return index ?? {};
|
|
4829
|
+
}
|
|
4830
|
+
/** The index entry of a block ID such as `minecraft:chest`. */
|
|
4831
|
+
static entry(index, block) {
|
|
4832
|
+
const entry = Object.prototype.hasOwnProperty.call(index, block) ? index[block] : void 0;
|
|
4833
|
+
return Array.isArray(entry?.parts) ? entry : void 0;
|
|
4834
|
+
}
|
|
4835
|
+
/** Selects the parts and placement for a block ID such as `minecraft:chest`; undefined when nothing is drawn. */
|
|
4836
|
+
static resolve(index, block, state = {}) {
|
|
4837
|
+
const entry = this.entry(index, block);
|
|
4838
|
+
if (!entry) return void 0;
|
|
4839
|
+
const value = (property) => String(state[property]).toLowerCase();
|
|
4840
|
+
const parts = entry.parts.filter((part) => Object.entries(part.when ?? {}).every(([property, values]) => String(values).split("|").includes(value(property))));
|
|
4841
|
+
if (!parts.length) return void 0;
|
|
4842
|
+
let rotation = 0;
|
|
4843
|
+
if (entry.rotation) {
|
|
4844
|
+
const selected = value(entry.rotation.property);
|
|
4845
|
+
rotation = "degrees" in entry.rotation ? entry.rotation.degrees[selected] : Number(selected) * entry.rotation.step;
|
|
4846
|
+
if (!Number.isFinite(rotation)) rotation = 0;
|
|
4847
|
+
}
|
|
4848
|
+
return { parts, rotation, translation: entry.translation ?? [0, 0, 0] };
|
|
4849
|
+
}
|
|
4850
|
+
/** Placement in block space (0..16 per axis), applied on top of the model's own transform. */
|
|
4851
|
+
static matrix(resolved, matrix = new Matrix43()) {
|
|
4852
|
+
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));
|
|
4853
|
+
}
|
|
4854
|
+
};
|
|
4855
|
+
|
|
4856
|
+
// src/assets/index.ts
|
|
4735
4857
|
init_BlockStates();
|
|
4736
4858
|
|
|
4737
4859
|
// src/assets/Entities.ts
|
|
@@ -4763,32 +4885,53 @@ var Entities = class {
|
|
|
4763
4885
|
static async getLayerList(modelKey) {
|
|
4764
4886
|
return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
|
|
4765
4887
|
}
|
|
4888
|
+
/** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */
|
|
4889
|
+
static async getPassList(modelKey) {
|
|
4890
|
+
return (await this.getModelFile(modelKey))?.passes ?? [];
|
|
4891
|
+
}
|
|
4766
4892
|
static async getEntity(modelKey, textureKey, options) {
|
|
4767
4893
|
const model = await this.getModelFile(modelKey);
|
|
4768
4894
|
if (!model) return void 0;
|
|
4769
|
-
const
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4895
|
+
const passes = options?.layers || options?.layer !== void 0 ? [] : (model.passes ?? []).filter((pass) => pass.when === void 0 || options?.when?.includes(pass.when));
|
|
4896
|
+
const draws = [...new Set(options?.layers ?? [options?.layer ?? "main"])].map((layer) => ({ layer }));
|
|
4897
|
+
if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
|
|
4898
|
+
draws.push(...passes);
|
|
4899
|
+
const names = [];
|
|
4900
|
+
const selected = draws.map((pass) => {
|
|
4901
|
+
const layer = model.layers[pass.layer];
|
|
4773
4902
|
if (!layer) {
|
|
4774
|
-
throw new MineRenderError(`Entity ${model.id} has no layer "${
|
|
4903
|
+
throw new MineRenderError(`Entity ${model.id} has no layer "${pass.layer}". Available layers: ${Object.keys(model.layers).join(", ")}`);
|
|
4775
4904
|
}
|
|
4776
|
-
|
|
4905
|
+
let name = pass.layer;
|
|
4906
|
+
for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;
|
|
4907
|
+
names.push(name);
|
|
4908
|
+
return { name, layer, pass };
|
|
4777
4909
|
});
|
|
4778
|
-
const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer }, index) => {
|
|
4910
|
+
const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {
|
|
4779
4911
|
const override = options?.textures?.[name] ?? (index === 0 ? textureKey : void 0);
|
|
4912
|
+
const textureLocation = pass.textureLocation ?? layer.textureLocation;
|
|
4780
4913
|
let texture;
|
|
4781
4914
|
if (override) {
|
|
4782
4915
|
const path = isAssetKey(override) ? override.getFullPath() : override.path;
|
|
4783
4916
|
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);
|
|
4784
|
-
} else if (
|
|
4785
|
-
texture = AssetKey.parse("textures",
|
|
4917
|
+
} else if (textureLocation !== void 0) {
|
|
4918
|
+
texture = AssetKey.parse("textures", textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
|
|
4786
4919
|
} else {
|
|
4787
4920
|
texture = await this.resolveTexture(modelKey);
|
|
4788
4921
|
}
|
|
4789
|
-
|
|
4922
|
+
const render = pass.render ?? layer.render;
|
|
4923
|
+
return [name, { key: override ?? modelKey, texture, layer, ...render && { render }, ...pass.tint && { tint: pass.tint } }];
|
|
4790
4924
|
})));
|
|
4791
|
-
return { ...layers[names[0]], id: model.id, layers };
|
|
4925
|
+
return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
|
|
4926
|
+
}
|
|
4927
|
+
/**
|
|
4928
|
+
* Vanilla's keyframe animations of a model by name, or undefined when the model or the selected version has none.
|
|
4929
|
+
*/
|
|
4930
|
+
static async getAnimations(modelKey) {
|
|
4931
|
+
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
4932
|
+
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json");
|
|
4933
|
+
const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
4934
|
+
return file?.animations;
|
|
4792
4935
|
}
|
|
4793
4936
|
static async resolveTexture(modelKey) {
|
|
4794
4937
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
@@ -4866,15 +5009,129 @@ function trimCanvas(source) {
|
|
|
4866
5009
|
return canvas;
|
|
4867
5010
|
}
|
|
4868
5011
|
|
|
5012
|
+
// src/entity/EntityAnimation.ts
|
|
5013
|
+
var ENTITY_ANIMATION_CHANNELS = ["position", "rotation", "scale"];
|
|
5014
|
+
function catmullRom(delta, p0, p1, p22, p32) {
|
|
5015
|
+
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);
|
|
5016
|
+
}
|
|
5017
|
+
function sampleEntityKeyframes(keyframes, time) {
|
|
5018
|
+
if (keyframes.length === 0) return [0, 0, 0];
|
|
5019
|
+
let low = 0, high = keyframes.length;
|
|
5020
|
+
while (low < high) {
|
|
5021
|
+
const middle = low + high >>> 1;
|
|
5022
|
+
if (time <= keyframes[middle].time) high = middle;
|
|
5023
|
+
else low = middle + 1;
|
|
5024
|
+
}
|
|
5025
|
+
const a = Math.max(0, low - 1);
|
|
5026
|
+
const b = Math.min(keyframes.length - 1, a + 1);
|
|
5027
|
+
const from = keyframes[a];
|
|
5028
|
+
const to = keyframes[b];
|
|
5029
|
+
const delta = a === b ? 0 : Math.min(1, Math.max(0, (time - from.time) / (to.time - from.time)));
|
|
5030
|
+
if (to.interpolation === "catmullrom") {
|
|
5031
|
+
const before = keyframes[Math.max(0, a - 1)].value;
|
|
5032
|
+
const after = keyframes[Math.min(keyframes.length - 1, b + 1)].value;
|
|
5033
|
+
return [0, 1, 2].map((i) => catmullRom(delta, before[i], from.value[i], to.value[i], after[i]));
|
|
5034
|
+
}
|
|
5035
|
+
const target = to.pre ?? to.value;
|
|
5036
|
+
return [0, 1, 2].map((i) => from.value[i] + (target[i] - from.value[i]) * delta);
|
|
5037
|
+
}
|
|
5038
|
+
function entityAnimationTime(animation, time, loop = animation.loop) {
|
|
5039
|
+
return loop && animation.length > 0 ? time % animation.length : time;
|
|
5040
|
+
}
|
|
5041
|
+
function sampleEntityAnimation(animation, time, loop = animation.loop) {
|
|
5042
|
+
const elapsed = entityAnimationTime(animation, time, loop);
|
|
5043
|
+
const pose = {};
|
|
5044
|
+
for (const [name, bone] of Object.entries(animation.bones)) {
|
|
5045
|
+
const sampled = pose[name] = {};
|
|
5046
|
+
for (const channel of ENTITY_ANIMATION_CHANNELS) {
|
|
5047
|
+
const keyframes = bone[channel];
|
|
5048
|
+
if (keyframes?.length) sampled[channel] = sampleEntityKeyframes(keyframes, elapsed);
|
|
5049
|
+
}
|
|
5050
|
+
}
|
|
5051
|
+
return pose;
|
|
5052
|
+
}
|
|
5053
|
+
|
|
5054
|
+
// src/entity/scene/EntityAnimationPlayer.ts
|
|
5055
|
+
var ZERO = [0, 0, 0];
|
|
5056
|
+
var EntityAnimationPlayer = class {
|
|
5057
|
+
constructor() {
|
|
5058
|
+
this.parts = [];
|
|
5059
|
+
this._time = 0;
|
|
5060
|
+
this.loop = false;
|
|
5061
|
+
this.speed = 1;
|
|
5062
|
+
}
|
|
5063
|
+
get animation() {
|
|
5064
|
+
return this._animation;
|
|
5065
|
+
}
|
|
5066
|
+
get time() {
|
|
5067
|
+
return this._time;
|
|
5068
|
+
}
|
|
5069
|
+
/**
|
|
5070
|
+
* Starts an animation on the named parts below each layer root. The current pose of a part becomes its default;
|
|
5071
|
+
* bones without a matching part are skipped.
|
|
5072
|
+
*/
|
|
5073
|
+
play(layers, animation, options = {}) {
|
|
5074
|
+
this.stop();
|
|
5075
|
+
this._animation = animation;
|
|
5076
|
+
this._time = options.time ?? 0;
|
|
5077
|
+
this.loop = options.loop ?? animation.loop;
|
|
5078
|
+
this.speed = options.speed ?? 1;
|
|
5079
|
+
for (const layer of layers) {
|
|
5080
|
+
for (const bone of Object.keys(animation.bones)) {
|
|
5081
|
+
const object = layer.getObjectByName(`group:${bone}`);
|
|
5082
|
+
if (!object) continue;
|
|
5083
|
+
this.parts.push({ bone, object, position: object.position.clone(), rotation: object.rotation.clone(), scale: object.scale.clone() });
|
|
5084
|
+
}
|
|
5085
|
+
}
|
|
5086
|
+
this.apply();
|
|
5087
|
+
}
|
|
5088
|
+
/** Restores the default poses. Returns whether an animation was active. */
|
|
5089
|
+
stop() {
|
|
5090
|
+
if (!this._animation) return false;
|
|
5091
|
+
for (const part of this.parts) {
|
|
5092
|
+
part.object.position.copy(part.position);
|
|
5093
|
+
part.object.rotation.copy(part.rotation);
|
|
5094
|
+
part.object.scale.copy(part.scale);
|
|
5095
|
+
}
|
|
5096
|
+
this.clear();
|
|
5097
|
+
return true;
|
|
5098
|
+
}
|
|
5099
|
+
/** Forgets the animation without touching the parts, for parts that no longer exist. */
|
|
5100
|
+
clear() {
|
|
5101
|
+
this.parts = [];
|
|
5102
|
+
this._animation = void 0;
|
|
5103
|
+
this._time = 0;
|
|
5104
|
+
}
|
|
5105
|
+
setTime(seconds) {
|
|
5106
|
+
if (!this._animation) return false;
|
|
5107
|
+
this._time = seconds;
|
|
5108
|
+
this.apply();
|
|
5109
|
+
return true;
|
|
5110
|
+
}
|
|
5111
|
+
advance(deltaSeconds) {
|
|
5112
|
+
return this.setTime(this._time + deltaSeconds * this.speed);
|
|
5113
|
+
}
|
|
5114
|
+
apply() {
|
|
5115
|
+
const pose = sampleEntityAnimation(this._animation, this._time, this.loop);
|
|
5116
|
+
for (const part of this.parts) {
|
|
5117
|
+
const { position = ZERO, rotation = ZERO, scale = ZERO } = pose[part.bone];
|
|
5118
|
+
part.object.position.set(part.position.x + position[0], part.position.y + position[1], part.position.z + position[2]);
|
|
5119
|
+
part.object.rotation.set(part.rotation.x + rotation[0], part.rotation.y + rotation[1], part.rotation.z + rotation[2], part.rotation.order);
|
|
5120
|
+
part.object.scale.set(part.scale.x + scale[0], part.scale.y + scale[1], part.scale.z + scale[2]);
|
|
5121
|
+
}
|
|
5122
|
+
}
|
|
5123
|
+
};
|
|
5124
|
+
|
|
4869
5125
|
// src/entity/scene/EntityObject.ts
|
|
4870
5126
|
init_SceneObject();
|
|
4871
5127
|
init_Caching();
|
|
4872
5128
|
var import_ts_deepmerge4 = __toESM(require_dist());
|
|
5129
|
+
init_Ticker();
|
|
4873
5130
|
init_model();
|
|
4874
5131
|
init_ModelTextures();
|
|
4875
5132
|
init_AssetKey();
|
|
4876
5133
|
init_Materials();
|
|
4877
|
-
import { Object3D as Object3D3 } from "three";
|
|
5134
|
+
import { Color as Color3, Euler as Euler4, Matrix4 as Matrix45, Object3D as Object3D3 } from "three";
|
|
4878
5135
|
init_three();
|
|
4879
5136
|
var _EntityObject = class _EntityObject extends SceneObject {
|
|
4880
5137
|
constructor(entity, options) {
|
|
@@ -4882,6 +5139,11 @@ var _EntityObject = class _EntityObject extends SceneObject {
|
|
|
4882
5139
|
this.entity = entity;
|
|
4883
5140
|
this.isEntityObject = true;
|
|
4884
5141
|
this.meshesCreated = false;
|
|
5142
|
+
/** Scrolling materials are owned: their texture offset follows this entity's age. */
|
|
5143
|
+
this.scrollMaterials = [];
|
|
5144
|
+
/** Entity age in ticks, as vanilla's `ageInTicks`; drives the scrolling render modes. */
|
|
5145
|
+
this.age = 0;
|
|
5146
|
+
this.animationPlayer = new EntityAnimationPlayer();
|
|
4885
5147
|
this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
|
|
4886
5148
|
}
|
|
4887
5149
|
async init() {
|
|
@@ -4891,6 +5153,59 @@ var _EntityObject = class _EntityObject extends SceneObject {
|
|
|
4891
5153
|
dispose() {
|
|
4892
5154
|
super.dispose();
|
|
4893
5155
|
}
|
|
5156
|
+
disposeAndRemoveAllChildren() {
|
|
5157
|
+
this.clearScrollMaterials();
|
|
5158
|
+
this.animationPlayer.clear();
|
|
5159
|
+
super.disposeAndRemoveAllChildren();
|
|
5160
|
+
}
|
|
5161
|
+
clearScrollMaterials() {
|
|
5162
|
+
Ticker.remove(this.scrollTicker);
|
|
5163
|
+
this.scrollTicker = void 0;
|
|
5164
|
+
for (const { material } of this.scrollMaterials.splice(0)) {
|
|
5165
|
+
material.map?.dispose();
|
|
5166
|
+
material.dispose();
|
|
5167
|
+
}
|
|
5168
|
+
}
|
|
5169
|
+
/** Applies the entity age to the scrolling materials; the ticker calls this 20 times per second. */
|
|
5170
|
+
updateScroll() {
|
|
5171
|
+
for (const { offset, speed } of this.scrollMaterials) {
|
|
5172
|
+
offset.set(this.age * speed[0] % 1, 0 - this.age * speed[1] % 1);
|
|
5173
|
+
}
|
|
5174
|
+
this.notifyDirty();
|
|
5175
|
+
}
|
|
5176
|
+
//<editor-fold desc="ANIMATION">
|
|
5177
|
+
/** The animation started by {@link playAnimation}, until {@link stopAnimation} or disposal. */
|
|
5178
|
+
get animation() {
|
|
5179
|
+
return this.animationPlayer.animation;
|
|
5180
|
+
}
|
|
5181
|
+
/** Seconds since the animation started, before looping. */
|
|
5182
|
+
get animationTime() {
|
|
5183
|
+
return this.animationPlayer.time;
|
|
5184
|
+
}
|
|
5185
|
+
/**
|
|
5186
|
+
* Poses the object from a keyframe animation of {@link Entities.getAnimations}, replacing the current one.
|
|
5187
|
+
* Parts of every layer are matched by name and their current pose is the default the offsets add to.
|
|
5188
|
+
* The object owns no clock: call {@link advanceAnimation} per frame, or {@link setAnimationTime}.
|
|
5189
|
+
*/
|
|
5190
|
+
playAnimation(animation, options) {
|
|
5191
|
+
this.createMeshes();
|
|
5192
|
+
const layers = Object.keys(this.entityLayers).map((name) => this.getLayerGroup(name)).filter((layer) => !!layer);
|
|
5193
|
+
this.animationPlayer.play(layers, animation, options);
|
|
5194
|
+
this.notifyDirty();
|
|
5195
|
+
}
|
|
5196
|
+
/** Stops the animation and restores the default pose. */
|
|
5197
|
+
stopAnimation() {
|
|
5198
|
+
if (this.animationPlayer.stop()) this.notifyDirty();
|
|
5199
|
+
}
|
|
5200
|
+
/** Poses the object at an explicit time in seconds. Has no effect without an animation. */
|
|
5201
|
+
setAnimationTime(seconds) {
|
|
5202
|
+
if (this.animationPlayer.setTime(seconds)) this.notifyDirty();
|
|
5203
|
+
}
|
|
5204
|
+
/** Advances the animation by a frame delta in seconds, scaled by its speed. Has no effect without an animation. */
|
|
5205
|
+
advanceAnimation(deltaSeconds) {
|
|
5206
|
+
if (this.animationPlayer.advance(deltaSeconds)) this.notifyDirty();
|
|
5207
|
+
}
|
|
5208
|
+
//</editor-fold>
|
|
4894
5209
|
getLayerGroup(name) {
|
|
4895
5210
|
return super.getGroupByName(`layer:${name}`);
|
|
4896
5211
|
}
|
|
@@ -4921,16 +5236,29 @@ var _EntityObject = class _EntityObject extends SceneObject {
|
|
|
4921
5236
|
createMeshes(force = false) {
|
|
4922
5237
|
if (this.meshesCreated && !force) return;
|
|
4923
5238
|
const modelRoot = new Object3D3();
|
|
4924
|
-
|
|
5239
|
+
const transform = this.options.flip === void 0 ? this.entity.transform : void 0;
|
|
5240
|
+
if (transform) {
|
|
5241
|
+
for (const op of transform) {
|
|
5242
|
+
const matrix = new Matrix45();
|
|
5243
|
+
if ("scale" in op) matrix.makeScale(...op.scale);
|
|
5244
|
+
else if ("translate" in op) matrix.makeTranslation(...op.translate);
|
|
5245
|
+
else matrix.makeRotationFromEuler(new Euler4(...op.rotate, "ZYX"));
|
|
5246
|
+
modelRoot.matrix.multiply(matrix);
|
|
5247
|
+
}
|
|
5248
|
+
modelRoot.matrixAutoUpdate = false;
|
|
5249
|
+
} else if (this.options.flip ?? true) {
|
|
5250
|
+
modelRoot.scale.set(-1, -1, 1);
|
|
5251
|
+
}
|
|
4925
5252
|
this.add(modelRoot);
|
|
4926
5253
|
Object.entries(this.entityLayers).forEach(([name, layer], index) => {
|
|
4927
5254
|
const group = this.createGroup(`layer:${name}`);
|
|
4928
5255
|
modelRoot.add(group);
|
|
4929
|
-
|
|
5256
|
+
const inward = !Materials.entityModeCulls(layer.render ?? layer.layer.render);
|
|
5257
|
+
this.createPart("root", layer.layer.root, group, layer.layer.texture, Materials.MISSING_TEXTURE, index, inward);
|
|
4930
5258
|
});
|
|
4931
5259
|
this.meshesCreated = true;
|
|
4932
5260
|
}
|
|
4933
|
-
createPart(name, part, parent, textureSize, material, renderOrder) {
|
|
5261
|
+
createPart(name, part, parent, textureSize, material, renderOrder, inward = true) {
|
|
4934
5262
|
const anchor = this.createGroup(name);
|
|
4935
5263
|
anchor.position.fromArray(part.pose.offset);
|
|
4936
5264
|
anchor.rotation.set(...part.pose.rotation, "ZYX");
|
|
@@ -4949,7 +5277,7 @@ var _EntityObject = class _EntityObject extends SceneObject {
|
|
|
4949
5277
|
uv
|
|
4950
5278
|
).clone();
|
|
4951
5279
|
geometry.translate(cube.origin[0] + width / 2, cube.origin[1] + height / 2, cube.origin[2] + depth / 2);
|
|
4952
|
-
if (Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
|
|
5280
|
+
if (inward && Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
|
|
4953
5281
|
const index = Array.from(geometry.getIndex().array);
|
|
4954
5282
|
geometry.setIndex(index.concat(index.slice().reverse()));
|
|
4955
5283
|
}
|
|
@@ -4959,30 +5287,46 @@ var _EntityObject = class _EntityObject extends SceneObject {
|
|
|
4959
5287
|
if (this.options.wireframe) addWireframeToMesh(geometry, mesh);
|
|
4960
5288
|
}
|
|
4961
5289
|
for (const [childName, child] of Object.entries(part.children)) {
|
|
4962
|
-
this.createPart(childName, child, anchor, size, material, renderOrder);
|
|
5290
|
+
this.createPart(childName, child, anchor, size, material, renderOrder, inward);
|
|
4963
5291
|
}
|
|
4964
5292
|
}
|
|
4965
5293
|
async applyTextures() {
|
|
5294
|
+
this.clearScrollMaterials();
|
|
4966
5295
|
await Promise.all(Object.entries(this.entityLayers).map(async ([name, layer]) => {
|
|
5296
|
+
const mode = layer.render ?? layer.layer.render ?? "cutout";
|
|
5297
|
+
const tint = layer.tint === void 0 ? void 0 : this.options.tints?.[layer.tint];
|
|
5298
|
+
const scroll = Materials.entityModeScroll(mode);
|
|
4967
5299
|
const assetKeyStr = this.getTextureKey(layer).serialize();
|
|
4968
|
-
const keyStr = `entity:${assetKeyStr}`;
|
|
4969
|
-
let mat = Caching.materialCache.getIfPresent(keyStr);
|
|
5300
|
+
const keyStr = `entity:${mode}:${tint === void 0 ? "" : new Color3(tint).getHexString()}:${assetKeyStr}`;
|
|
5301
|
+
let mat = scroll ? void 0 : Caching.materialCache.getIfPresent(keyStr);
|
|
4970
5302
|
if (!mat) {
|
|
4971
5303
|
const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
|
|
4972
5304
|
const imageData = await this.loadTextures(layer);
|
|
4973
5305
|
if (!imageData) return;
|
|
4974
5306
|
const canvas = imageData.data.canvas;
|
|
4975
|
-
const createMaterial = () => Materials.
|
|
4976
|
-
mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
|
|
5307
|
+
const createMaterial = () => Materials.createEntityCanvasMaterial(canvas, mode, tint);
|
|
5308
|
+
mat = !scroll && cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
|
|
5309
|
+
if (scroll) {
|
|
5310
|
+
this.scrollMaterials.push({ material: mat, offset: mat.map.offset, speed: scroll });
|
|
5311
|
+
}
|
|
4977
5312
|
}
|
|
4978
5313
|
this.getLayerGroup(name)?.traverse((object) => {
|
|
4979
5314
|
if (isMesh(object)) object.material = mat;
|
|
4980
5315
|
});
|
|
4981
5316
|
}));
|
|
5317
|
+
if (!this.children.length) {
|
|
5318
|
+
this.clearScrollMaterials();
|
|
5319
|
+
} else if (this.scrollMaterials.length) {
|
|
5320
|
+
this.updateScroll();
|
|
5321
|
+
this.scrollTicker = Ticker.add(() => {
|
|
5322
|
+
this.age++;
|
|
5323
|
+
this.updateScroll();
|
|
5324
|
+
});
|
|
5325
|
+
}
|
|
4982
5326
|
this.notifyDirty();
|
|
4983
5327
|
}
|
|
4984
5328
|
};
|
|
4985
|
-
_EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS
|
|
5329
|
+
_EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS);
|
|
4986
5330
|
var EntityObject = _EntityObject;
|
|
4987
5331
|
function isEntityObject(obj) {
|
|
4988
5332
|
return obj.isEntityObject;
|
|
@@ -4992,11 +5336,11 @@ function isEntityObject(obj) {
|
|
|
4992
5336
|
init_MineRenderError();
|
|
4993
5337
|
|
|
4994
5338
|
// src/export/SceneExporter.ts
|
|
4995
|
-
import { ClampToEdgeWrapping as ClampToEdgeWrapping2, Color as
|
|
5339
|
+
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";
|
|
4996
5340
|
|
|
4997
5341
|
// ../../node_modules/three/examples/jsm/exporters/OBJExporter.js
|
|
4998
5342
|
import {
|
|
4999
|
-
Color as
|
|
5343
|
+
Color as Color4,
|
|
5000
5344
|
Matrix3,
|
|
5001
5345
|
Vector2 as Vector22,
|
|
5002
5346
|
Vector3 as Vector36
|
|
@@ -5008,7 +5352,7 @@ var OBJExporter = class {
|
|
|
5008
5352
|
let indexVertexUvs = 0;
|
|
5009
5353
|
let indexNormals = 0;
|
|
5010
5354
|
const vertex = new Vector36();
|
|
5011
|
-
const color = new
|
|
5355
|
+
const color = new Color4();
|
|
5012
5356
|
const normal = new Vector36();
|
|
5013
5357
|
const uv = new Vector22();
|
|
5014
5358
|
const face = [];
|
|
@@ -5139,7 +5483,7 @@ var OBJExporter = class {
|
|
|
5139
5483
|
import {
|
|
5140
5484
|
Matrix3 as Matrix32,
|
|
5141
5485
|
Vector3 as Vector37,
|
|
5142
|
-
Color as
|
|
5486
|
+
Color as Color5
|
|
5143
5487
|
} from "three";
|
|
5144
5488
|
var PLYExporter = class {
|
|
5145
5489
|
parse(object, onDone, options = {}) {
|
|
@@ -5197,7 +5541,7 @@ var PLYExporter = class {
|
|
|
5197
5541
|
includeIndices = false;
|
|
5198
5542
|
}
|
|
5199
5543
|
});
|
|
5200
|
-
const tempColor = new
|
|
5544
|
+
const tempColor = new Color5();
|
|
5201
5545
|
includeIndices = includeIndices && excludeAttributes.indexOf("index") === -1;
|
|
5202
5546
|
includeNormals = includeNormals && excludeAttributes.indexOf("normal") === -1;
|
|
5203
5547
|
includeColors = includeColors && excludeAttributes.indexOf("color") === -1;
|
|
@@ -5409,7 +5753,7 @@ property list uchar int vertex_index
|
|
|
5409
5753
|
import {
|
|
5410
5754
|
BufferAttribute as BufferAttribute3,
|
|
5411
5755
|
ClampToEdgeWrapping,
|
|
5412
|
-
Color as
|
|
5756
|
+
Color as Color6,
|
|
5413
5757
|
DoubleSide as DoubleSide2,
|
|
5414
5758
|
InterpolateDiscrete,
|
|
5415
5759
|
InterpolateLinear,
|
|
@@ -5418,14 +5762,14 @@ import {
|
|
|
5418
5762
|
LinearMipmapLinearFilter,
|
|
5419
5763
|
LinearMipmapNearestFilter,
|
|
5420
5764
|
MathUtils as MathUtils2,
|
|
5421
|
-
Matrix4 as
|
|
5765
|
+
Matrix4 as Matrix46,
|
|
5422
5766
|
MirroredRepeatWrapping,
|
|
5423
5767
|
NearestFilter as NearestFilter2,
|
|
5424
5768
|
NearestMipmapLinearFilter,
|
|
5425
5769
|
NearestMipmapNearestFilter,
|
|
5426
5770
|
PropertyBinding,
|
|
5427
5771
|
RGBAFormat as RGBAFormat2,
|
|
5428
|
-
RepeatWrapping,
|
|
5772
|
+
RepeatWrapping as RepeatWrapping2,
|
|
5429
5773
|
Scene as Scene3,
|
|
5430
5774
|
Source,
|
|
5431
5775
|
SRGBColorSpace as SRGBColorSpace4,
|
|
@@ -5643,7 +5987,7 @@ THREE_TO_WEBGL[LinearFilter] = WEBGL_CONSTANTS.LINEAR;
|
|
|
5643
5987
|
THREE_TO_WEBGL[LinearMipmapNearestFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST;
|
|
5644
5988
|
THREE_TO_WEBGL[LinearMipmapLinearFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR;
|
|
5645
5989
|
THREE_TO_WEBGL[ClampToEdgeWrapping] = WEBGL_CONSTANTS.CLAMP_TO_EDGE;
|
|
5646
|
-
THREE_TO_WEBGL[
|
|
5990
|
+
THREE_TO_WEBGL[RepeatWrapping2] = WEBGL_CONSTANTS.REPEAT;
|
|
5647
5991
|
THREE_TO_WEBGL[MirroredRepeatWrapping] = WEBGL_CONSTANTS.MIRRORED_REPEAT;
|
|
5648
5992
|
var PATH_PROPERTIES = {
|
|
5649
5993
|
scale: "scale",
|
|
@@ -5651,7 +5995,7 @@ var PATH_PROPERTIES = {
|
|
|
5651
5995
|
quaternion: "rotation",
|
|
5652
5996
|
morphTargetInfluences: "weights"
|
|
5653
5997
|
};
|
|
5654
|
-
var DEFAULT_SPECULAR_COLOR = new
|
|
5998
|
+
var DEFAULT_SPECULAR_COLOR = new Color6();
|
|
5655
5999
|
var GLB_HEADER_BYTES = 12;
|
|
5656
6000
|
var GLB_HEADER_MAGIC = 1179937895;
|
|
5657
6001
|
var GLB_VERSION = 2;
|
|
@@ -6708,7 +7052,7 @@ var GLTFWriter = class {
|
|
|
6708
7052
|
if (rootJoint === void 0) return null;
|
|
6709
7053
|
const joints = [];
|
|
6710
7054
|
const inverseBindMatrices = new Float32Array(skeleton.bones.length * 16);
|
|
6711
|
-
const temporaryBoneInverse = new
|
|
7055
|
+
const temporaryBoneInverse = new Matrix46();
|
|
6712
7056
|
for (let i = 0; i < skeleton.bones.length; ++i) {
|
|
6713
7057
|
joints.push(nodeMap.get(skeleton.bones[i]));
|
|
6714
7058
|
temporaryBoneInverse.copy(skeleton.boneInverses[i]);
|
|
@@ -7174,7 +7518,7 @@ var GLTFMeshGpuInstancing = class {
|
|
|
7174
7518
|
const translationAttr = new Float32Array(mesh.count * 3);
|
|
7175
7519
|
const rotationAttr = new Float32Array(mesh.count * 4);
|
|
7176
7520
|
const scaleAttr = new Float32Array(mesh.count * 3);
|
|
7177
|
-
const matrix = new
|
|
7521
|
+
const matrix = new Matrix46();
|
|
7178
7522
|
const position = new Vector38();
|
|
7179
7523
|
const quaternion = new Quaternion4();
|
|
7180
7524
|
const scale = new Vector38();
|
|
@@ -7348,7 +7692,7 @@ var SceneExporter = class {
|
|
|
7348
7692
|
}
|
|
7349
7693
|
};
|
|
7350
7694
|
function localMatrix(object) {
|
|
7351
|
-
return object.matrixAutoUpdate ? new
|
|
7695
|
+
return object.matrixAutoUpdate ? new Matrix47().compose(object.position, object.quaternion, object.scale) : object.matrix.clone();
|
|
7352
7696
|
}
|
|
7353
7697
|
function createSnapshot(root, gltf, bakeColors = false) {
|
|
7354
7698
|
const scene = new Scene4();
|
|
@@ -7433,7 +7777,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
|
|
|
7433
7777
|
const material = copyMaterial(sourceMaterial, geometry);
|
|
7434
7778
|
if (!sourceMaterial.vertexColors) geometry.deleteAttribute("color");
|
|
7435
7779
|
if (bakeColors || instanceColor) {
|
|
7436
|
-
const tint = (material.color ?? new
|
|
7780
|
+
const tint = (material.color ?? new Color7()).clone();
|
|
7437
7781
|
if (instanceColor) tint.multiply(instanceColor);
|
|
7438
7782
|
if (bakeColors) {
|
|
7439
7783
|
const original = geometry.getAttribute("color");
|
|
@@ -7460,9 +7804,9 @@ function createSnapshot(root, gltf, bakeColors = false) {
|
|
|
7460
7804
|
const instanced = mesh;
|
|
7461
7805
|
if (instanced.isInstancedMesh) {
|
|
7462
7806
|
for (let i = 0; i < instanced.count; i++) {
|
|
7463
|
-
const matrix = new
|
|
7807
|
+
const matrix = new Matrix47();
|
|
7464
7808
|
instanced.getMatrixAt(i, matrix);
|
|
7465
|
-
const color = instanced.instanceColor ? new
|
|
7809
|
+
const color = instanced.instanceColor ? new Color7().fromBufferAttribute(instanced.instanceColor, i) : void 0;
|
|
7466
7810
|
addMesh(mesh, world.clone().multiply(matrix), color);
|
|
7467
7811
|
}
|
|
7468
7812
|
} else {
|
|
@@ -7474,7 +7818,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
|
|
|
7474
7818
|
try {
|
|
7475
7819
|
const ancestors = [];
|
|
7476
7820
|
for (let parent = root.parent; parent; parent = parent.parent) ancestors.unshift(parent);
|
|
7477
|
-
const world = new
|
|
7821
|
+
const world = new Matrix47();
|
|
7478
7822
|
for (const ancestor of ancestors) {
|
|
7479
7823
|
if (!ancestor.visible) return { scene, dispose };
|
|
7480
7824
|
world.multiply(localMatrix(ancestor));
|
|
@@ -7541,11 +7885,69 @@ function copyDataTexture(source) {
|
|
|
7541
7885
|
}
|
|
7542
7886
|
|
|
7543
7887
|
// src/gui/GuiHelper.ts
|
|
7888
|
+
init_AssetKey();
|
|
7544
7889
|
var GuiHelper = class {
|
|
7545
7890
|
static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
|
|
7546
7891
|
const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
|
|
7547
7892
|
return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
|
|
7548
7893
|
}
|
|
7894
|
+
/** Creates crafting-table layers for ingredients and the result; stack counts are not drawn. */
|
|
7895
|
+
static recipe(recipe, options = {}) {
|
|
7896
|
+
const layers = [
|
|
7897
|
+
{ name: "background", texture: "minecraft:gui/container/crafting_table", crop: [0, 0, 176, 166] }
|
|
7898
|
+
];
|
|
7899
|
+
const itemKey = (ingredient) => {
|
|
7900
|
+
const item = typeof ingredient === "string" && !ingredient.startsWith("#") ? ingredient : typeof ingredient === "object" && "item" in ingredient ? ingredient.item : options.resolveIngredient?.(ingredient);
|
|
7901
|
+
if (isAssetKey(item)) return item;
|
|
7902
|
+
if (!item || item.startsWith("#")) {
|
|
7903
|
+
throw new Error(`Select a concrete item for recipe ingredient ${JSON.stringify(ingredient)}`);
|
|
7904
|
+
}
|
|
7905
|
+
const key = AssetKey.parse("models", item);
|
|
7906
|
+
return new AssetKey(key.namespace, key.getFullPath(), "models", "item");
|
|
7907
|
+
};
|
|
7908
|
+
const addIngredient = (ingredient, slot) => {
|
|
7909
|
+
layers.push({
|
|
7910
|
+
name: `ingredient-${slot}`,
|
|
7911
|
+
item: itemKey(ingredient),
|
|
7912
|
+
position: this.inventorySlot(slot, [30, 17], [18, 18], 3)
|
|
7913
|
+
});
|
|
7914
|
+
};
|
|
7915
|
+
switch (recipe.type) {
|
|
7916
|
+
case "minecraft:crafting_shaped":
|
|
7917
|
+
case "crafting_shaped": {
|
|
7918
|
+
const pattern = recipe.pattern;
|
|
7919
|
+
if (!pattern.length || pattern.length > 3 || !pattern[0].length || pattern[0].length > 3 || pattern.some((row) => row.length !== pattern[0].length)) {
|
|
7920
|
+
throw new Error("Crafting patterns must be rectangular, with 1\u20133 rows and columns");
|
|
7921
|
+
}
|
|
7922
|
+
const cells = pattern.flatMap((row, y) => row.split("").map((symbol, x) => ({ symbol, x, y }))).filter((cell) => cell.symbol !== " ");
|
|
7923
|
+
if (!cells.length) throw new Error("Crafting patterns must contain an ingredient");
|
|
7924
|
+
const minX = Math.min(...cells.map((cell) => cell.x)), maxX = Math.max(...cells.map((cell) => cell.x));
|
|
7925
|
+
const minY = Math.min(...cells.map((cell) => cell.y)), maxY = Math.max(...cells.map((cell) => cell.y));
|
|
7926
|
+
const offsetX = minX === maxX ? 1 : 0, offsetY = minY === maxY ? 1 : 0;
|
|
7927
|
+
for (const { symbol, x, y } of cells) {
|
|
7928
|
+
const ingredient = recipe.key[symbol];
|
|
7929
|
+
if (!ingredient) throw new Error(`Missing recipe ingredient for symbol ${JSON.stringify(symbol)}`);
|
|
7930
|
+
addIngredient(ingredient, (y - minY + offsetY) * 3 + x - minX + offsetX);
|
|
7931
|
+
}
|
|
7932
|
+
break;
|
|
7933
|
+
}
|
|
7934
|
+
case "minecraft:crafting_shapeless":
|
|
7935
|
+
case "crafting_shapeless":
|
|
7936
|
+
if (!recipe.ingredients.length || recipe.ingredients.length > 9) {
|
|
7937
|
+
throw new Error("Shapeless crafting recipes require 1\u20139 ingredients");
|
|
7938
|
+
}
|
|
7939
|
+
recipe.ingredients.forEach(addIngredient);
|
|
7940
|
+
break;
|
|
7941
|
+
default:
|
|
7942
|
+
throw new Error(`Unsupported crafting recipe type: ${recipe.type}`);
|
|
7943
|
+
}
|
|
7944
|
+
layers.push({
|
|
7945
|
+
name: "result",
|
|
7946
|
+
item: itemKey("id" in recipe.result ? recipe.result.id : recipe.result.item),
|
|
7947
|
+
position: [124, 35]
|
|
7948
|
+
});
|
|
7949
|
+
return layers;
|
|
7950
|
+
}
|
|
7549
7951
|
};
|
|
7550
7952
|
|
|
7551
7953
|
// src/gui/scene/GuiObject.ts
|
|
@@ -8133,7 +8535,7 @@ init_ModelMerger();
|
|
|
8133
8535
|
init_BlockStates();
|
|
8134
8536
|
init_MineRenderError();
|
|
8135
8537
|
init_util();
|
|
8136
|
-
import { Euler as
|
|
8538
|
+
import { Euler as Euler7 } from "three";
|
|
8137
8539
|
function matchesCondition(condition, state) {
|
|
8138
8540
|
return Object.entries(condition).every(([key, value]) => {
|
|
8139
8541
|
if (Array.isArray(value)) {
|
|
@@ -8208,7 +8610,7 @@ var BlockStateResolver = class {
|
|
|
8208
8610
|
return variants[variants.length - 1];
|
|
8209
8611
|
}
|
|
8210
8612
|
static rotation(variant) {
|
|
8211
|
-
const rotation = new
|
|
8613
|
+
const rotation = new Euler7();
|
|
8212
8614
|
if (typeof variant.x !== "undefined") {
|
|
8213
8615
|
rotation.x = toRadians(clampRotationDegrees(variant.x));
|
|
8214
8616
|
}
|
|
@@ -8318,7 +8720,7 @@ var import_ts_deepmerge6 = __toESM(require_dist());
|
|
|
8318
8720
|
init_MineRenderError();
|
|
8319
8721
|
init_InstanceReference();
|
|
8320
8722
|
init_AssetKey();
|
|
8321
|
-
import { Euler as
|
|
8723
|
+
import { Euler as Euler8, Matrix4 as Matrix49, Quaternion as Quaternion5, Vector3 as Vector311 } from "three";
|
|
8322
8724
|
init_ModelCulling();
|
|
8323
8725
|
init_FluidGeometry();
|
|
8324
8726
|
var _BlockObject = class _BlockObject extends SceneObject {
|
|
@@ -8335,6 +8737,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
8335
8737
|
this._variants = [];
|
|
8336
8738
|
this._models = [];
|
|
8337
8739
|
this._cullMask = 0;
|
|
8740
|
+
this._entities = [];
|
|
8741
|
+
this._entityPlacement = new Matrix49();
|
|
8742
|
+
this._entityGeneration = 0;
|
|
8338
8743
|
this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
|
|
8339
8744
|
}
|
|
8340
8745
|
async init() {
|
|
@@ -8354,6 +8759,8 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
8354
8759
|
}
|
|
8355
8760
|
clearModels() {
|
|
8356
8761
|
this.removeModels(this._models.splice(0));
|
|
8762
|
+
this._entityGeneration++;
|
|
8763
|
+
this.removeEntities(this._entities.splice(0));
|
|
8357
8764
|
this._fluidKey = void 0;
|
|
8358
8765
|
this._fluidModel = void 0;
|
|
8359
8766
|
this._isInstanced = false;
|
|
@@ -8365,6 +8772,57 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
8365
8772
|
if (!isInstanceReference(model)) model.dispose();
|
|
8366
8773
|
}
|
|
8367
8774
|
}
|
|
8775
|
+
removeEntities(entities) {
|
|
8776
|
+
for (const entity of entities) {
|
|
8777
|
+
entity.removeFromScene();
|
|
8778
|
+
entity.dispose();
|
|
8779
|
+
}
|
|
8780
|
+
}
|
|
8781
|
+
/** Entity models drawn for this block instead of its block model; they are scene children, unlike the block. */
|
|
8782
|
+
get blockEntities() {
|
|
8783
|
+
return this._entities;
|
|
8784
|
+
}
|
|
8785
|
+
/**
|
|
8786
|
+
* Draws the block through the dataset's block-entity index. Returns false, leaving nothing behind,
|
|
8787
|
+
* when the block is not listed or one of its models cannot be loaded.
|
|
8788
|
+
*/
|
|
8789
|
+
async createBlockEntities() {
|
|
8790
|
+
const key = this.blockState.key;
|
|
8791
|
+
if (!key || this.options.displayPosition) return false;
|
|
8792
|
+
const generation = this._entityGeneration;
|
|
8793
|
+
const created = [];
|
|
8794
|
+
let resolved;
|
|
8795
|
+
try {
|
|
8796
|
+
resolved = BlockEntities.resolve(await BlockEntities.getIndex(key.root), key.toNamespacedString(), this.state);
|
|
8797
|
+
if (!resolved) return false;
|
|
8798
|
+
for (const part of resolved.parts) {
|
|
8799
|
+
const [namespace, path] = part.model.includes(":") ? part.model.split(":") : [key.namespace, part.model];
|
|
8800
|
+
const texture = part.textureLocation === void 0 ? void 0 : AssetKey.parse("textures", part.textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
|
|
8801
|
+
if (texture) texture.root = key.root;
|
|
8802
|
+
const entity = await Entities.getEntity(new BasicAssetKey(namespace, path), texture, { layer: part.layer });
|
|
8803
|
+
if (!entity) throw new MineRenderError(`Missing entity model ${part.model}`);
|
|
8804
|
+
created.push(await this.scene.addEntity(entity, { wireframe: this.options.wireframe }));
|
|
8805
|
+
}
|
|
8806
|
+
} catch (error) {
|
|
8807
|
+
console.warn(`Could not draw block entity ${key.toNamespacedString()}, using its block model`, error);
|
|
8808
|
+
this.removeEntities(created);
|
|
8809
|
+
return false;
|
|
8810
|
+
}
|
|
8811
|
+
if (generation !== this._entityGeneration) {
|
|
8812
|
+
this.removeEntities(created);
|
|
8813
|
+
return true;
|
|
8814
|
+
}
|
|
8815
|
+
BlockEntities.matrix(resolved, this._entityPlacement);
|
|
8816
|
+
this._entities = created;
|
|
8817
|
+
this.placeEntities();
|
|
8818
|
+
return true;
|
|
8819
|
+
}
|
|
8820
|
+
placeEntities() {
|
|
8821
|
+
const matrix = new Matrix49().makeTranslation(this.position.x - 8, this.position.y - 8, this.position.z - 8).multiply(this._entityPlacement);
|
|
8822
|
+
for (const entity of this._entities) {
|
|
8823
|
+
matrix.decompose(entity.position, entity.quaternion, entity.scale);
|
|
8824
|
+
}
|
|
8825
|
+
}
|
|
8368
8826
|
get isOccluding() {
|
|
8369
8827
|
return this._models.some((model) => {
|
|
8370
8828
|
const object = isInstanceReference(model) ? model.instanceable : model;
|
|
@@ -8384,7 +8842,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
8384
8842
|
const scale = new Vector311();
|
|
8385
8843
|
this.getModelMatrix(model).decompose(position, rotation, scale);
|
|
8386
8844
|
if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector311(1, 1, 1)) > 1e-10) return 0;
|
|
8387
|
-
return ModelCulling.toLocalMask(worldMask, new
|
|
8845
|
+
return ModelCulling.toLocalMask(worldMask, new Euler8().setFromQuaternion(rotation));
|
|
8388
8846
|
}
|
|
8389
8847
|
async setCullMask(worldMask) {
|
|
8390
8848
|
worldMask &= 63;
|
|
@@ -8446,7 +8904,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
8446
8904
|
() => new FluidModelObject2(kind, surface.sample, this.blockState.key, this.options)
|
|
8447
8905
|
);
|
|
8448
8906
|
const previous = this._fluidModel;
|
|
8449
|
-
const matrix = previous ? this.getModelMatrix(previous) : new
|
|
8907
|
+
const matrix = previous ? this.getModelMatrix(previous) : new Matrix49().makeTranslation(...this.position.toArray());
|
|
8450
8908
|
if (isInstanceReference(replacement)) replacement.setMatrix(matrix);
|
|
8451
8909
|
else matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
|
|
8452
8910
|
this._models = this._models.filter((model) => model !== previous);
|
|
@@ -8476,13 +8934,20 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
8476
8934
|
await this.updateFluid(this._fluidSampler);
|
|
8477
8935
|
return;
|
|
8478
8936
|
}
|
|
8937
|
+
const hasEntities = await this.createBlockEntities();
|
|
8479
8938
|
const variantsToCreate = await this.mapStateToVariant(this.state);
|
|
8480
8939
|
this._variants = variantsToCreate;
|
|
8481
8940
|
for (let blockStateVariant of variantsToCreate) {
|
|
8941
|
+
if (hasEntities && !await this.hasGeometry(blockStateVariant)) continue;
|
|
8482
8942
|
this._models.push(await this.createVariant(blockStateVariant));
|
|
8483
8943
|
}
|
|
8484
8944
|
await this.updateFluid(this._fluidSampler);
|
|
8485
8945
|
}
|
|
8946
|
+
async hasGeometry(variant) {
|
|
8947
|
+
const modelKey = AssetKey.parse("models", variant.model);
|
|
8948
|
+
modelKey.root = this.blockState.key?.root;
|
|
8949
|
+
return !!(await Models.getMerged(modelKey))?.elements?.length;
|
|
8950
|
+
}
|
|
8486
8951
|
getSingleVariant(variants) {
|
|
8487
8952
|
return BlockStateResolver.choose(variants);
|
|
8488
8953
|
}
|
|
@@ -8577,7 +9042,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
8577
9042
|
setPositionRotationScaleAt(index, position, rotation, scale) {
|
|
8578
9043
|
super.setPositionRotationScaleAt(index, position, rotation, scale);
|
|
8579
9044
|
}
|
|
8580
|
-
getMatrixAt(index, matrix = new
|
|
9045
|
+
getMatrixAt(index, matrix = new Matrix49()) {
|
|
8581
9046
|
if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
|
|
8582
9047
|
const child = this._models[0];
|
|
8583
9048
|
if (child && isModelObject(child)) {
|
|
@@ -8602,6 +9067,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
8602
9067
|
for (let model of this._models) {
|
|
8603
9068
|
model.setPosition(position);
|
|
8604
9069
|
}
|
|
9070
|
+
this.placeEntities();
|
|
8605
9071
|
this.notifyDirty();
|
|
8606
9072
|
}
|
|
8607
9073
|
//TODO: should override rotation + scale methods
|
|
@@ -13141,7 +13607,7 @@ init_CubeFace();
|
|
|
13141
13607
|
init_AssetKey();
|
|
13142
13608
|
init_Models();
|
|
13143
13609
|
init_CubeFace();
|
|
13144
|
-
import { Matrix4 as
|
|
13610
|
+
import { Matrix4 as Matrix410, Vector3 as Vector314 } from "three";
|
|
13145
13611
|
init_ModelCulling();
|
|
13146
13612
|
init_ModelObject();
|
|
13147
13613
|
init_UVMapper();
|
|
@@ -13204,7 +13670,7 @@ var SectionModels = class {
|
|
|
13204
13670
|
});
|
|
13205
13671
|
await object.init();
|
|
13206
13672
|
const geometry = object.children[0].geometry;
|
|
13207
|
-
geometry.applyMatrix4(new
|
|
13673
|
+
geometry.applyMatrix4(new Matrix410().makeRotationFromEuler(rotation));
|
|
13208
13674
|
object.clear();
|
|
13209
13675
|
const cullFaces = CUBE_FACES.map((face) => {
|
|
13210
13676
|
const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
|
|
@@ -13616,7 +14082,8 @@ var Chunk = class _Chunk {
|
|
|
13616
14082
|
this.data.set(index, void 0);
|
|
13617
14083
|
return void 0;
|
|
13618
14084
|
}
|
|
13619
|
-
const
|
|
14085
|
+
const perBlock = !this.sectionModels || getFluidKind(blockState.key, stored.properties) || blockState.key && BlockEntities.entry(await BlockEntities.getIndex(blockState.key.root), blockState.key.toNamespacedString());
|
|
14086
|
+
const template = perBlock ? void 0 : await this.sectionModels.get(blockState, stored.properties);
|
|
13620
14087
|
if (template) {
|
|
13621
14088
|
this.sectionBlocks.set(index, { index, template, cullMask: 0 });
|
|
13622
14089
|
this.meshDirty = true;
|
|
@@ -13725,6 +14192,7 @@ export {
|
|
|
13725
14192
|
BUILTIN_GENERATED,
|
|
13726
14193
|
BasicAssetKey,
|
|
13727
14194
|
BatchedExecutor,
|
|
14195
|
+
BlockEntities,
|
|
13728
14196
|
BlockObject,
|
|
13729
14197
|
BlockStateResolver,
|
|
13730
14198
|
BlockStates,
|
|
@@ -13748,7 +14216,9 @@ export {
|
|
|
13748
14216
|
DefaultBlockStates,
|
|
13749
14217
|
DisplayPosition,
|
|
13750
14218
|
DisplayTransforms,
|
|
14219
|
+
ENTITY_ANIMATION_CHANNELS,
|
|
13751
14220
|
Entities,
|
|
14221
|
+
EntityAnimationPlayer,
|
|
13752
14222
|
EntityObject,
|
|
13753
14223
|
Env,
|
|
13754
14224
|
FluidModelObject,
|
|
@@ -13822,6 +14292,7 @@ export {
|
|
|
13822
14292
|
createCanvas,
|
|
13823
14293
|
createFluidGeometry,
|
|
13824
14294
|
createImage,
|
|
14295
|
+
entityAnimationTime,
|
|
13825
14296
|
estimateBytesUsed,
|
|
13826
14297
|
getBlockFluidState,
|
|
13827
14298
|
getFluidKind,
|
|
@@ -13855,6 +14326,8 @@ export {
|
|
|
13855
14326
|
prefix,
|
|
13856
14327
|
probeImageSize,
|
|
13857
14328
|
registerBrowserEnv,
|
|
14329
|
+
sampleEntityAnimation,
|
|
14330
|
+
sampleEntityKeyframes,
|
|
13858
14331
|
sampleFluid,
|
|
13859
14332
|
serializeBoxGeometryKey,
|
|
13860
14333
|
serializeImageKey,
|