228 lines
5.8 KiB
Markdown
228 lines
5.8 KiB
Markdown
---
|
|
title: Codecs
|
|
type: docs
|
|
weight: 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
|
|
|
|
```java
|
|
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:
|
|
|
|
```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()`:
|
|
|
|
```java
|
|
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:
|
|
|
|
```java
|
|
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:
|
|
|
|
```java
|
|
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:
|
|
|
|
```java
|
|
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:
|
|
|
|
```java
|
|
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:
|
|
|
|
```java
|
|
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:
|
|
|
|
```java
|
|
// 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 >}}
|