Files
Documentation/content/core-concepts/codecs.en.md
2026-01-20 20:33:59 +01:00

5.8 KiB

title, type, weight
title type weight
Codecs docs 3

Codecs in Hytale provide a powerful way to serialize and deserialize data. They're used for configuration files, network communication, and data persistence.

Package: com.hypixel.hytale.codec

BuilderCodec

The BuilderCodec is the primary codec type for complex objects. It uses a builder pattern for construction.

Defining a Codec

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

public class MyConfig {
    private String serverName;
    private int maxPlayers = 20;  // Default value
    private boolean debugMode = false;

    public static final BuilderCodec<MyConfig> CODEC = BuilderCodec.builder(MyConfig.class, MyConfig::new)
        .append(new KeyedCodec<>("ServerName", Codec.STRING),
            (config, val) -> config.serverName = val,
            config -> config.serverName)
        .add()
        .append(new KeyedCodec<>("MaxPlayers", Codec.INTEGER),
            (config, val) -> config.maxPlayers = val,
            config -> config.maxPlayers)
        .add()
        .append(new KeyedCodec<>("DebugMode", Codec.BOOLEAN),
            (config, val) -> config.debugMode = val,
            config -> config.debugMode)
        .add()
        .build();

    // Getters...
    public String getServerName() { return serverName; }
    public int getMaxPlayers() { return maxPlayers; }
    public boolean isDebugMode() { return debugMode; }
}

{{< callout type="warning" >}} KeyedCodec keys must start with an uppercase letter (PascalCase). Keys like "serverName" will throw an IllegalArgumentException. {{< /callout >}}

JSON Structure

The codec above corresponds to this JSON:

{
  "ServerName": "My Server",
  "MaxPlayers": 100,
  "DebugMode": true
}

Basic Codecs

Hytale provides codecs for primitive types:

Codec Type
Codec.STRING String
Codec.INTEGER Integer
Codec.LONG Long
Codec.FLOAT Float
Codec.DOUBLE Double
Codec.BOOLEAN Boolean
Codec.BYTE Byte
Codec.SHORT Short

Using Config Files

Register configuration files in setup():

import com.hypixel.hytale.server.core.util.Config;
import java.util.logging.Level;

private Config<MyConfig> config;

@Override
public void setup() {
    config = withConfig(MyConfig.CODEC);
}

@Override
public void start() {
    MyConfig cfg = config.get();
    getLogger().at(Level.INFO).log("Server name: " + cfg.getServerName());
}

Config File Location

Config files are automatically stored in your plugin's data directory:

Plugins/
└── your-plugin/
    └── config.json

Named Configs

You can have multiple config files:

Config<MyConfig> mainConfig = withConfig("main", MyConfig.CODEC);
Config<DatabaseConfig> dbConfig = withConfig("database", DatabaseConfig.CODEC);

Required vs Optional Fields

By default, all fields are optional. To make a field required, add a validator:

import com.hypixel.hytale.codec.validation.Validators;

BuilderCodec.builder(MyConfig.class, MyConfig::new)
    .append(new KeyedCodec<>("ServerName", Codec.STRING),
        (config, val) -> config.serverName = val,
        config -> config.serverName)
    .addValidator(Validators.nonNull())  // Makes field required
    .add()
    .append(new KeyedCodec<>("MaxPlayers", Codec.INTEGER),
        (config, val) -> config.maxPlayers = val,
        config -> config.maxPlayers)
    .add()  // Optional - uses default value from class
    .build();

List and Map Codecs

For collections:

import com.hypixel.hytale.codec.codecs.array.ArrayCodec;
import com.hypixel.hytale.codec.codecs.map.ObjectMapCodec;

// Array of strings
Codec<String[]> stringArray = new ArrayCodec<>(Codec.STRING, String[]::new);

// Map with string keys
Codec<Map<String, Integer>> stringIntMap = new ObjectMapCodec<>(
    Codec.INTEGER,
    LinkedHashMap::new,
    key -> key,           // Key to string
    str -> str            // String to key
);

Enum Codecs

For enum types:

import com.hypixel.hytale.codec.codecs.EnumCodec;

public enum GameMode {
    SURVIVAL, CREATIVE, ADVENTURE
}

Codec<GameMode> gameModeCodec = new EnumCodec<>(GameMode.class);

Nested Codecs

Codecs can be nested for complex structures:

public class ServerSettings {
    private GeneralSettings general;
    private DatabaseSettings database;

    public static final BuilderCodec<ServerSettings> CODEC = BuilderCodec.builder(ServerSettings.class, ServerSettings::new)
        .append(new KeyedCodec<>("General", GeneralSettings.CODEC),
            (s, val) -> s.general = val,
            s -> s.general)
        .add()
        .append(new KeyedCodec<>("Database", DatabaseSettings.CODEC),
            (s, val) -> s.database = val,
            s -> s.database)
        .add()
        .build();
}

Inheritance

Use parent codecs for class hierarchies:

// Base class codec
public static final BuilderCodec<BaseEntity> BASE_CODEC = BuilderCodec.builder(BaseEntity.class, BaseEntity::new)
    .append(new KeyedCodec<>("Id", Codec.STRING),
        (e, val) -> e.id = val,
        e -> e.id)
    .add()
    .build();

// Child class codec inherits from parent
public static final BuilderCodec<PlayerEntity> CODEC = BuilderCodec.builder(PlayerEntity.class, PlayerEntity::new, BASE_CODEC)
    .append(new KeyedCodec<>("Username", Codec.STRING),
        (e, val) -> e.username = val,
        e -> e.username)
    .add()
    .build();

Best Practices

{{< callout type="tip" >}}

  • Define codecs as public static final fields
  • Use PascalCase for JSON keys (e.g., "ServerName", not "serverName")
  • Set default values in class field declarations
  • Use Validators.nonNull() for required fields
  • Keep configuration classes with simple setters for codec compatibility {{< /callout >}}