Skip to content
iam edited this page May 19, 2022 · 17 revisions

A full example of the steps described below can be found here

Folder Structure

Models Folder

models/ is where you put your custom models. Each model must go in its own folder, with the model name as the folder name. In the demo server you can see that models/ can be found, and within the folder there is another folder with the name gem_golem, for the gem golem model.

Each model folder must contain 3 files:

  • model.animation.json File containing the animations
  • model.geo.json File contain the model data
  • texture.png File contain the model textures

Generating a Resource Pack

FileUtils.copyDirectory(BASE_PATH.resolve("resourcepack_template").toFile(), BASE_PATH.resolve("resourcepack").toFile());

First start by copying a template resource pack. This is your server resource pack which you plan on adding the models to. Feel free to use the resource pack in the demo server

ModelParser.parse(BASE_PATH.resolve("resourcepack/assets/wsee"), MODEL_PATH, BASE_PATH);

Next, call the parse method from ModelParser and tell it where your copied resource pack is, and where your models/ folder is. This is the folder described above, containing your custom entity models. Calling this method will generate a model_mappings.json file in BASE_PATH, which is used in the following steps.

This step will add necessary files to your resource pack. After this step is complete, you must zip the resource pack before sending it to clients.

Loading your Models

ModelEngine.loadMappings(BASE_PATH.resolve("model_mappings.json"), MODEL_PATH);

Specify where your models are located, and where your mapping file is.

Creating a Multipart Entity

The example below can be found in the test folder.

public class GemGolemModel extends GenericModelImpl {
    private static final String id = "gem_golem";

    @Override
    public String getId() {
        return id;
    }

    public void init(@Nullable Instance instance, @NotNull Pos position, LivingEntity masterEntity, LivingEntity nametag) {
        super.init(instance, position, ModelEngine.RenderType.ZOMBIE, masterEntity, nametag);
    }
}

To create a model you must define the model ID. This is the name of the folder that the model is inside of. For example, in the demo server there is a folder models/gem_golem, and this ID is gem_golem.

Here you can also define the RenderType. This specifies what type of entity to use for drawing the bones. Unless your model is designed to use zombies, use ARMOR_STAND here

Spawning Multipart Entities

Multipart entities can now be spawned.

GenericModel model = new GemGolemModel();
model.init(instance, pos, master_entity);

Start by creating a new instance of the model that you would like to spawn. In this example we call new GemGolemModel() to create the gem golem entity.

Next, initiate the model. This will spawn the entity in the instance and position specified. master_entity is used to define which entity is used to control mob health, physics, and pathfinding. Any living entity can be passed as the master entity.

Animating the Multipart Entity

Creating an Animation Handler

public class AnimationHandlerGemGolem extends AnimationHandlerImpl {
    private static final Map<String, Integer> ANIMATION_PRIORITIES = Map.ofEntries(
            entry("idle_extended", 5),
            entry("idle_retracted", 4),
            entry("walk", 3),
            entry("attack", 2),
            entry("attack_near", 1),
            entry("death", 0),
            entry("retract", -1),
            entry("extend", -2));

    public AnimationHandlerGemGolem(GenericModel model) {
        super(model);
    }

    @Override
    public Map<String, Integer> animationPriorities() {
        return ANIMATION_PRIORITIES;
    }
}

First you must create an animation handler. This will define the priority of animations. Entities can have any number of animations, but they must all have their own priority number, and they must have an entry in their model.animation.json file.

Animation priority defines the order in which animations will be played. For example, if you have idle with priority 5 and attack with priority 4 and play both on repeat, attack will be played multiple times and idle will never be played.

Attaching an animation handler to a model

AnimationHandler animationHandler = new AnimationHandlerGemGolem(model);

This will create an animation handler for a model

Setting an Idle Animation

It is highly suggested that you run the idle animation after creating the animation handler.

animationHandler.playRepeat("idle");

Running Animations

void playRepeat(String animation);

This can be used to play an animation multiple times. animation name is the name of the animation.

void stopRepeat(String animation);

This is used to stop an animation that is repeating.

void playOnce(String animation, Consumer cb);

This plays an animation once, then runs the code from a callback when the animation is complete.

Optimizing Entity Animations

void setUpdates(boolean updates); can be used to turn off animations. This is useful for when an entity does not need to be animated, ex. no players are nearby. When updates are turned off, no position update packets will be sent to nearby players, and the entity will not move.

An example of this concept in use can be found here

Destroying a Multipart Entity

this.model.destroy();
this.animationHandler.destroy();

When you remove a multipart entity, you must remove the model and animation handler. If you don't destroy these objects, the model will continue to be rendered and animated after the master entity death.

Clone this wiki locally