AgentSkillsCN

hytale-config-files

在 Hytale 中,利用 Config<T>、BuilderCodec 与 KeyedCodec 创建并管理插件配置文件,确保持久化设置在服务器重启后依然有效。适用于创建配置类、加载/保存插件设置、定义可序列化的配置选项,或从其他类中访问配置时使用。触发条件:config、configuration、Config、withConfig、配置文件、插件设置、插件配置、配置保存、配置加载、配置文件、服务器设置。

SKILL.md
--- frontmatter
name: hytale-config-files
description: Creates and manages plugin configuration files in Hytale using Config<T>, BuilderCodec, and KeyedCodec for persistent settings that survive server restarts. Use when creating config classes, loading/saving plugin settings, defining serializable config options, or accessing config from other classes. Triggers - config, configuration, Config, withConfig, config file, plugin settings, plugin config, config save, config load, configuration file, server settings.

Hytale Plugin Configuration Files

Use this skill when creating and managing configuration files for Hytale plugins. Configuration files allow plugins to store persistent settings that survive server restarts.

Source: https://hytalemodding.dev/en/docs/guides/plugin/creating-configuration-file


Quick Reference

TaskApproach
Create config classClass with BuilderCodec<T> defining serializable fields
Register configthis.withConfig("Name", MyConfig.CODEC) in plugin field initializer
Ensure file existsconfig.save() in setup()
Read config valuesconfig.get().getFieldName()
Modify config valuesconfig.get().setFieldName(value) then config.save()
Access from other classesPass Config<T> or plugin reference with a getter

Key Concepts

Config Class

A plain Java class that holds your configuration data. It must define a BuilderCodec<T> that tells Hytale how to serialize/deserialize each field. The class does NOT need to implement Component<EntityStore> — it is a standalone config object.

Config<T> Wrapper

The Config<T> class (provided by Hytale) wraps your config class and manages file I/O. You obtain an instance via JavaPlugin.withConfig().

BuilderCodec Keys Must Be Capitalized

Keys in KeyedCodec must start with a capital letter. Lowercase keys will throw an error when loading the configuration file.

Config File Location

Configuration files are stored in the mods folder of the server, persisting across restarts.


Required Imports

java
import com.hypixel.hytale.codec.Codec;         // Careful: use this Codec, not other Codec imports
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;

Creating a Configuration Class

Define a class with fields, a BuilderCodec, a default constructor, getters, and setters.

java
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;

public class MyConfig {

    // === Codec Definition ===
    public static final BuilderCodec<MyConfig> CODEC =
        BuilderCodec.builder(MyConfig.class, MyConfig::new)
            .append(new KeyedCodec<Integer>("SomeValue", Codec.INTEGER),
                    (config, value) -> config.someValue = value,   // setter
                    (config) -> config.someValue)                  // getter
            .add()
            .append(new KeyedCodec<String>("SomeString", Codec.STRING),
                    (config, value) -> config.someString = value,
                    (config) -> config.someString)
            .add()
            .build();

    // === Fields with defaults ===
    private int someValue = 12;
    private String someString = "My default string";

    // === Default Constructor ===
    public MyConfig() {
    }

    // === Getters ===
    public int getSomeValue() {
        return someValue;
    }

    public String getSomeString() {
        return someString;
    }

    // === Setters ===
    public void setSomeValue(int someValue) {
        this.someValue = someValue;
    }

    public void setSomeString(String someString) {
        this.someString = someString;
    }
}

Key Rules

  • Codec keys must be capitalized"SomeValue" not "someValue".
  • Each field needs a getter lambda and a setter lambda in the codec chain.
  • Default field values are used when the config file doesn't yet exist.
  • The config class does not need clone() or Component<EntityStore> — that's only for ECS components.

Loading, Saving, and Using the Configuration

Registering the Config in Your Plugin

Register the config as a field initializer in your JavaPlugin class using this.withConfig(). The config must be loaded before setup() completes — loading it after will throw an error.

Call config.save() in setup() to ensure the file is created on first run.

java
import com.hypixel.hytale.server.plugin.JavaPlugin;
import com.hypixel.hytale.server.plugin.JavaPluginInit;
import com.hypixel.hytale.server.plugin.config.Config;

import javax.annotation.Nonnull;

public class ExamplePlugin extends JavaPlugin {

    // Register config — MUST be in the field initializer, not in setup()
    private final Config<MyConfig> config = this.withConfig("MyConfig", MyConfig.CODEC);

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

    @Override
    protected void setup() {
        // Ensures the config file is created if it doesn't exist
        config.save();
    }

