Hytale Modding
Hytale Modding
Server Plugins

Spawning Entities

Learn how to spawn Entities in Hytale

Written by Neil Revin

In this guide, you will learn how to spawn entities in Hytale. It is highly recommended to familiarize yourself with the Entity Component System (ECS) before proceeding with this guide. You can find the ECS guide here.

Getting the World Object

You need to first get the World object before proceeding with spawning entities. You can get this object in a few ways:

Using the Player Object

You can use the Player object to get the World object by calling the getWorld() method on the Player instance.

World world = player.getWorld();

Using the Universe Class

You can use the Universe class to get the World object by calling the getWorld(string UUID) method on the Universe instance.

World world = Universe.get().getWorld("your-world-uuid");

Once you have the world object, you need to get a instance of Store<EntityStore>, you can do so by:

Store<EntityStore> store = world.getEntityStore().getStore();

Creating Entities

Once you have the EntityStore instance, you can start to create an entity and give it components. Entities are just instances of Holder<EntityStore> with several components attached to them.

Warning

To interact with the World instance, some methods require you to run the code inside the world's execution context. The logic under the hood enqueues each task to be executed in the world's thread. To do this, you can use the world.execute() method.

In our case, we will be using the world.execute() method to spawn the entity in the world. For convenience, in this guide we will be putting all the code below inside the lambda function, but it's not required.

world.execute(() -> {
    // run all the code below in this context
})

Let's start by creating a blank holder:

Holder<EntityStore> holder = EntityStore.REGISTRY.newHolder();

Getting a Model

You now need a model for your Entity. You can find a list of all entities here, we're going to use the Minecart entity for this example:

ModelAsset modelAsset = ModelAsset.getAssetMap().getAsset("Minecart");
Model model = Model.createScaledModel(modelAsset, 1.0f);

The Transform Component

The TransformComponent is the component that tells Hytale where to place your entity, what it's location is. You can get this in multiple ways.

  1. Getting the Transform Component from the player - note that this requires fetching the player's EntityStore reference first.
TransformComponent transform = store.getComponent(playerRef.getReference(), EntityModule.get().getTransformComponentType());
  1. Generating a new TransformComponent
Vector3d vector3d = new Vector3d(0, 0, 0); // position
Vector3f vector3f = new Vector3f(0, 0, 0); // rotation
TransformComponent transform = new TransformComponent(vector3d, vector3f);

Adding Components to our Entity

Now we need to add all the components we made above to our entity, here's all the components we need to add one by one:


holder.addComponent(TransformComponent.getComponentType(), new TransformComponent(vector3d, new Vector3f(0, 0, 0)));
holder.addComponent(PersistentModel.getComponentType(), new PersistentModel(model.toReference()));
holder.addComponent(ModelComponent.getComponentType(), new ModelComponent(model));
holder.addComponent(BoundingBox.getComponentType(), new BoundingBox(model.getBoundingBox()));
holder.addComponent(NetworkId.getComponentType(), new NetworkId(store.getExternalData().takeNextNetworkId()));
holder.addComponent(Interactions.getComponentType(), new Interactions()); // you need to add interactions here if you want your entity to be interactable

Ensuring Hytale's Components are present

These act as "configuration" or "default" components that Hytale expects to be present on all entities.

holder.ensureComponent(UUIDComponent.getComponentType());
holder.ensureComponent(Interactable.getComponentType()); // if you want your entity to be interactable

Spawning the Entity

Finally, we can add the entity to the world by calling the addEntity method on the EntityStore instance:

Warning

As a reminder, a part of the logic is to enqueue the entity spawn task inside the world in its thread. Because of this, this part needs to be run inside world.execute() method.

store.addEntity(holder, AddReason.SPAWN);

Making the entity persist

Hytale automatically saves all entities, but the NetworkId component (required for players to be able to see the entity) needs to be manually added every time the entity is loaded.

Using a system

If you have a component that is unique to your entities, this can be done by creating and registering a custom system as follows:

public class AddNetworkIdToMyEntitySystem extends HolderSystem<EntityStore> {
    private final ComponentType<EntityStore, MyEntityComponent> myEntityComponentType = MyEntityComponent.getComponentType();
    private final ComponentType<EntityStore, NetworkId> networkIdComponentType = NetworkId.getComponentType();
    private final Query<EntityStore> query = Query.and(this.myEntityComponentType, Query.not(this.networkIdComponentType));

    @Override
    public void onEntityAdd(@NotNull Holder<EntityStore> holder, @NotNull AddReason reason, @NotNull Store<EntityStore> store) {
        if (!holder.getArchetype().contains(NetworkId.getComponentType())) {
            holder.addComponent(NetworkId.getComponentType(), new NetworkId(store.getExternalData().takeNextNetworkId()));
        }
    }

    @Override
    public void onEntityRemoved(@NotNull Holder<EntityStore> holder, @NotNull RemoveReason reason, @NotNull Store<EntityStore> store) {}

    @Override
    public @Nullable Query<EntityStore> getQuery() {
        return query;
    }
}

In your plugin's setup() function

this.getEntityStoreRegistry().registerSystem(new AddNetworkIdToMyEntitySystem())

Using PropComponent

Alternatively you can add PropComponent to your entity. Hytale adds PropComponent to entities spawned with the Entity Tool, and such entities automatically get NetworkId and PrefabCopyableComponent (which makes the entity work with prefabs).

Warning

There is no guarantee, that Hytale will not add some other behavior to this component in the future, which may break your entity, so be careful if you decide to rely on it.