minerender 2.1.0-alpha.61 → 2.1.0-alpha.62

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/bundle.js CHANGED
@@ -78923,11 +78923,11 @@ ${key}` : key;
78923
78923
  return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
78924
78924
  }
78925
78925
  /**
78926
- * Vanilla's keyframe animations of a model by name, or undefined when the model or the selected version has none.
78926
+ * Native and sampled vanilla clips by name, or undefined when the model or selected version has none.
78927
78927
  */
78928
78928
  static async getAnimations(modelKey) {
78929
78929
  const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
78930
- const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json");
78930
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
78931
78931
  const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
78932
78932
  return file?.animations;
78933
78933
  }
@@ -78977,7 +78977,7 @@ ${key}` : key;
78977
78977
  let low = 0, high = keyframes.length;
78978
78978
  while (low < high) {
78979
78979
  const middle = low + high >>> 1;
78980
- if (time <= keyframes[middle].time) high = middle;
78980
+ if (time < keyframes[middle].time) high = middle;
78981
78981
  else low = middle + 1;
78982
78982
  }
78983
78983
  const a4 = Math.max(0, low - 1);
@@ -79025,6 +79025,7 @@ ${key}` : key;
79025
79025
  init_dirname();
79026
79026
  init_buffer2();
79027
79027
  init_process2();
79028
+ init_three_module();
79028
79029
  init_EntityAnimation();
79029
79030
  ZERO = [0, 0, 0];
79030
79031
  EntityAnimationPlayer = class {
@@ -79041,25 +79042,45 @@ ${key}` : key;
79041
79042
  return this._time;
79042
79043
  }
79043
79044
  /**
79044
- * Starts an animation on the named parts below each layer root. The current pose of a part becomes its default;
79045
- * bones without a matching part are skipped.
79045
+ * Starts an animation on matching named parts. Supplied baked poses are the baseline for offsets;
79046
+ * without them, the current pose is used. Stopping restores the pose from before playback.
79046
79047
  */
