Skip to content

API ‐ Extensible Animations Events

Sleys edited this page Sep 22, 2026 · 3 revisions

The Animation Event system is fully extensible.

Third-party mods may register custom animation events, allowing animations to execute arbitrary logic at specific moments during playback.

Every animation event consists of three parts:

  • An event parameter record.
  • An event type.
  • A registry entry.

🧩 Architecture

ExtendedDatapacksRegistry
          │
          ▼
 IAnimationEventType
          │
          ▼
    paramsCodec()
          │
          ▼
IAnimationEventParams
          │
          ▼
       execute(...)
          │
          ▼
   Animation Timeline

The registry serializes event types using DFU (Codec), while event parameters are decoded through the MapCodec supplied by each registered type.


📦 Step 1 — Create the Event Record

Every event is represented by a parameter record.

The record contains both:

  • The serialized configuration.
  • The execution logic.

Third-party events must implement:

IAnimationExternalEventParams

which is the non-sealed extension point of:

IAnimationEventParams

Example

public record ExampleEvent(Float radius, String joint)
        implements IAnimationExternalEventParams {

    public static final MapCodec<ExampleEvent> CODEC =
        RecordCodecBuilder.mapCodec(instance ->
            instance.group(
                Codec.FLOAT.fieldOf("radius")
                    .forGetter(ExampleEvent::radius),

                Codec.STRING.fieldOf("joint")
                    .forGetter(ExampleEvent::joint)
            ).apply(instance, ExampleEvent::new)
        );

    @Override
    public <T extends StaticAnimation> void execute(
            AssetAccessor<T> accessor,
            LivingEntityPatch<?> patch) {

        // Custom event logic
    }
}

The execute() method is invoked automatically whenever the animation reaches the configured event time.


📦 Step 2 — Create the Event Type

Every event type exposes the codec responsible for decoding its parameter object.

Implement:

IAnimationEventType

Example

public enum ExampleAnimationEvents
        implements IAnimationEventType {

    EXAMPLE(ExampleEvent.CODEC);

    private final MapCodec<? extends IAnimationEventParams> codec;

    ExampleAnimationEvents(
            MapCodec<? extends IAnimationEventParams> codec) {
        this.codec = codec;
    }

    @Override
    public MapCodec<? extends IAnimationEventParams> paramsCodec() {
        return codec;
    }
}

Each enum constant represents one animation event.


📦 Step 3 — Register the Event Type

Animation event types are registered through the centralized:

ExtendedDatapacksRegistry

Use the ANIMATIONS_EVENTS registry entry:

ExtendedDatapacksRegistry.ANIMATIONS_EVENTS.register(
        MOD_ID,
        ExampleAnimationEvents.class
);

Multiple event enums can also be registered in a single call:

ExtendedDatapacksRegistry.ANIMATIONS_EVENTS.register(
        MOD_ID,
        CombatAnimationEvents.class,
        SoundAnimationEvents.class,
        ExampleAnimationEvents.class
);

The registry automatically verifies that each supplied enum implements:

IAnimationEventType

Invalid classes are rejected and a warning is emitted to the log.

Every enum constant becomes an available animation event.

The generated identifier follows the format:

<modid>:<enum_name>

For example:

example_mod:example

📄 Datapack Usage

Once registered, the event can immediately be used inside animation JSON.

{
  "in_time_events": [
    {
      "type": "example_mod:example",
      "side": "server",
      "start": 0.75,
      "params": {
        "radius": 4.0,
        "joint": "Tool_R"
      }
    }
  ]
}

The params object is automatically decoded using the MapCodec supplied by the registered event type.


⚙️ Registration Lifecycle

Animation events must be registered before Extended Datapacks initializes and consumes its animation registries.

Attempting to register additional events after the registry has been consumed will throw:

RegistryObjectException

This restriction exists because the available animation event types are resolved while the animation codecs are being initialized.

For example, registration should occur during mod initialization:

private static void registerAnimationEvents() {
    ExtendedDatapacksRegistry.ANIMATIONS_EVENTS.register(
            MOD_ID,
            ExampleAnimationEvents.class
    );
}

🔄 Serialization

The animation event registry internally uses DFU:

Codec<IAnimationEventType>

Every registered event provides its own:

MapCodec<? extends IAnimationEventParams>

allowing each event to define its own JSON structure independently.

The centralized ExtendedDatapacksRegistry handles routing the registration to the underlying animation event registry.


🧱 Complete Example

A minimal external animation event therefore consists of:

1. Event parameter record

public record ExampleEvent(Float radius, String joint)
        implements IAnimationExternalEventParams {

    public static final MapCodec<ExampleEvent> CODEC =
        RecordCodecBuilder.mapCodec(instance ->
            instance.group(
                Codec.FLOAT.fieldOf("radius")
                    .forGetter(ExampleEvent::radius),

                Codec.STRING.fieldOf("joint")
                    .forGetter(ExampleEvent::joint)
            ).apply(instance, ExampleEvent::new)
        );

    @Override
    public <T extends StaticAnimation> void execute(
            AssetAccessor<T> accessor,
            LivingEntityPatch<?> patch) {

        // Custom event logic
    }
}

2. Event type

public enum ExampleAnimationEvents
        implements IAnimationEventType {

    EXAMPLE(ExampleEvent.CODEC);

    private final MapCodec<? extends IAnimationEventParams> codec;

    ExampleAnimationEvents(
            MapCodec<? extends IAnimationEventParams> codec) {
        this.codec = codec;
    }

    @Override
    public MapCodec<? extends IAnimationEventParams> paramsCodec() {
        return codec;
    }
}

3. Registration

ExtendedDatapacksRegistry.ANIMATIONS_EVENTS.register(
        MOD_ID,
        ExampleAnimationEvents.class
);

4. JSON

{
  "in_time_events": [
    {
      "type": "example_mod:example",
      "side": "server",
      "start": 0.75,
      "params": {
        "radius": 4.0,
        "joint": "Tool_R"
      }
    }
  ]
}

⚠️ Notes

  • Custom events should implement IAnimationExternalEventParams rather than directly implementing IAnimationEventParams.
  • Animation event types must implement IAnimationEventType.
  • Register event enums through ExtendedDatapacksRegistry.ANIMATIONS_EVENTS.
  • Multiple event enum classes can be registered in a single call.
  • The registry automatically validates that supplied classes implement the appropriate registry interface.
  • Registration must occur before Extended Datapacks initializes and consumes its animation registries.
  • The generated event identifier is based on the mod ID and enum constant name.
  • The params object is decoded using the MapCodec supplied by the registered event type.
  • Every event implementation is responsible for validating its own execution context (client/server side, entity state, world access, etc.) inside its execute() method.
  • The centralized ExtendedDatapacksRegistry is the recommended registration API; the underlying AnimationEventTypeRegistry remains an implementation detail.

EF: Extended Datapacks

📦 Data

🧰 Core

👁️ Visuals

⚔️ Combat

🗝️ Skill Builder

🛠️ Innate Builder

🗡️ Animation Operations

⚙️ Third-Party

Clone this wiki locally