minerender 2.1.0-alpha.145 → 2.1.0-alpha.147

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.
@@ -1794,6 +1794,7 @@ declare class BlockObject extends SceneObject {
1794
1794
  */
1795
1795
  private createBlockEntities;
1796
1796
  private placeEntities;
1797
+ private placeEntity;
1797
1798
  get isOccluding(): boolean;
1798
1799
  private getModelMatrix;
1799
1800
  private getModelCullMask;
@@ -2744,6 +2745,8 @@ interface UnihexFile {
2744
2745
 
2745
2746
  /** Shared in-memory caches for loaded assets and render resources. Persistent stores are managed separately. */
2746
2747
  declare class Caching {
2748
+ /** Cached in place of a missing asset. The caches drop `undefined` results, which would request the asset again. */
2749
+ static readonly MISSING: false;
2747
2750
  private static _generation;
2748
2751
  /** Changes when shared assets are cleared, so derived caches can discard their old values. */
2749
2752
  static get generation(): number;
@@ -2756,7 +2759,7 @@ declare class Caching {
2756
2759
  static readonly materialCache: SimpleCache<CacheKey, Material>;
2757
2760
  static readonly boxMeshCache: SimpleCache<CacheKey, Mesh>;
2758
2761
  static readonly textureAssetCache: AsyncLoadingCache<CacheKey, TextureAsset>;
2759
- static readonly textureMetaCache: AsyncLoadingCache<CacheKey, MinecraftTextureMeta>;
2762
+ static readonly textureMetaCache: AsyncLoadingCache<CacheKey, MinecraftTextureMeta | typeof Caching.MISSING>;
2760
2763
  static readonly rawModelCache: AsyncLoadingCache<CacheKey, Model>;
2761
2764
  static readonly mergedModelCache: AsyncLoadingCache<CacheKey, Model>;
2762
2765
  static readonly modelTextureAtlasCache: AsyncLoadingCache<CacheKey, TextureAtlas>;
@@ -2764,7 +2767,7 @@ declare class Caching {
2764
2767
  static readonly listAssetCache: AsyncLoadingCache<CacheKey, ListAsset>;
2765
2768
  static readonly blockTintCache: AsyncLoadingCache<CacheKey, number>;
2766
2769
  static readonly entityModelCache: AsyncLoadingCache<CacheKey, EntityModelFile>;
2767
- static readonly entityTextureCache: AsyncLoadingCache<CacheKey, AssetKey>;
2770
+ static readonly entityTextureCache: AsyncLoadingCache<CacheKey, AssetKey | typeof Caching.MISSING>;
2768
2771
  static readonly entityAnimationCache: AsyncLoadingCache<CacheKey, EntityAnimationFile>;
2769
2772
  static readonly blockEntityIndexCache: AsyncLoadingCache<CacheKey, BlockEntityIndex>;
2770
2773
  static readonly entityDatasetVersionCache: AsyncLoadingCache<CacheKey, string>;
@@ -4459,6 +4462,7 @@ declare function registerNodeEnv(): NodeEnv;
4459
4462
  */
4460
4463
  declare class NodeCache extends PersistentCache<LocalStorage> {
4461
4464
  private initialized;
4465
+ private readonly pendingWrites;
4462
4466
  constructor(backing: LocalStorage);
4463
4467
  private ready;
4464
4468
  get<T>(key: string): Promise<T>;
@@ -1794,6 +1794,7 @@ declare class BlockObject extends SceneObject {
1794
1794
  */
1795
1795
  private createBlockEntities;
1796
1796
  private placeEntities;
1797
+ private placeEntity;
1797
1798
  get isOccluding(): boolean;
1798
1799
  private getModelMatrix;
1799
1800
  private getModelCullMask;
@@ -2744,6 +2745,8 @@ interface UnihexFile {
2744
2745
 
2745
2746
  /** Shared in-memory caches for loaded assets and render resources. Persistent stores are managed separately. */
2746
2747
  declare class Caching {
2748
+ /** Cached in place of a missing asset. The caches drop `undefined` results, which would request the asset again. */
2749
+ static readonly MISSING: false;
2747
2750
  private static _generation;
2748
2751
  /** Changes when shared assets are cleared, so derived caches can discard their old values. */
2749
2752
  static get generation(): number;
@@ -2756,7 +2759,7 @@ declare class Caching {
2756
2759
  static readonly materialCache: SimpleCache<CacheKey, Material>;
2757
2760
  static readonly boxMeshCache: SimpleCache<CacheKey, Mesh>;
2758
2761
  static readonly textureAssetCache: AsyncLoadingCache<CacheKey, TextureAsset>;
2759
- static readonly textureMetaCache: AsyncLoadingCache<CacheKey, MinecraftTextureMeta>;
2762
+ static readonly textureMetaCache: AsyncLoadingCache<CacheKey, MinecraftTextureMeta | typeof Caching.MISSING>;
2760
2763
  static readonly rawModelCache: AsyncLoadingCache<CacheKey, Model>;
2761
2764
  static readonly mergedModelCache: AsyncLoadingCache<CacheKey, Model>;
2762
2765
  static readonly modelTextureAtlasCache: AsyncLoadingCache<CacheKey, TextureAtlas>;
@@ -2764,7 +2767,7 @@ declare class Caching {
2764
2767
  static readonly listAssetCache: AsyncLoadingCache<CacheKey, ListAsset>;
2765
2768
  static readonly blockTintCache: AsyncLoadingCache<CacheKey, number>;
2766
2769
  static readonly entityModelCache: AsyncLoadingCache<CacheKey, EntityModelFile>;
2767
- static readonly entityTextureCache: AsyncLoadingCache<CacheKey, AssetKey>;
2770
+ static readonly entityTextureCache: AsyncLoadingCache<CacheKey, AssetKey | typeof Caching.MISSING>;
2768
2771
  static readonly entityAnimationCache: AsyncLoadingCache<CacheKey, EntityAnimationFile>;
2769
2772
  static readonly blockEntityIndexCache: AsyncLoadingCache<CacheKey, BlockEntityIndex>;
2770
2773
  static readonly entityDatasetVersionCache: AsyncLoadingCache<CacheKey, string>;
@@ -4459,6 +4462,7 @@ declare function registerNodeEnv(): NodeEnv;
4459
4462
  */
4460
4463
  declare class NodeCache extends PersistentCache<LocalStorage> {
4461
4464
  private initialized;
4465
+ private readonly pendingWrites;
4462
4466
  constructor(backing: LocalStorage);
4463
4467
  private ready;
4464
4468
  get<T>(key: string): Promise<T>;
@@ -241,6 +241,10 @@ var init_Caching = __esm({
241
241
  import_loading_cache = require("@inventivetalent/loading-cache");
242
242
  import_time = require("@inventivetalent/time");
243
243
  Caching = class _Caching {
244
+ static {
245
+ /** Cached in place of a missing asset. The caches drop `undefined` results, which would request the asset again. */
246
+ this.MISSING = false;
247
+ }
244
248
  static {
245
249
  this._generation = 0;
246
250
  }
@@ -2406,15 +2410,21 @@ var init_ModelTextures = __esm({
2406
2410
  key.extension += ".mcmeta";
2407
2411
  }
2408
2412
  const keyStr = key.serialize();
2409
- return Caching.textureMetaCache.get(keyStr, (k) => {
2410
- return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
2411
- return AssetLoader.get(key, "meta" /* META */).then((asset2) => {
2412
- if (asset2)
2413
- asset2.key = key;
2414
- return asset2;
2415
- });
2413
+ const meta = await Caching.textureMetaCache.get(keyStr, (k) => {
2414
+ return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), async (k1) => {
2415
+ if (AssetLoader.persistentScope === "") {
2416
+ const path = key.getFullPath();
2417
+ const slash = path.lastIndexOf("/");
2418
+ const listKey = new AssetKey(key.namespace, `${path.slice(0, slash + 1)}_list`, "textures", void 0, "assets", ".json", key.root);
2419
+ const list2 = await Caching.listAssetCache.get(listKey.serialize(), () => AssetLoader.get(listKey, "list" /* LIST */)).catch(() => void 0);
2420
+ if (list2 && !list2.files.includes(`${path.slice(slash + 1)}${key.extension}`)) return Caching.MISSING;
2421
+ }
2422
+ const asset2 = await AssetLoader.get(key, "meta" /* META */);
2423
+ if (asset2) asset2.key = key;
2424
+ return asset2 ?? Caching.MISSING;
2416
2425
  });
2417
2426
  });
2427
+ return meta === Caching.MISSING ? void 0 : meta;
2418
2428
  }
2419
2429
  /** Clears persisted texture metadata. Use {@link Caching.clear} to discard in-memory textures and metadata. */
2420
2430
  static async clearCache() {
@@ -4660,26 +4670,27 @@ var init_Entities = __esm({
4660
4670
  const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
4661
4671
  const root = isAssetKey(modelKey) ? modelKey.root : void 0;
4662
4672
  const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", root);
4663
- return Caching.entityTextureCache.get(key.serialize(), async () => {
4673
+ const texture = await Caching.entityTextureCache.get(key.serialize(), async () => {
4664
4674
  const name = path.split("/").pop();
4665
4675
  for (const candidate of [path, `${path}/${name}`]) {
4666
- const texture2 = new AssetKey(modelKey.namespace, candidate, "textures", "entity", "assets", ".png", root);
4667
- if (await ModelTextures.get(texture2)) return texture2;
4676
+ const texture3 = new AssetKey(modelKey.namespace, candidate, "textures", "entity", "assets", ".png", root);
4677
+ if (await ModelTextures.get(texture3)) return texture3;
4668
4678
  }
4669
4679
  const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json", root);
4670
4680
  const list2 = await AssetLoader.get(listKey, "list" /* LIST */);
4671
4681
  const files = list2?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
4672
4682
  const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
4673
- if (!file) return void 0;
4683
+ if (!file) return Caching.MISSING;
4674
4684
  const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json", root);
4675
4685
  const variant = await AssetLoader.get(variantKey, "json" /* JSON */);
4676
4686
  const assets = variant?.assets;
4677
4687
  const textureId = variant?.asset_id ?? (typeof assets?.wild === "string" ? assets.wild : Object.values(assets ?? {}).find((value) => typeof value === "string"));
4678
- if (typeof textureId !== "string") return void 0;
4679
- const texture = AssetKey.parse("textures", textureId);
4680
- texture.root = root;
4681
- return texture;
4688
+ if (typeof textureId !== "string") return Caching.MISSING;
4689
+ const texture2 = AssetKey.parse("textures", textureId);
4690
+ texture2.root = root;
4691
+ return texture2;
4682
4692
  });
4693
+ return texture === Caching.MISSING ? void 0 : texture;
4683
4694
  }
4684
4695
  /** @deprecated Use getEntityList(); block entities share the entity dataset. */
4685
4696
  static getBlockList() {
@@ -9472,6 +9483,10 @@ var init_SkinTextures = __esm({
9472
9483
  });
9473
9484
 
9474
9485
  // src/skin/PlayerHeadTextures.ts
9486
+ var PlayerHeadTextures_exports = {};
9487
+ __export(PlayerHeadTextures_exports, {
9488
+ PlayerHeadTextures: () => PlayerHeadTextures
9489
+ });
9475
9490
  var PlayerHeadTextures;
9476
9491
  var init_PlayerHeadTextures = __esm({
9477
9492
  "src/skin/PlayerHeadTextures.ts"() {
@@ -11203,17 +11218,25 @@ var init_BlockObject = __esm({
11203
11218
  if (!key || this.options.displayPosition) return false;
11204
11219
  const generation = this._entityGeneration;
11205
11220
  const created = [];
11221
+ const placement = new import_three34.Matrix4();
11206
11222
  let resolved;
11207
11223
  try {
11208
11224
  resolved = BlockEntities.resolve(await BlockEntities.getIndex(key.root), key.toNamespacedString(), this.state);
11209
11225
  if (!resolved) return false;
11226
+ BlockEntities.matrix(resolved, placement);
11210
11227
  for (const part of resolved.parts) {
11211
11228
  const [namespace, path] = part.model.includes(":") ? part.model.split(":") : [key.namespace, part.model];
11212
- const texture = part.textureLocation === void 0 ? void 0 : AssetKey.parse("textures", part.textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
11229
+ let texture = part.textureLocation === void 0 ? void 0 : AssetKey.parse("textures", part.textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
11230
+ if (part.textureLocation === void 0 && namespace === "minecraft" && path === "player_head") {
11231
+ const { PlayerHeadTextures: PlayerHeadTextures2 } = await Promise.resolve().then(() => (init_PlayerHeadTextures(), PlayerHeadTextures_exports));
11232
+ texture = (await PlayerHeadTextures2.get(void 0, key.root)).texture;
11233
+ }
11213
11234
  if (texture) texture.root = key.root;
11214
11235
  const entity = await Entities.getEntity(new BasicAssetKey(namespace, path), texture, { layer: part.layer });
11215
11236
  if (!entity) throw new MineRenderError(`Missing entity model ${part.model}`);
11216
- created.push(await this.scene.addEntity(entity, { wireframe: this.options.wireframe }));
11237
+ const object4 = await this.scene.addEntity(entity, { wireframe: this.options.wireframe });
11238
+ this.placeEntity(object4, placement);
11239
+ created.push(object4);
11217
11240
  }
11218
11241
  } catch (error) {
11219
11242
  log15.warn(`Could not draw block entity ${key.toNamespacedString()}, using its block model`, error);
@@ -11224,18 +11247,21 @@ var init_BlockObject = __esm({
11224
11247
  this.removeEntities(created);
11225
11248
  return true;
11226
11249
  }
11227
- BlockEntities.matrix(resolved, this._entityPlacement);
11250
+ this._entityPlacement.copy(placement);
11228
11251
  this._entities = created;
11229
11252
  this.placeEntities();
11230
11253
  this.setVisible(this.visible);
11231
11254
  return true;
11232
11255
  }
11233
11256
  placeEntities() {
11234
- const matrix = new import_three34.Matrix4().makeTranslation(this.position.x - 8, this.position.y - 8, this.position.z - 8).multiply(this._entityPlacement);
11235
11257
  for (const entity of this._entities) {
11236
- matrix.decompose(entity.position, entity.quaternion, entity.scale);
11258
+ this.placeEntity(entity, this._entityPlacement);
11237
11259
  }
11238
11260
  }
11261
+ placeEntity(entity, placement) {
11262
+ const matrix = new import_three34.Matrix4().makeTranslation(this.position.x - 8, this.position.y - 8, this.position.z - 8).multiply(placement);
11263
+ matrix.decompose(entity.position, entity.quaternion, entity.scale);
11264
+ }
11239
11265
  get isOccluding() {
11240
11266
  if (!this.visible) {
11241
11267
  return false;
@@ -11750,6 +11776,7 @@ init_PersistentCache();
11750
11776
  var NodeCache = class extends PersistentCache {
11751
11777
  constructor(backing) {
11752
11778
  super(backing);
11779
+ this.pendingWrites = /* @__PURE__ */ new Map();
11753
11780
  }
11754
11781
  ready() {
11755
11782
  return this.initialized ??= this.backing.init();
@@ -11760,7 +11787,14 @@ var NodeCache = class extends PersistentCache {
11760
11787
  }
11761
11788
  async put(key, value) {
11762
11789
  await this.ready();
11763
- return this.backing.setItem(key, value).then((res) => res.content);
11790
+ const previous = this.pendingWrites.get(key);
11791
+ const write = (previous ? previous.catch(() => void 0) : Promise.resolve()).then(() => this.backing.setItem(key, value)).then(() => value);
11792
+ this.pendingWrites.set(key, write);
11793
+ try {
11794
+ return await write;
11795
+ } finally {
11796
+ if (this.pendingWrites.get(key) === write) this.pendingWrites.delete(key);
11797
+ }
11764
11798
  }
11765
11799
  async delete(key) {
11766
11800
  await this.ready();
@@ -11806,7 +11840,10 @@ var NodeEnv = class {
11806
11840
  openCache(name, version2) {
11807
11841
  return new NodeCache(import_node_persist.default.create({
11808
11842
  dir: name + version2,
11809
- encoding: "utf8"
11843
+ encoding: "utf8",
11844
+ // node-persist's unref'd one-second write queue delays loads and lets Node exit before writes finish.
11845
+ // NodeCache serializes writes to each key while allowing different files to write concurrently.
11846
+ writeQueue: false
11810
11847
  }));
11811
11848
  }
11812
11849
  };