Skip to main content
BlueprintAnimation represents a fully processed animation for a BetterModel, including all keyframes, loop settings, and associated scripts.

Package

kr.toxicity.model.api.data.blueprint.BlueprintAnimation

Record Components

ComponentTypeDescription
nameStringThe unique name of the animation
loopAnimationIterator.TypeThe default loop mode
lengthfloatThe length of the animation in seconds
overridebooleanWhether this animation overrides other animations
animatorMap<BoneName, BlueprintAnimator>Map of animators for each bone
scriptBlueprintScriptAssociated script (nullable)
emptyAnimatorTimedStorage<AnimationProgress>Empty movements used as fallback
Since: 1.15.2

Methods

script(AnimationModifier)

public @Nullable BlueprintScript script(@NotNull AnimationModifier modifier)
Retrieves the script for this animation, considering the provided modifier. If the modifier overrides the animation or specifies a player, the script may be suppressed. Parameters:
  • modifier - The animation modifier to consider
Returns: The script, or null if suppressed Since: 1.15.2

emptyIterator(AnimationIterator.Type)

public @NotNull AnimationIterator<AnimationProgress> emptyIterator(
    @NotNull AnimationIterator.Type type
)
Creates an iterator for the empty animation sequence. Parameters:
  • type - The loop type for the iterator
Returns: An animation iterator Since: 1.15.2

Usage Examples

Accessing Animation Data

BlueprintAnimation animation = blueprint.getAnimation("walk");

String name = animation.name();
float duration = animation.length();
AnimationIterator.Type loopType = animation.loop();
boolean canOverride = animation.override();

Getting Bone Animators

BlueprintAnimation animation = blueprint.getAnimation("attack");

// Get animator for specific bone
BoneName rightArm = BoneName.of("rightArm");
BlueprintAnimator armAnimator = animation.animator().get(rightArm);

if (armAnimator != null) {
    // Apply animation to bone
    applyAnimator(rightArm, armAnimator);
}

Iterating All Bone Animations

BlueprintAnimation animation = blueprint.getAnimation("dance");

animation.animator().forEach((boneName, animator) -> {
    System.out.println("Animating bone: " + boneName);
    // Apply animator to bone
});

Script Execution with Modifier

BlueprintAnimation animation = blueprint.getAnimation("special_attack");

// Default modifier - script will run
AnimationModifier defaultModifier = AnimationModifier.DEFAULT;
BlueprintScript script = animation.script(defaultModifier);
if (script != null) {
    script.execute();
}

// Override modifier - script may be suppressed
AnimationModifier overrideModifier = AnimationModifier.builder()
    .override(true)
    .build();
BlueprintScript suppressedScript = animation.script(overrideModifier);
// May be null due to override

Player-Specific Animation

BlueprintAnimation animation = blueprint.getAnimation("emote");
PlatformPlayer player = getPlayer();

// When player is specified, script is suppressed
AnimationModifier playerModifier = AnimationModifier.builder()
    .player(player)
    .build();

BlueprintScript script = animation.script(playerModifier);
// Will be null because player is specified

Creating Empty Iterator

BlueprintAnimation animation = blueprint.getAnimation("idle");

// Create iterator for empty animation (fallback)
AnimationIterator<AnimationProgress> emptyIter = 
    animation.emptyIterator(AnimationIterator.Type.LOOP);

while (emptyIter.hasNext()) {
    AnimationProgress progress = emptyIter.next();
    // Apply empty/neutral animation
}

Animation Duration and Loop

BlueprintAnimation animation = blueprint.getAnimation("run");

float lengthSeconds = animation.length();
int lengthTicks = (int) (lengthSeconds * 20); // Convert to ticks

if (animation.loop() == AnimationIterator.Type.LOOP) {
    System.out.println("Animation loops every " + lengthSeconds + " seconds");
} else if (animation.loop() == AnimationIterator.Type.PLAY_ONCE) {
    System.out.println("Animation plays once for " + lengthSeconds + " seconds");
}

Applying Animation to Model

public void playAnimation(ModelInstance model, String animationName) {
    BlueprintAnimation animation = model.getBlueprint().getAnimation(animationName);
    
    if (animation == null) {
        System.err.println("Animation not found: " + animationName);
        return;
    }
    
    // Apply each bone animator
    animation.animator().forEach((boneName, animator) -> {
        ModelBone bone = model.getBone(boneName);
        if (bone != null) {
            bone.setAnimator(animator);
        }
    });
    
    // Execute associated script
    AnimationModifier modifier = AnimationModifier.DEFAULT;
    BlueprintScript script = animation.script(modifier);
    if (script != null) {
        script.execute();
    }
}

Checking Animation Properties

BlueprintAnimation animation = blueprint.getAnimation("jump");

// Check if animation has a script
if (animation.script() != null) {
    System.out.println("Animation has associated script");
}

// Check override behavior
if (animation.override()) {
    System.out.println("This animation will override others");
}

// Check bone count
int boneCount = animation.animator().size();
System.out.println("Animation affects " + boneCount + " bones");

Animation Blending Setup

BlueprintAnimation fromAnim = blueprint.getAnimation("walk");
BlueprintAnimation toAnim = blueprint.getAnimation("run");

// Create modifier with lerp timing for smooth transition
AnimationModifier blendModifier = AnimationModifier.builder()
    .start(10)  // 10 tick blend-in
    .end(10)    // 10 tick blend-out
    .type(toAnim.loop())
    .build();

// Apply with blending
model.startAnimation(toAnim.name(), blendModifier);

See Also

Build docs developers (and LLMs) love