Hytale Modding
Server Plugins

Storing Persistant Data on the Player

Learn how to save and load persistant data using Components

Here is how to store persistent data using a custom component on a Player.

Build your Component Class

Creating a custom component class leverages the Component system made with the ECS architecture in mind. For more information on Components, check out the ECS Guide.

Start by creating your custom component class. This will be extremely similar to how regular components are created, however we'll setup a custom Codec so the server can translate this data to BSON, or the server's internal json encoder.

Info

Each variable you want to store in your component must have its own Codec field defined in the BuilderCodec. For more information on how to create custom Codecs, check out the ECS Codec Guide.

public class YourPlayerData implements Component<EntityStore> {

    // define some vars!
    private int someInteger;
    private String someString;
    private Map<String, String> someMap;

    public static final BuilderCodec<YourPlayerData> CODEC =
            BuilderCodec.builder(YourPlayerData.class, YourPlayerData::new)
            .append(new KeyedCodec<>("SomeInteger", Codec.INTEGER),
                    (data, value) -> data.someInteger = value, // setter
                    data -> data.someInteger) // getter
            .addValidator(Validators.nonNull())
            .add()
            .append(new KeyedCodec<>("SomeString", Codec.STRING),
                    (data, value) -> data.someString = value, // setter
                    data -> data.someString) // getter
            .add()
            .append(new KeyedCodec<>("SomeMap",
                            new MapCodec<>(Codec.STRING, HashMap::new, false)),
                    (data, value) -> data.someMap = value, // setter
                    data -> data.someMap) // getter
            .add()
            .build();



    // Getters and Setters are for the purpose of this example omitted.

    // constructor
    public YourPlayerData() {
        this.someInteger = 0;
        this.someString = "";
        this.someMap = new HashMap<>();
    }

    // copy constructor for cloning
    public YourPlayerData(YourPlayerData clone) {
        this.someInteger = clone.someInteger;
        this.someString = clone.someString;
        this.someMap = clone.someMap;
    }

    @Nonnull
    @Override
    public Component<EntityStore> clone() {
        return new YourPlayerData(this);
    }
}

Register your Component

Inside your main class's setup() method, register your new Component.

public class YourPlugin extends JavaPlugin {

    private ComponentType<EntityStore, YourPlayerData> yourPlayerDataComponent;

    public YourPlugin(@Nonnull JavaPluginInit init) {
        super(init);
    }

    @Override
    protected void setup(){
        this.yourPlayerDataComponent = this.getEntityStoreRegistry().registerComponent(
            YourPlayerData.class,
            "YourPlayerDataComponent",
            YourPlayerData.CODEC
        );
    }

    public ComponentType<EntityStore, YourPlayerData> getYourPlayerDataComponent() {
        return this.yourPlayerDataComponent;
    }
}

Using your Component

To use your newly created component, you can add the Component to a player using the addComponent method, although this only adds it temporarily, meaning when the player/entity leaves the world, the component is removed. You can use putComponent to ensure the component persists between sessions.

// You will need the Ref and Store to apply components
private void someEntryMethod(@Nonnull Ref<EntityStore> ref, @Nonnull Store<EntityStore> store)
{
       // Any entity will work, for now we will use the player
      Player player = (Player) store.getComponent(ref, Player.getComponentType());

      // since were using putComponent, it could be useful to check if it already exists on the player in case we want to update it
     if(store.getComponent(ref, YourPlugin.instance().getYourPlayerDataComponent()) != null)
     {
          // here we implement logic that updates the component
         var comp = store.getComponent(ref, YourPlugin.instance().getYourPlayerDataComponent())
         // declare public fields or methods in the component class
         comp.SomeString = "An Updated Field";
     } else {
          // Here we put the component
          var myCustomComp = new CustomComponent();
          // declare public fields or methods in the component class
          myCustomComp.SomeString = "Edited String";

          // putComponent allows you to insert declared objects
          store.putComponent(ref, YourPlugin.instance().getYourPlayerDataComponent(), myCustomComp);
     }
}

Using your Data

Your component will be stored within the Store<EntityStore> when added to the player. In the provided example, we'll fetch this data off the player using the ensureAndGetComponent() method, which will add the component to the player if it does not exist with the default values.

public class IncompleteCustomCommand extends AbstractPlayerCommand {

    public IncompleteCustomCommand() {
        super("nope", "don't use this command");
    }

    @Override
    protected void execute(
        @NonNullDecl CommandContext commandContext,
        @NonNullDecl Store<EntityStore> store,
        @NonNullDecl Ref<EntityStore> ref,
        @NonNullDecl PlayerRef playerRef,
        @NonNullDecl World world
    ) {
        YourPlayerData customData = store.ensureAndGetComponent(ref, YourPlugin.instance().getYourPlayerDataComponent());
        // ensureAndGetComponent adds the component to the ref, with the default values defined inside your component.
 		// use your data
    }
}

And that's it! Your data will now be saved and loaded automatically with the player.

Using custom components to store persistent data on players is a powerful way to maintain state across sessions. By following the steps outlined above, you can easily create, register, and utilize your own data structures within the Hytale ECS framework. This approach ensures that your data is seamlessly integrated with the game's existing systems. For more information about Hytale's Entity Component System visit the Hytale ECS Theory guide.