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/node/index.js
CHANGED
|
@@ -886,6 +886,71 @@ var init_Materials = __esm({
|
|
|
886
886
|
alphaTest: 0.5
|
|
887
887
|
});
|
|
888
888
|
}
|
|
889
|
+
/** Whether vanilla's render type for the mode culls back faces. */
|
|
890
|
+
static entityModeCulls(mode = "cutout") {
|
|
891
|
+
return mode === "cutout_cull" || mode === "solid" || mode === "eyes" || mode === "water_mask";
|
|
892
|
+
}
|
|
893
|
+
/** UV offset per tick of entity age for the scrolling modes, as vanilla's texture matrix applies it. */
|
|
894
|
+
static entityModeScroll(mode = "cutout") {
|
|
895
|
+
if (mode === "energy_swirl") return [0.01, 0.01];
|
|
896
|
+
if (mode === "breeze_wind") return [0.02, 0];
|
|
897
|
+
return void 0;
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Entity material for one of vanilla's render types. Entities are unlit here, so the lit and full-bright modes
|
|
901
|
+
* differ only in blending and depth state. Culling is not a material property: {@link entityModeCulls} decides
|
|
902
|
+
* whether the geometry gets inward faces.
|
|
903
|
+
*/
|
|
904
|
+
static createEntityCanvasMaterial(canvas, mode = "cutout", tint) {
|
|
905
|
+
const material = _Materials.createBasicCanvasMaterial(canvas);
|
|
906
|
+
switch (mode) {
|
|
907
|
+
case "cutout":
|
|
908
|
+
case "cutout_cull":
|
|
909
|
+
break;
|
|
910
|
+
case "cutout_z_offset":
|
|
911
|
+
material.polygonOffset = true;
|
|
912
|
+
material.polygonOffsetFactor = -1;
|
|
913
|
+
material.polygonOffsetUnits = -10;
|
|
914
|
+
break;
|
|
915
|
+
case "solid":
|
|
916
|
+
material.alphaTest = 0;
|
|
917
|
+
break;
|
|
918
|
+
case "translucent":
|
|
919
|
+
case "breeze_wind":
|
|
920
|
+
material.transparent = true;
|
|
921
|
+
material.alphaTest = 0.1;
|
|
922
|
+
break;
|
|
923
|
+
case "translucent_emissive":
|
|
924
|
+
material.transparent = true;
|
|
925
|
+
material.alphaTest = 0.1;
|
|
926
|
+
material.depthWrite = false;
|
|
927
|
+
break;
|
|
928
|
+
case "eyes":
|
|
929
|
+
material.transparent = true;
|
|
930
|
+
material.alphaTest = 0;
|
|
931
|
+
material.depthWrite = false;
|
|
932
|
+
break;
|
|
933
|
+
case "energy_swirl":
|
|
934
|
+
material.transparent = true;
|
|
935
|
+
material.alphaTest = 0.1;
|
|
936
|
+
material.blending = import_three5.CustomBlending;
|
|
937
|
+
material.blendSrc = import_three5.OneFactor;
|
|
938
|
+
material.blendDst = import_three5.OneFactor;
|
|
939
|
+
material.blendSrcAlpha = import_three5.ZeroFactor;
|
|
940
|
+
material.blendDstAlpha = import_three5.OneFactor;
|
|
941
|
+
material.color.set(8421504);
|
|
942
|
+
break;
|
|
943
|
+
case "water_mask":
|
|
944
|
+
material.alphaTest = 0;
|
|
945
|
+
material.colorWrite = false;
|
|
946
|
+
break;
|
|
947
|
+
}
|
|
948
|
+
if (_Materials.entityModeScroll(mode)) {
|
|
949
|
+
material.map.wrapS = material.map.wrapT = import_three5.RepeatWrapping;
|
|
950
|
+
}
|
|
951
|
+
if (tint !== void 0) material.color.multiply(new import_three5.Color(tint));
|
|
952
|
+
return material;
|
|
953
|
+
}
|
|
889
954
|
static createGuiCanvasMaterial(canvas) {
|
|
890
955
|
const material = new import_three5.MeshBasicMaterial({
|
|
891
956
|
map: Textures.createCanvasTexture(canvas),
|
|
@@ -4970,32 +5035,44 @@ var Entities = class {
|
|
|
4970
5035
|
static async getLayerList(modelKey) {
|
|
4971
5036
|
return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
|
|
4972
5037
|
}
|
|
5038
|
+
/** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */
|
|
5039
|
+
static async getPassList(modelKey) {
|
|
5040
|
+
return (await this.getModelFile(modelKey))?.passes ?? [];
|
|
5041
|
+
}
|
|
4973
5042
|
static async getEntity(modelKey, textureKey, options) {
|
|
4974
5043
|
const model = await this.getModelFile(modelKey);
|
|
4975
5044
|
if (!model) return void 0;
|
|
4976
|
-
const
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
5045
|
+
const passes = options?.layers || options?.layer !== void 0 ? [] : (model.passes ?? []).filter((pass) => pass.when === void 0 || options?.when?.includes(pass.when));
|
|
5046
|
+
const draws = [...new Set(options?.layers ?? [options?.layer ?? "main"])].map((layer) => ({ layer }));
|
|
5047
|
+
if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
|
|
5048
|
+
draws.push(...passes);
|
|
5049
|
+
const names = [];
|
|
5050
|
+
const selected = draws.map((pass) => {
|
|
5051
|
+
const layer = model.layers[pass.layer];
|
|
4980
5052
|
if (!layer) {
|
|
4981
|
-
throw new MineRenderError(`Entity ${model.id} has no layer "${
|
|
5053
|
+
throw new MineRenderError(`Entity ${model.id} has no layer "${pass.layer}". Available layers: ${Object.keys(model.layers).join(", ")}`);
|
|
4982
5054
|
}
|
|
4983
|
-
|
|
5055
|
+
let name = pass.layer;
|
|
5056
|
+
for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;
|
|
5057
|
+
names.push(name);
|
|
5058
|
+
return { name, layer, pass };
|
|
4984
5059
|
});
|
|
4985
|
-
const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer }, index) => {
|
|
5060
|
+
const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {
|
|
4986
5061
|
const override = options?.textures?.[name] ?? (index === 0 ? textureKey : void 0);
|
|
5062
|
+
const textureLocation = pass.textureLocation ?? layer.textureLocation;
|
|
4987
5063
|
let texture;
|
|
4988
5064
|
if (override) {
|
|
4989
5065
|
const path = isAssetKey(override) ? override.getFullPath() : override.path;
|
|
4990
5066
|
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);
|
|
4991
|
-
} else if (
|
|
4992
|
-
texture = AssetKey.parse("textures",
|
|
5067
|
+
} else if (textureLocation !== void 0) {
|
|
5068
|
+
texture = AssetKey.parse("textures", textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
|
|
4993
5069
|
} else {
|
|
4994
5070
|
texture = await this.resolveTexture(modelKey);
|
|
4995
5071
|
}
|
|
4996
|
-
|
|
5072
|
+
const render = pass.render ?? layer.render;
|
|
5073
|
+
return [name, { key: override ?? modelKey, texture, layer, ...render && { render }, ...pass.tint && { tint: pass.tint } }];
|
|
4997
5074
|
})));
|
|
4998
|
-
return { ...layers[names[0]], id: model.id, layers };
|
|
5075
|
+
return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
|
|
4999
5076
|
}
|
|
5000
5077
|
static async resolveTexture(modelKey) {
|
|
5001
5078
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
@@ -5078,6 +5155,7 @@ init_SceneObject();
|
|
|
5078
5155
|
init_Caching();
|
|
5079
5156
|
var import_ts_deepmerge4 = __toESM(require_dist());
|
|
5080
5157
|
var import_three12 = require("three");
|
|
5158
|
+
init_Ticker();
|
|
5081
5159
|
init_model();
|
|
5082
5160
|
init_ModelTextures();
|
|
5083
5161
|
init_AssetKey();
|
|
@@ -5089,10 +5167,14 @@ var EntityObject = class _EntityObject extends SceneObject {
|
|
|
5089
5167
|
this.entity = entity;
|
|
5090
5168
|
this.isEntityObject = true;
|
|
5091
5169
|
this.meshesCreated = false;
|
|
5170
|
+
/** Scrolling materials are owned: their texture offset follows this entity's age. */
|
|
5171
|
+
this.scrollMaterials = [];
|
|
5172
|
+
/** Entity age in ticks, as vanilla's `ageInTicks`; drives the scrolling render modes. */
|
|
5173
|
+
this.age = 0;
|
|
5092
5174
|
this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
|
|
5093
5175
|
}
|
|
5094
5176
|
static {
|
|
5095
|
-
this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS
|
|
5177
|
+
this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS);
|
|
5096
5178
|
}
|
|
5097
5179
|
async init() {
|
|
5098
5180
|
this.createMeshes();
|
|
@@ -5101,6 +5183,25 @@ var EntityObject = class _EntityObject extends SceneObject {
|
|
|
5101
5183
|
dispose() {
|
|
5102
5184
|
super.dispose();
|
|
5103
5185
|
}
|
|
5186
|
+
disposeAndRemoveAllChildren() {
|
|
5187
|
+
this.clearScrollMaterials();
|
|
5188
|
+
super.disposeAndRemoveAllChildren();
|
|
5189
|
+
}
|
|
5190
|
+
clearScrollMaterials() {
|
|
5191
|
+
Ticker.remove(this.scrollTicker);
|
|
5192
|
+
this.scrollTicker = void 0;
|
|
5193
|
+
for (const { material } of this.scrollMaterials.splice(0)) {
|
|
5194
|
+
material.map?.dispose();
|
|
5195
|
+
material.dispose();
|
|
5196
|
+
}
|
|
5197
|
+
}
|
|
5198
|
+
/** Applies the entity age to the scrolling materials; the ticker calls this 20 times per second. */
|
|
5199
|
+
updateScroll() {
|
|
5200
|
+
for (const { offset, speed } of this.scrollMaterials) {
|
|
5201
|
+
offset.set(this.age * speed[0] % 1, 0 - this.age * speed[1] % 1);
|
|
5202
|
+
}
|
|
5203
|
+
this.notifyDirty();
|
|
5204
|
+
}
|
|
5104
5205
|
getLayerGroup(name) {
|
|
5105
5206
|
return super.getGroupByName(`layer:${name}`);
|
|
5106
5207
|
}
|
|
@@ -5131,16 +5232,29 @@ var EntityObject = class _EntityObject extends SceneObject {
|
|
|
5131
5232
|
createMeshes(force = false) {
|
|
5132
5233
|
if (this.meshesCreated && !force) return;
|
|
5133
5234
|
const modelRoot = new import_three12.Object3D();
|
|
5134
|
-
|
|
5235
|
+
const transform = this.options.flip === void 0 ? this.entity.transform : void 0;
|
|
5236
|
+
if (transform) {
|
|
5237
|
+
for (const op of transform) {
|
|
5238
|
+
const matrix = new import_three12.Matrix4();
|
|
5239
|
+
if ("scale" in op) matrix.makeScale(...op.scale);
|
|
5240
|
+
else if ("translate" in op) matrix.makeTranslation(...op.translate);
|
|
5241
|
+
else matrix.makeRotationFromEuler(new import_three12.Euler(...op.rotate, "ZYX"));
|
|
5242
|
+
modelRoot.matrix.multiply(matrix);
|
|
5243
|
+
}
|
|
5244
|
+
modelRoot.matrixAutoUpdate = false;
|
|
5245
|
+
} else if (this.options.flip ?? true) {
|
|
5246
|
+
modelRoot.scale.set(-1, -1, 1);
|
|
5247
|
+
}
|
|
5135
5248
|
this.add(modelRoot);
|
|
5136
5249
|
Object.entries(this.entityLayers).forEach(([name, layer], index) => {
|
|
5137
5250
|
const group = this.createGroup(`layer:${name}`);
|
|
5138
5251
|
modelRoot.add(group);
|
|
5139
|
-
|
|
5252
|
+
const inward = !Materials.entityModeCulls(layer.render ?? layer.layer.render);
|
|
5253
|
+
this.createPart("root", layer.layer.root, group, layer.layer.texture, Materials.MISSING_TEXTURE, index, inward);
|
|
5140
5254
|
});
|
|
5141
5255
|
this.meshesCreated = true;
|
|
5142
5256
|
}
|
|
5143
|
-
createPart(name, part, parent, textureSize, material, renderOrder) {
|
|
5257
|
+
createPart(name, part, parent, textureSize, material, renderOrder, inward = true) {
|
|
5144
5258
|
const anchor = this.createGroup(name);
|
|
5145
5259
|
anchor.position.fromArray(part.pose.offset);
|
|
5146
5260
|
anchor.rotation.set(...part.pose.rotation, "ZYX");
|
|
@@ -5159,7 +5273,7 @@ var EntityObject = class _EntityObject extends SceneObject {
|
|
|
5159
5273
|
uv
|
|
5160
5274
|
).clone();
|
|
5161
5275
|
geometry.translate(cube.origin[0] + width / 2, cube.origin[1] + height / 2, cube.origin[2] + depth / 2);
|
|
5162
|
-
if (Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
|
|
5276
|
+
if (inward && Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
|
|
5163
5277
|
const index = Array.from(geometry.getIndex().array);
|
|
5164
5278
|
geometry.setIndex(index.concat(index.slice().reverse()));
|
|
5165
5279
|
}
|
|
@@ -5169,26 +5283,42 @@ var EntityObject = class _EntityObject extends SceneObject {
|
|
|
5169
5283
|
if (this.options.wireframe) addWireframeToMesh(geometry, mesh);
|
|
5170
5284
|
}
|
|
5171
5285
|
for (const [childName, child] of Object.entries(part.children)) {
|
|
5172
|
-
this.createPart(childName, child, anchor, size, material, renderOrder);
|
|
5286
|
+
this.createPart(childName, child, anchor, size, material, renderOrder, inward);
|
|
5173
5287
|
}
|
|
5174
5288
|
}
|
|
5175
5289
|
async applyTextures() {
|
|
5290
|
+
this.clearScrollMaterials();
|
|
5176
5291
|
await Promise.all(Object.entries(this.entityLayers).map(async ([name, layer]) => {
|
|
5292
|
+
const mode = layer.render ?? layer.layer.render ?? "cutout";
|
|
5293
|
+
const tint = layer.tint === void 0 ? void 0 : this.options.tints?.[layer.tint];
|
|
5294
|
+
const scroll = Materials.entityModeScroll(mode);
|
|
5177
5295
|
const assetKeyStr = this.getTextureKey(layer).serialize();
|
|
5178
|
-
const keyStr = `entity:${assetKeyStr}`;
|
|
5179
|
-
let mat = Caching.materialCache.getIfPresent(keyStr);
|
|
5296
|
+
const keyStr = `entity:${mode}:${tint === void 0 ? "" : new import_three12.Color(tint).getHexString()}:${assetKeyStr}`;
|
|
5297
|
+
let mat = scroll ? void 0 : Caching.materialCache.getIfPresent(keyStr);
|
|
5180
5298
|
if (!mat) {
|
|
5181
5299
|
const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
|
|
5182
5300
|
const imageData = await this.loadTextures(layer);
|
|
5183
5301
|
if (!imageData) return;
|
|
5184
5302
|
const canvas = imageData.data.canvas;
|
|
5185
|
-
const createMaterial = () => Materials.
|
|
5186
|
-
mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
|
|
5303
|
+
const createMaterial = () => Materials.createEntityCanvasMaterial(canvas, mode, tint);
|
|
5304
|
+
mat = !scroll && cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
|
|
5305
|
+
if (scroll) {
|
|
5306
|
+
this.scrollMaterials.push({ material: mat, offset: mat.map.offset, speed: scroll });
|
|
5307
|
+
}
|
|
5187
5308
|
}
|
|
5188
5309
|
this.getLayerGroup(name)?.traverse((object) => {
|
|
5189
5310
|
if (isMesh(object)) object.material = mat;
|
|
5190
5311
|
});
|
|
5191
5312
|
}));
|
|
5313
|
+
if (!this.children.length) {
|
|
5314
|
+
this.clearScrollMaterials();
|
|
5315
|
+
} else if (this.scrollMaterials.length) {
|
|
5316
|
+
this.updateScroll();
|
|
5317
|
+
this.scrollTicker = Ticker.add(() => {
|
|
5318
|
+
this.age++;
|
|
5319
|
+
this.updateScroll();
|
|
5320
|
+
});
|
|
5321
|
+
}
|
|
5192
5322
|
this.notifyDirty();
|
|
5193
5323
|
}
|
|
5194
5324
|
};
|
|
@@ -7704,11 +7834,69 @@ function copyDataTexture(source) {
|
|
|
7704
7834
|
}
|
|
7705
7835
|
|
|
7706
7836
|
// src/gui/GuiHelper.ts
|
|
7837
|
+
init_AssetKey();
|
|
7707
7838
|
var GuiHelper = class {
|
|
7708
7839
|
static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
|
|
7709
7840
|
const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
|
|
7710
7841
|
return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
|
|
7711
7842
|
}
|
|
7843
|
+
/** Creates crafting-table layers for ingredients and the result; stack counts are not drawn. */
|
|
7844
|
+
static recipe(recipe, options = {}) {
|
|
7845
|
+
const layers = [
|
|
7846
|
+
{ name: "background", texture: "minecraft:gui/container/crafting_table", crop: [0, 0, 176, 166] }
|
|
7847
|
+
];
|
|
7848
|
+
const itemKey = (ingredient) => {
|
|
7849
|
+
const item = typeof ingredient === "string" && !ingredient.startsWith("#") ? ingredient : typeof ingredient === "object" && "item" in ingredient ? ingredient.item : options.resolveIngredient?.(ingredient);
|
|
7850
|
+
if (isAssetKey(item)) return item;
|
|
7851
|
+
if (!item || item.startsWith("#")) {
|
|
7852
|
+
throw new Error(`Select a concrete item for recipe ingredient ${JSON.stringify(ingredient)}`);
|
|
7853
|
+
}
|
|
7854
|
+
const key = AssetKey.parse("models", item);
|
|
7855
|
+
return new AssetKey(key.namespace, key.getFullPath(), "models", "item");
|
|
7856
|
+
};
|
|
7857
|
+
const addIngredient = (ingredient, slot) => {
|
|
7858
|
+
layers.push({
|
|
7859
|
+
name: `ingredient-${slot}`,
|
|
7860
|
+
item: itemKey(ingredient),
|
|
7861
|
+
position: this.inventorySlot(slot, [30, 17], [18, 18], 3)
|
|
7862
|
+
});
|
|
7863
|
+
};
|
|
7864
|
+
switch (recipe.type) {
|
|
7865
|
+
case "minecraft:crafting_shaped":
|
|
7866
|
+
case "crafting_shaped": {
|
|
7867
|
+
const pattern = recipe.pattern;
|
|
7868
|
+
if (!pattern.length || pattern.length > 3 || !pattern[0].length || pattern[0].length > 3 || pattern.some((row) => row.length !== pattern[0].length)) {
|
|
7869
|
+
throw new Error("Crafting patterns must be rectangular, with 1\u20133 rows and columns");
|
|
7870
|
+
}
|
|
7871
|
+
const cells = pattern.flatMap((row, y) => row.split("").map((symbol, x) => ({ symbol, x, y }))).filter((cell) => cell.symbol !== " ");
|
|
7872
|
+
if (!cells.length) throw new Error("Crafting patterns must contain an ingredient");
|
|
7873
|
+
const minX = Math.min(...cells.map((cell) => cell.x)), maxX = Math.max(...cells.map((cell) => cell.x));
|
|
7874
|
+
const minY = Math.min(...cells.map((cell) => cell.y)), maxY = Math.max(...cells.map((cell) => cell.y));
|
|
7875
|
+
const offsetX = minX === maxX ? 1 : 0, offsetY = minY === maxY ? 1 : 0;
|
|
7876
|
+
for (const { symbol, x, y } of cells) {
|
|
7877
|
+
const ingredient = recipe.key[symbol];
|
|
7878
|
+
if (!ingredient) throw new Error(`Missing recipe ingredient for symbol ${JSON.stringify(symbol)}`);
|
|
7879
|
+
addIngredient(ingredient, (y - minY + offsetY) * 3 + x - minX + offsetX);
|
|
7880
|
+
}
|
|
7881
|
+
break;
|
|
7882
|
+
}
|
|
7883
|
+
case "minecraft:crafting_shapeless":
|
|
7884
|
+
case "crafting_shapeless":
|
|
7885
|
+
if (!recipe.ingredients.length || recipe.ingredients.length > 9) {
|
|
7886
|
+
throw new Error("Shapeless crafting recipes require 1\u20139 ingredients");
|
|
7887
|
+
}
|
|
7888
|
+
recipe.ingredients.forEach(addIngredient);
|
|
7889
|
+
break;
|
|
7890
|
+
default:
|
|
7891
|
+
throw new Error(`Unsupported crafting recipe type: ${recipe.type}`);
|
|
7892
|
+
}
|
|
7893
|
+
layers.push({
|
|
7894
|
+
name: "result",
|
|
7895
|
+
item: itemKey("id" in recipe.result ? recipe.result.id : recipe.result.item),
|
|
7896
|
+
position: [124, 35]
|
|
7897
|
+
});
|
|
7898
|
+
return layers;
|
|
7899
|
+
}
|
|
7712
7900
|
};
|
|
7713
7901
|
|
|
7714
7902
|
// src/gui/scene/GuiObject.ts
|