minerender 2.1.0-alpha.53 → 2.1.0-alpha.54
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 +141 -41
- package/dist/browser/index.d.ts +141 -41
- package/dist/browser/index.js +209 -21
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +244 -56
- package/dist/browser/index.mjs.map +1 -1
- package/dist/bundle.js +209 -21
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +141 -41
- package/dist/node/index.d.ts +141 -41
- package/dist/node/index.js +209 -21
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +244 -56
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/browser/index.js
CHANGED
|
@@ -839,6 +839,71 @@ var init_Materials = __esm({
|
|
|
839
839
|
alphaTest: 0.5
|
|
840
840
|
});
|
|
841
841
|
}
|
|
842
|
+
/** Whether vanilla's render type for the mode culls back faces. */
|
|
843
|
+
static entityModeCulls(mode = "cutout") {
|
|
844
|
+
return mode === "cutout_cull" || mode === "solid" || mode === "eyes" || mode === "water_mask";
|
|
845
|
+
}
|
|
846
|
+
/** UV offset per tick of entity age for the scrolling modes, as vanilla's texture matrix applies it. */
|
|
847
|
+
static entityModeScroll(mode = "cutout") {
|
|
848
|
+
if (mode === "energy_swirl") return [0.01, 0.01];
|
|
849
|
+
if (mode === "breeze_wind") return [0.02, 0];
|
|
850
|
+
return void 0;
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Entity material for one of vanilla's render types. Entities are unlit here, so the lit and full-bright modes
|
|
854
|
+
* differ only in blending and depth state. Culling is not a material property: {@link entityModeCulls} decides
|
|
855
|
+
* whether the geometry gets inward faces.
|
|
856
|
+
*/
|
|
857
|
+
static createEntityCanvasMaterial(canvas, mode = "cutout", tint) {
|
|
858
|
+
const material = _Materials.createBasicCanvasMaterial(canvas);
|
|
859
|
+
switch (mode) {
|
|
860
|
+
case "cutout":
|
|
861
|
+
case "cutout_cull":
|
|
862
|
+
break;
|
|
863
|
+
case "cutout_z_offset":
|
|
864
|
+
material.polygonOffset = true;
|
|
865
|
+
material.polygonOffsetFactor = -1;
|
|
866
|
+
material.polygonOffsetUnits = -10;
|
|
867
|
+
break;
|
|
868
|
+
case "solid":
|
|
869
|
+
material.alphaTest = 0;
|
|
870
|
+
break;
|
|
871
|
+
case "translucent":
|
|
872
|
+
case "breeze_wind":
|
|
873
|
+
material.transparent = true;
|
|
874
|
+
material.alphaTest = 0.1;
|
|
875
|
+
break;
|
|
876
|
+
case "translucent_emissive":
|
|
877
|
+
material.transparent = true;
|
|
878
|
+
material.alphaTest = 0.1;
|
|
879
|
+
material.depthWrite = false;
|
|
880
|
+
break;
|
|
881
|
+
case "eyes":
|
|
882
|
+
material.transparent = true;
|
|
883
|
+
material.alphaTest = 0;
|
|
884
|
+
material.depthWrite = false;
|
|
885
|
+
break;
|
|
886
|
+
case "energy_swirl":
|
|
887
|
+
material.transparent = true;
|
|
888
|
+
material.alphaTest = 0.1;
|
|
889
|
+
material.blending = import_three5.CustomBlending;
|
|
890
|
+
material.blendSrc = import_three5.OneFactor;
|
|
891
|
+
material.blendDst = import_three5.OneFactor;
|
|
892
|
+
material.blendSrcAlpha = import_three5.ZeroFactor;
|
|
893
|
+
material.blendDstAlpha = import_three5.OneFactor;
|
|
894
|
+
material.color.set(8421504);
|
|
895
|
+
break;
|
|
896
|
+
case "water_mask":
|
|
897
|
+
material.alphaTest = 0;
|
|
898
|
+
material.colorWrite = false;
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
901
|
+
if (_Materials.entityModeScroll(mode)) {
|
|
902
|
+
material.map.wrapS = material.map.wrapT = import_three5.RepeatWrapping;
|
|
903
|
+
}
|
|
904
|
+
if (tint !== void 0) material.color.multiply(new import_three5.Color(tint));
|
|
905
|
+
return material;
|
|
906
|
+
}
|
|
842
907
|
static createGuiCanvasMaterial(canvas) {
|
|
843
908
|
const material = new import_three5.MeshBasicMaterial({
|
|
844
909
|
map: Textures.createCanvasTexture(canvas),
|
|
@@ -4925,32 +4990,44 @@ var Entities = class {
|
|
|
4925
4990
|
static async getLayerList(modelKey) {
|
|
4926
4991
|
return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
|
|
4927
4992
|
}
|
|
4993
|
+
/** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */
|
|
4994
|
+
static async getPassList(modelKey) {
|
|
4995
|
+
return (await this.getModelFile(modelKey))?.passes ?? [];
|
|
4996
|
+
}
|
|
4928
4997
|
static async getEntity(modelKey, textureKey, options) {
|
|
4929
4998
|
const model = await this.getModelFile(modelKey);
|
|
4930
4999
|
if (!model) return void 0;
|
|
4931
|
-
const
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
5000
|
+
const passes = options?.layers || options?.layer !== void 0 ? [] : (model.passes ?? []).filter((pass) => pass.when === void 0 || options?.when?.includes(pass.when));
|
|
5001
|
+
const draws = [...new Set(options?.layers ?? [options?.layer ?? "main"])].map((layer) => ({ layer }));
|
|
5002
|
+
if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
|
|
5003
|
+
draws.push(...passes);
|
|
5004
|
+
const names = [];
|
|
5005
|
+
const selected = draws.map((pass) => {
|
|
5006
|
+
const layer = model.layers[pass.layer];
|
|
4935
5007
|
if (!layer) {
|
|
4936
|
-
throw new MineRenderError(`Entity ${model.id} has no layer "${
|
|
5008
|
+
throw new MineRenderError(`Entity ${model.id} has no layer "${pass.layer}". Available layers: ${Object.keys(model.layers).join(", ")}`);
|
|
4937
5009
|
}
|
|
4938
|
-
|
|
5010
|
+
let name = pass.layer;
|
|
5011
|
+
for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;
|
|
5012
|
+
names.push(name);
|
|
5013
|
+
return { name, layer, pass };
|
|
4939
5014
|
});
|
|
4940
|
-
const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer }, index) => {
|
|
5015
|
+
const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {
|
|
4941
5016
|
const override = options?.textures?.[name] ?? (index === 0 ? textureKey : void 0);
|
|
5017
|
+
const textureLocation = pass.textureLocation ?? layer.textureLocation;
|
|
4942
5018
|
let texture;
|
|
4943
5019
|
if (override) {
|
|
4944
5020
|
const path = isAssetKey(override) ? override.getFullPath() : override.path;
|
|
4945
5021
|
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);
|
|
4946
|
-
} else if (
|
|
4947
|
-
texture = AssetKey.parse("textures",
|
|
5022
|
+
} else if (textureLocation !== void 0) {
|
|
5023
|
+
texture = AssetKey.parse("textures", textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
|
|
4948
5024
|
} else {
|
|
4949
5025
|
texture = await this.resolveTexture(modelKey);
|
|
4950
5026
|
}
|
|
4951
|
-
|
|
5027
|
+
const render = pass.render ?? layer.render;
|
|
5028
|
+
return [name, { key: override ?? modelKey, texture, layer, ...render && { render }, ...pass.tint && { tint: pass.tint } }];
|
|
4952
5029
|
})));
|
|
4953
|
-
return { ...layers[names[0]], id: model.id, layers };
|
|
5030
|
+
return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
|
|
4954
5031
|
}
|
|
4955
5032
|
static async resolveTexture(modelKey) {
|
|
4956
5033
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
@@ -5033,6 +5110,7 @@ init_SceneObject();
|
|
|
5033
5110
|
init_Caching();
|
|
5034
5111
|
var import_ts_deepmerge4 = __toESM(require_dist());
|
|
5035
5112
|
var import_three12 = require("three");
|
|
5113
|
+
init_Ticker();
|
|
5036
5114
|
init_model();
|
|
5037
5115
|
init_ModelTextures();
|
|
5038
5116
|
init_AssetKey();
|
|
@@ -5044,6 +5122,10 @@ var _EntityObject = class _EntityObject extends SceneObject {
|
|
|
5044
5122
|
this.entity = entity;
|
|
5045
5123
|
this.isEntityObject = true;
|
|
5046
5124
|
this.meshesCreated = false;
|
|
5125
|
+
/** Scrolling materials are owned: their texture offset follows this entity's age. */
|
|
5126
|
+
this.scrollMaterials = [];
|
|
5127
|
+
/** Entity age in ticks, as vanilla's `ageInTicks`; drives the scrolling render modes. */
|
|
5128
|
+
this.age = 0;
|
|
5047
5129
|
this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
|
|
5048
5130
|
}
|
|
5049
5131
|
async init() {
|
|
@@ -5053,6 +5135,25 @@ var _EntityObject = class _EntityObject extends SceneObject {
|
|
|
5053
5135
|
dispose() {
|
|
5054
5136
|
super.dispose();
|
|
5055
5137
|
}
|
|
5138
|
+
disposeAndRemoveAllChildren() {
|
|
5139
|
+
this.clearScrollMaterials();
|
|
5140
|
+
super.disposeAndRemoveAllChildren();
|
|
5141
|
+
}
|
|
5142
|
+
clearScrollMaterials() {
|
|
5143
|
+
Ticker.remove(this.scrollTicker);
|
|
5144
|
+
this.scrollTicker = void 0;
|
|
5145
|
+
for (const { material } of this.scrollMaterials.splice(0)) {
|
|
5146
|
+
material.map?.dispose();
|
|
5147
|
+
material.dispose();
|
|
5148
|
+
}
|
|
5149
|
+
}
|
|
5150
|
+
/** Applies the entity age to the scrolling materials; the ticker calls this 20 times per second. */
|
|
5151
|
+
updateScroll() {
|
|
5152
|
+
for (const { offset, speed } of this.scrollMaterials) {
|
|
5153
|
+
offset.set(this.age * speed[0] % 1, 0 - this.age * speed[1] % 1);
|
|
5154
|
+
}
|
|
5155
|
+
this.notifyDirty();
|
|
5156
|
+
}
|
|
5056
5157
|
getLayerGroup(name) {
|
|
5057
5158
|
return super.getGroupByName(`layer:${name}`);
|
|
5058
5159
|
}
|
|
@@ -5083,16 +5184,29 @@ var _EntityObject = class _EntityObject extends SceneObject {
|
|
|
5083
5184
|
createMeshes(force = false) {
|
|
5084
5185
|
if (this.meshesCreated && !force) return;
|
|
5085
5186
|
const modelRoot = new import_three12.Object3D();
|
|
5086
|
-
|
|
5187
|
+
const transform = this.options.flip === void 0 ? this.entity.transform : void 0;
|
|
5188
|
+
if (transform) {
|
|
5189
|
+
for (const op of transform) {
|
|
5190
|
+
const matrix = new import_three12.Matrix4();
|
|
5191
|
+
if ("scale" in op) matrix.makeScale(...op.scale);
|
|
5192
|
+
else if ("translate" in op) matrix.makeTranslation(...op.translate);
|
|
5193
|
+
else matrix.makeRotationFromEuler(new import_three12.Euler(...op.rotate, "ZYX"));
|
|
5194
|
+
modelRoot.matrix.multiply(matrix);
|
|
5195
|
+
}
|
|
5196
|
+
modelRoot.matrixAutoUpdate = false;
|
|
5197
|
+
} else if (this.options.flip ?? true) {
|
|
5198
|
+
modelRoot.scale.set(-1, -1, 1);
|
|
5199
|
+
}
|
|
5087
5200
|
this.add(modelRoot);
|
|
5088
5201
|
Object.entries(this.entityLayers).forEach(([name, layer], index) => {
|
|
5089
5202
|
const group = this.createGroup(`layer:${name}`);
|
|
5090
5203
|
modelRoot.add(group);
|
|
5091
|
-
|
|
5204
|
+
const inward = !Materials.entityModeCulls(layer.render ?? layer.layer.render);
|
|
5205
|
+
this.createPart("root", layer.layer.root, group, layer.layer.texture, Materials.MISSING_TEXTURE, index, inward);
|
|
5092
5206
|
});
|
|
5093
5207
|
this.meshesCreated = true;
|
|
5094
5208
|
}
|
|
5095
|
-
createPart(name, part, parent, textureSize, material, renderOrder) {
|
|
5209
|
+
createPart(name, part, parent, textureSize, material, renderOrder, inward = true) {
|
|
5096
5210
|
const anchor = this.createGroup(name);
|
|
5097
5211
|
anchor.position.fromArray(part.pose.offset);
|
|
5098
5212
|
anchor.rotation.set(...part.pose.rotation, "ZYX");
|
|
@@ -5111,7 +5225,7 @@ var _EntityObject = class _EntityObject extends SceneObject {
|
|
|
5111
5225
|
uv
|
|
5112
5226
|
).clone();
|
|
5113
5227
|
geometry.translate(cube.origin[0] + width / 2, cube.origin[1] + height / 2, cube.origin[2] + depth / 2);
|
|
5114
|
-
if (Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
|
|
5228
|
+
if (inward && Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
|
|
5115
5229
|
const index = Array.from(geometry.getIndex().array);
|
|
5116
5230
|
geometry.setIndex(index.concat(index.slice().reverse()));
|
|
5117
5231
|
}
|
|
@@ -5121,30 +5235,46 @@ var _EntityObject = class _EntityObject extends SceneObject {
|
|
|
5121
5235
|
if (this.options.wireframe) addWireframeToMesh(geometry, mesh);
|
|
5122
5236
|
}
|
|
5123
5237
|
for (const [childName, child] of Object.entries(part.children)) {
|
|
5124
|
-
this.createPart(childName, child, anchor, size, material, renderOrder);
|
|
5238
|
+
this.createPart(childName, child, anchor, size, material, renderOrder, inward);
|
|
5125
5239
|
}
|
|
5126
5240
|
}
|
|
5127
5241
|
async applyTextures() {
|
|
5242
|
+
this.clearScrollMaterials();
|
|
5128
5243
|
await Promise.all(Object.entries(this.entityLayers).map(async ([name, layer]) => {
|
|
5244
|
+
const mode = layer.render ?? layer.layer.render ?? "cutout";
|
|
5245
|
+
const tint = layer.tint === void 0 ? void 0 : this.options.tints?.[layer.tint];
|
|
5246
|
+
const scroll = Materials.entityModeScroll(mode);
|
|
5129
5247
|
const assetKeyStr = this.getTextureKey(layer).serialize();
|
|
5130
|
-
const keyStr = `entity:${assetKeyStr}`;
|
|
5131
|
-
let mat = Caching.materialCache.getIfPresent(keyStr);
|
|
5248
|
+
const keyStr = `entity:${mode}:${tint === void 0 ? "" : new import_three12.Color(tint).getHexString()}:${assetKeyStr}`;
|
|
5249
|
+
let mat = scroll ? void 0 : Caching.materialCache.getIfPresent(keyStr);
|
|
5132
5250
|
if (!mat) {
|
|
5133
5251
|
const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
|
|
5134
5252
|
const imageData = await this.loadTextures(layer);
|
|
5135
5253
|
if (!imageData) return;
|
|
5136
5254
|
const canvas = imageData.data.canvas;
|
|
5137
|
-
const createMaterial = () => Materials.
|
|
5138
|
-
mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
|
|
5255
|
+
const createMaterial = () => Materials.createEntityCanvasMaterial(canvas, mode, tint);
|
|
5256
|
+
mat = !scroll && cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
|
|
5257
|
+
if (scroll) {
|
|
5258
|
+
this.scrollMaterials.push({ material: mat, offset: mat.map.offset, speed: scroll });
|
|
5259
|
+
}
|
|
5139
5260
|
}
|
|
5140
5261
|
this.getLayerGroup(name)?.traverse((object) => {
|
|
5141
5262
|
if (isMesh(object)) object.material = mat;
|
|
5142
5263
|
});
|
|
5143
5264
|
}));
|
|
5265
|
+
if (!this.children.length) {
|
|
5266
|
+
this.clearScrollMaterials();
|
|
5267
|
+
} else if (this.scrollMaterials.length) {
|
|
5268
|
+
this.updateScroll();
|
|
5269
|
+
this.scrollTicker = Ticker.add(() => {
|
|
5270
|
+
this.age++;
|
|
5271
|
+
this.updateScroll();
|
|
5272
|
+
});
|
|
5273
|
+
}
|
|
5144
5274
|
this.notifyDirty();
|
|
5145
5275
|
}
|
|
5146
5276
|
};
|
|
5147
|
-
_EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS
|
|
5277
|
+
_EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS);
|
|
5148
5278
|
var EntityObject = _EntityObject;
|
|
5149
5279
|
function isEntityObject(obj) {
|
|
5150
5280
|
return obj.isEntityObject;
|
|
@@ -7658,11 +7788,69 @@ function copyDataTexture(source) {
|
|
|
7658
7788
|
}
|
|
7659
7789
|
|
|
7660
7790
|
// src/gui/GuiHelper.ts
|
|
7791
|
+
init_AssetKey();
|
|
7661
7792
|
var GuiHelper = class {
|
|
7662
7793
|
static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
|
|
7663
7794
|
const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
|
|
7664
7795
|
return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
|
|
7665
7796
|
}
|
|
7797
|
+
/** Creates crafting-table layers for ingredients and the result; stack counts are not drawn. */
|
|
7798
|
+
static recipe(recipe, options = {}) {
|
|
7799
|
+
const layers = [
|
|
7800
|
+
{ name: "background", texture: "minecraft:gui/container/crafting_table", crop: [0, 0, 176, 166] }
|
|
7801
|
+
];
|
|
7802
|
+
const itemKey = (ingredient) => {
|
|
7803
|
+
const item = typeof ingredient === "string" && !ingredient.startsWith("#") ? ingredient : typeof ingredient === "object" && "item" in ingredient ? ingredient.item : options.resolveIngredient?.(ingredient);
|
|
7804
|
+
if (isAssetKey(item)) return item;
|
|
7805
|
+
if (!item || item.startsWith("#")) {
|
|
7806
|
+
throw new Error(`Select a concrete item for recipe ingredient ${JSON.stringify(ingredient)}`);
|
|
7807
|
+
}
|
|
7808
|
+
const key = AssetKey.parse("models", item);
|
|
7809
|
+
return new AssetKey(key.namespace, key.getFullPath(), "models", "item");
|
|
7810
|
+
};
|
|
7811
|
+
const addIngredient = (ingredient, slot) => {
|
|
7812
|
+
layers.push({
|
|
7813
|
+
name: `ingredient-${slot}`,
|
|
7814
|
+
item: itemKey(ingredient),
|
|
7815
|
+
position: this.inventorySlot(slot, [30, 17], [18, 18], 3)
|
|
7816
|
+
});
|
|
7817
|
+
};
|
|
7818
|
+
switch (recipe.type) {
|
|
7819
|
+
case "minecraft:crafting_shaped":
|
|
7820
|
+
case "crafting_shaped": {
|
|
7821
|
+
const pattern = recipe.pattern;
|
|
7822
|
+
if (!pattern.length || pattern.length > 3 || !pattern[0].length || pattern[0].length > 3 || pattern.some((row) => row.length !== pattern[0].length)) {
|
|
7823
|
+
throw new Error("Crafting patterns must be rectangular, with 1\u20133 rows and columns");
|
|
7824
|
+
}
|
|
7825
|
+
const cells = pattern.flatMap((row, y) => row.split("").map((symbol, x) => ({ symbol, x, y }))).filter((cell) => cell.symbol !== " ");
|
|
7826
|
+
if (!cells.length) throw new Error("Crafting patterns must contain an ingredient");
|
|
7827
|
+
const minX = Math.min(...cells.map((cell) => cell.x)), maxX = Math.max(...cells.map((cell) => cell.x));
|
|
7828
|
+
const minY = Math.min(...cells.map((cell) => cell.y)), maxY = Math.max(...cells.map((cell) => cell.y));
|
|
7829
|
+
const offsetX = minX === maxX ? 1 : 0, offsetY = minY === maxY ? 1 : 0;
|
|
7830
|
+
for (const { symbol, x, y } of cells) {
|
|
7831
|
+
const ingredient = recipe.key[symbol];
|
|
7832
|
+
if (!ingredient) throw new Error(`Missing recipe ingredient for symbol ${JSON.stringify(symbol)}`);
|
|
7833
|
+
addIngredient(ingredient, (y - minY + offsetY) * 3 + x - minX + offsetX);
|
|
7834
|
+
}
|
|
7835
|
+
break;
|
|
7836
|
+
}
|
|
7837
|
+
case "minecraft:crafting_shapeless":
|
|
7838
|
+
case "crafting_shapeless":
|
|
7839
|
+
if (!recipe.ingredients.length || recipe.ingredients.length > 9) {
|
|
7840
|
+
throw new Error("Shapeless crafting recipes require 1\u20139 ingredients");
|
|
7841
|
+
}
|
|
7842
|
+
recipe.ingredients.forEach(addIngredient);
|
|
7843
|
+
break;
|
|
7844
|
+
default:
|
|
7845
|
+
throw new Error(`Unsupported crafting recipe type: ${recipe.type}`);
|
|
7846
|
+
}
|
|
7847
|
+
layers.push({
|
|
7848
|
+
name: "result",
|
|
7849
|
+
item: itemKey("id" in recipe.result ? recipe.result.id : recipe.result.item),
|
|
7850
|
+
position: [124, 35]
|
|
7851
|
+
});
|
|
7852
|
+
return layers;
|
|
7853
|
+
}
|
|
7666
7854
|
};
|
|
7667
7855
|
|
|
7668
7856
|
// src/gui/scene/GuiObject.ts
|