    // Getter for other classes to access
    public Config<MyConfig> getConfig() {
        return config;
    }
}

Important Timing

WhenWhat
Field initializationCall this.withConfig(...) to register the config
setup()Call config.save() to write defaults if file missing
After setup()Too late — loading config here throws an error

Accessing Config from Other Classes

Pass the plugin instance or the Config<T> directly to other classes.

java
public class SomeOtherClass {

    private final ExamplePlugin plugin;

    public SomeOtherClass(ExamplePlugin plugin) {
        this.plugin = plugin;
    }

    public void someMethod() {
        // Read values
        MyConfig myConfig = plugin.getConfig().get();
        int value = myConfig.getSomeValue();
        String str = myConfig.getSomeString();

        // Modify values
        myConfig.setSomeValue(999);
        myConfig.setSomeString("A new string");

        // Persist changes to disk
        plugin.getConfig().save();
    }
}

Common Codec Types for Config Fields

Java TypeCodecExample Key
intCodec.INTEGER"MaxPlayers"
longCodec.LONG"CooldownMs"
floatCodec.FLOAT"SpeedMultiplier"
doubleCodec.DOUBLE"SpawnRadius"
booleanCodec.BOOLEAN"Enabled"
StringCodec.STRING"WelcomeMessage"

For complex types (maps, lists, sets), see the hytale-persistent-data skill which documents MapCodec, ListCodec, and SetCodec.


Config vs Persistent Data

Config (Config<T>)Persistent Data (Component<EntityStore>)
PurposePlugin-wide settingsPer-entity/per-player data
StorageFile in mods/ folderBSON on entity store
Registrationthis.withConfig(...)getEntityStoreRegistry().registerComponent(...)
RequiresBuilderCodec<T> onlyBuilderCodec<T>, Component<EntityStore>, clone()
Accessconfig.get()store.getComponent(ref, type)
When to useServer settings, feature toggles, thresholdsPlayer progress, entity state, session data

Complete Example

A full plugin with a configuration file for a welcome message and max player setting:

java
// === WelcomeConfig.java ===
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;

public class WelcomeConfig {

    public static final BuilderCodec<WelcomeConfig> CODEC =
        BuilderCodec.builder(WelcomeConfig.class, WelcomeConfig::new)
            .append(new KeyedCodec<String>("WelcomeMessage", Codec.STRING),
                    (c, v) -> c.welcomeMessage = v,
                    c -> c.welcomeMessage)
            .add()
            .append(new KeyedCodec<Boolean>("EnableWelcome", Codec.BOOLEAN),
                    (c, v) -> c.enableWelcome = v,
                    c -> c.enableWelcome)
            .add()
            .append(new KeyedCodec<Integer>("MaxWarnings", Codec.INTEGER),
                    (c, v) -> c.maxWarnings = v,
                    c -> c.maxWarnings)
            .add()
            .build();

    private String welcomeMessage = "Welcome to the server!";
    private boolean enableWelcome = true;
    private int maxWarnings = 3;

    public WelcomeConfig() {}

    public String getWelcomeMessage() { return welcomeMessage; }
    public void setWelcomeMessage(String msg) { this.welcomeMessage = msg; }

    public boolean isEnableWelcome() { return enableWelcome; }
    public void setEnableWelcome(boolean enable) { this.enableWelcome = enable; }

    public int getMaxWarnings() { return maxWarnings; }
    public void setMaxWarnings(int max) { this.maxWarnings = max; }
}
java
// === WelcomePlugin.java ===
import com.hypixel.hytale.server.plugin.JavaPlugin;
import com.hypixel.hytale.server.plugin.JavaPluginInit;
import com.hypixel.hytale.server.plugin.config.Config;

import javax.annotation.Nonnull;

public class WelcomePlugin extends JavaPlugin {

    private final Config<WelcomeConfig> config = this.withConfig("WelcomeConfig", WelcomeConfig.CODEC);

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

    @Override
    protected void setup() {
        config.save(); // Create file with defaults if it doesn't exist
    }

    public Config<WelcomeConfig> getWelcomeConfig() {
        return config;
    }
}

Troubleshooting

ProblemCauseFix
Error when loading configCodec key not capitalizedChange "someValue""SomeValue"
Error: config loaded too latewithConfig() called in setup() or laterMove to field initializer
Config file not createdconfig.save() not called in setup()Add config.save() to setup()
Changes not persistedForgot to call save() after modificationCall config.save() after changing values
Wrong Codec importUsing a different library's Codec classUse com.hypixel.hytale.codec.Codec
code