BetterModel provides a powerful animation system that supports looping, single-play animations, speed control, blending, and per-player animation states.
public enum Type { LOOP, // Loop indefinitely PLAY_ONCE, // Play once and stop HOLD // Play once and hold the last frame}
Example usage:
// Loop continuouslyAnimationModifier looping = AnimationModifier.builder() .type(AnimationIterator.Type.LOOP) .build();// Play onceAnimationModifier once = AnimationModifier.builder() .type(AnimationIterator.Type.PLAY_ONCE) .build();// Hold last frameAnimationModifier hold = AnimationModifier.builder() .type(AnimationIterator.Type.HOLD) .build();
AnimationModifier conditional = AnimationModifier.builder() .predicate(() -> entity.isOnGround()) // Only play when on ground .build();tracker.animate("walk", conditional);
// Stop on all bonesboolean stopped = tracker.stopAnimation("walk");// Stop on specific bonestracker.stopAnimation( bone -> bone.name().toString().contains("arm"), "attack");
import kr.toxicity.model.api.platform.PlatformPlayer;PlatformPlayer player = BukkitAdapter.adapt(bukkitPlayer);tracker.stopAnimation( bone -> true, "custom_animation", player);
Use the player() modifier to target specific players:
import org.bukkit.entity.Player;Player targetPlayer = // the player who should see this animationAnimationModifier perPlayer = AnimationModifier.builder() .player(BukkitAdapter.adapt(targetPlayer)) .type(AnimationIterator.Type.PLAY_ONCE) .build();tracker.animate("wave", perPlayer);
// The "spawn" animation plays automatically if definedDummyTracker tracker = BetterModel.model("npc") .map(r -> r.create(BukkitAdapter.adapt(location))) .orElse(null);// Built-in animations are played via TrackerBuiltInAnimationimport kr.toxicity.model.api.tracker.TrackerBuiltInAnimation;// You can also manually trigger built-in animationsTrackerBuiltInAnimation.play(tracker);
import kr.toxicity.model.api.data.blueprint.BlueprintAnimation;tracker.renderer().animation("wave_arm").ifPresent(animation -> { // This animation will only affect bones it's designed for tracker.animate(animation, AnimationModifier.DEFAULT);});
// Access bones to check animationstracker.bones().forEach(bone -> { System.out.println("Bone: " + bone.name()); // Check animation state via bone methods});