79047
- play(layers, animation, options = {}) {
79048
+ play(layers, animation, options = {}, poses) {
79048
79049
  this.stop();
79049
79050
  this._animation = animation;
79050
79051
  this._time = options.time ?? 0;
79051
79052
  this.loop = options.loop ?? animation.loop;
79052
79053
  this.speed = options.speed ?? 1;
79053
79054
  for (const layer of layers) {
79054
- for (const bone of Object.keys(animation.bones)) {
79055
- const object = layer.getObjectByName(`group:${bone}`);
79056
- if (!object) continue;
79057
- this.parts.push({ bone, object, position: object.position.clone(), rotation: object.rotation.clone(), scale: object.scale.clone() });
79055
+ const objects = [];
79056
+ if (poses) {
79057
+ layer.traverse((object) => {
79058
+ if (poses.has(object)) objects.push(object);
79059
+ });
79060
+ } else {
79061
+ for (const bone of Object.keys(animation.bones)) {
79062
+ const object = layer.getObjectByName(`group:${bone}`);
79063
+ if (object) objects.push(object);
79064
+ }
79065
+ }
79066
+ for (const object of objects) {
79067
+ const bone = object.name.slice("group:".length);
79068
+ const pose = poses?.get(object);
79069
+ this.parts.push({
79070
+ bone,
79071
+ object,
79072
+ position: object.position.clone(),
79073
+ rotation: object.rotation.clone(),
79074
+ scale: object.scale.clone(),
79075
+ basePosition: pose ? new Vector3(...pose.offset) : object.position.clone(),
79076
+ baseRotation: pose ? new Euler(...pose.rotation, "ZYX") : object.rotation.clone(),
79077
+ baseScale: pose ? new Vector3(...pose.scale ?? [1, 1, 1]) : object.scale.clone()
79078
+ });
79058
79079
  }
79059
79080
  }
79060
79081
  this.apply();
79061
79082
  }
79062
- /** Restores the default poses. Returns whether an animation was active. */
79083
+ /** Restores the poses from before playback. Returns whether an animation was active. */
79063
79084
  stop() {
79064
79085
  if (!this._animation) return false;
79065
79086
  for (const part of this.parts) {
@@ -79088,10 +79109,10 @@ ${key}` : key;
79088
79109
  apply() {
79089
79110
  const pose = sampleEntityAnimation(this._animation, this._time, this.loop);
79090
79111
  for (const part of this.parts) {
79091
- const { position = ZERO, rotation = ZERO, scale = ZERO } = pose[part.bone];
79092
- part.object.position.set(part.position.x + position[0], part.position.y + position[1], part.position.z + position[2]);
79093
- part.object.rotation.set(part.rotation.x + rotation[0], part.rotation.y + rotation[1], part.rotation.z + rotation[2], part.rotation.order);
79094
- part.object.scale.set(part.scale.x + scale[0], part.scale.y + scale[1], part.scale.z + scale[2]);
79112
+ const { position = ZERO, rotation = ZERO, scale = ZERO } = pose[part.bone] ?? {};
79113
+ part.object.position.set(part.basePosition.x + position[0], part.basePosition.y + position[1], part.basePosition.z + position[2]);
79114
+ part.object.rotation.set(part.baseRotation.x + rotation[0], part.baseRotation.y + rotation[1], part.baseRotation.z + rotation[2], part.baseRotation.order);
79115
+ part.object.scale.set(part.baseScale.x + scale[0], part.baseScale.y + scale[1], part.baseScale.z + scale[2]);
79095
79116
  }
79096
79117
  }
79097
79118
  };
@@ -79634,7 +79655,8 @@ ${key}` : key;
79634
79655
  this.scrollMaterials = [];
79635
79656
  /** Entity age in ticks, as vanilla's `ageInTicks`; drives the scrolling render modes. */
79636
79657
  this.age = 0;
79637
- this.animationPlayer = new EntityAnimationPlayer();
79658
+ this.animationPlayers = [];
79659
+ this.partPoses = /* @__PURE__ */ new Map();
79638
79660
  this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
79639
79661
  this.addEventListener("added", () => this.updateScrollSubscription());
79640
79662
  this.addEventListener("removed", () => this.updateScrollSubscription());
@@ -79651,7 +79673,8 @@ ${key}` : key;
79651
79673
  for (const geometry of this.geometries) geometry.dispose();
79652
79674
  this.geometries.clear();
79653
79675
  for (const dispose of this.disposeWireframes.splice(0)) dispose();
79654
- this.animationPlayer.clear();
79676
+ for (const player of this.animationPlayers.splice(0)) player.clear();
79677
+ this.partPoses.clear();
79655
79678
  super.disposeAndRemoveAllChildren();
79656
79679
  }
79657
79680
  clearScrollMaterials() {
@@ -79683,36 +79706,61 @@ ${key}` : key;
79683
79706
  this.notifyDirty();
79684
79707
  }
79685
79708
  //<editor-fold desc="ANIMATION">
79686
- /** The animation started by {@link playAnimation}, until {@link stopAnimation} or disposal. */
79709
+ /** The first active clip, until playback is stopped or the object is disposed. */
79687
79710
  get animation() {
79688
- return this.animationPlayer.animation;
79711
+ return this.animationPlayers[0]?.animation;
79712
+ }
79713
+ /** Clips playing together, each targeting a separate geometry layer. */
79714
+ get activeAnimations() {
79715
+ return this.animationPlayers.map((player) => player.animation);
79689
79716
  }
79690
79717
  /** Seconds since the animation started, before looping. */
79691
79718
  get animationTime() {
79692
- return this.animationPlayer.time;
79719
+ return this.animationPlayers[0]?.time ?? 0;
79693
79720
  }
79694
79721
  /**
79695
- * Poses the object from a keyframe animation of {@link Entities.getAnimations}, replacing the current one.
79696
- * Parts of every layer are matched by name and their current pose is the default the offsets add to.
79722
+ * Plays a clip from {@link Entities.getAnimations}, replacing all active clips.
79723
+ * Offsets apply to the baked pose in the clip's layer (`main` by default), including repeated draws of that layer.
79697
79724
  * The object owns no clock: call {@link advanceAnimation} per frame, or {@link setAnimationTime}.
79698
79725
  */
79699
79726
  playAnimation(animation, options) {
79727
+ this.playAnimations([animation], options);
79728
+ }
79729
+ /** Plays one clip per selected geometry layer, with a shared clock and no blending between clips. */
79730
+ playAnimations(animations, options) {
79731
+ const targets = /* @__PURE__ */ new Set();
79732
+ const selections = animations.map((animation) => {
79733
+ const layer = animation.layer ?? "main";
79734
+ if (targets.has(layer)) throw new Error(`Multiple animations target layer "${layer}"`);
79735
+ targets.add(layer);
79736
+ const names = Object.keys(this.entityLayers).filter((name2) => name2.split("#")[0] === layer);
79737
+ if (!names.length) throw new Error(`Entity ${this.entity.id} has no selected animation layer "${layer}"`);
79738
+ return { animation, names };
79739
+ });
79700
79740
  this.createMeshes();
79701
- const layers = Object.keys(this.entityLayers).map((name2) => this.getLayerGroup(name2)).filter((layer) => !!layer);
79702
- this.animationPlayer.play(layers, animation, options);
79741
+ this.stopAnimation();
79742
+ for (const { animation, names } of selections) {
79743
+ const player = new EntityAnimationPlayer();
79744
+ player.play(names.map((name2) => this.getLayerGroup(name2)), animation, options, this.partPoses);
79745
+ this.animationPlayers.push(player);
79746
+ }
79703
79747
  this.notifyDirty();
79704
79748
  }
79705
- /** Stops the animation and restores the default pose. */
79749
+ /** Stops all clips and restores the poses from before playback. */
79706
79750
  stopAnimation() {
79707
- if (this.animationPlayer.stop()) this.notifyDirty();
79751
+ const players = this.animationPlayers.splice(0);
79752
+ for (const player of players) player.stop();
79753
+ if (players.length) this.notifyDirty();
79708
79754
  }
79709
79755
  /** Poses the object at an explicit time in seconds. Has no effect without an animation. */
79710
79756
  setAnimationTime(seconds) {
79711
- if (this.animationPlayer.setTime(seconds)) this.notifyDirty();
79757
+ for (const player of this.animationPlayers) player.setTime(seconds);
79758
+ if (this.animationPlayers.length) this.notifyDirty();
79712
79759
  }
79713
79760
  /** Advances the animation by a frame delta in seconds, scaled by its speed. Has no effect without an animation. */
79714
79761
  advanceAnimation(deltaSeconds) {
79715
- if (this.animationPlayer.advance(deltaSeconds)) this.notifyDirty();
79762
+ for (const player of this.animationPlayers) player.advance(deltaSeconds);
79763
+ if (this.animationPlayers.length) this.notifyDirty();
79716
79764
  }
79717
79765
  //</editor-fold>
79718
79766
  getLayerGroup(name2) {
@@ -79772,6 +79820,7 @@ ${key}` : key;
79772
79820
  anchor.position.fromArray(part.pose.offset);
79773
79821
  anchor.rotation.set(...part.pose.rotation, "ZYX");
79774
79822
  anchor.scale.fromArray(part.pose.scale ?? [1, 1, 1]);
79823
+ this.partPoses.set(anchor, part.pose);
79775
79824
  parent.add(anchor);
79776
79825
  const size = part.texture ?? textureSize;
79777
79826
  for (const cube of part.cubes) {