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 finalfields - 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 >}}