HyCodeYourTale

Codecs

Codecs

Dokumentace k Codec systému pro serializaci/deserializaci objektů v Hytale.

---

Přehled

Codecs jsou systém pro konverzi Java objektů do/z BSON formátu. Hytale poskytuje předdefinované codecy pro základní typy a BuilderCodec pro komplexní objekty.

---

Základní Codecy

Import

import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.ExtraInfo;
import com.hypixel.hytale.codec.EmptyExtraInfo;

Předdefinované Codecy

// Z Codec.java - předdefinované codecy
Codec.STRING // String
Codec.BOOLEAN // boolean
Codec.INTEGER // int
Codec.LONG // long
Codec.FLOAT // float
Codec.DOUBLE // double
Codec.BYTE // byte
Codec.SHORT // short

// Arrays
Codec.STRING_ARRAY // String[]
Codec.INT_ARRAY // int[]
Codec.LONG_ARRAY // long[]
Codec.FLOAT_ARRAY // float[]
Codec.DOUBLE_ARRAY // double[]
Codec.BYTE_ARRAY // byte[]

// Speciální typy
Codec.PATH // java.nio.file.Path
Codec.INSTANT // java.time.Instant
Codec.DURATION // java.time.Duration
Codec.DURATION_SECONDS // Duration v sekundách (double)
Codec.LOG_LEVEL // java.util.logging.Level
Codec.UUID_BINARY // UUID jako binary
Codec.UUID_STRING // UUID jako string

---

Použití Codeců

Enkódování (Java → BSON)

// Základní typy
BsonValue bsonString = Codec.STRING.encode("Hello", EmptyExtraInfo.EMPTY);
BsonValue bsonInt = Codec.INTEGER.encode(42, EmptyExtraInfo.EMPTY);
BsonValue bsonBool = Codec.BOOLEAN.encode(true, EmptyExtraInfo.EMPTY);

// S deprecated metodou (bez ExtraInfo)
BsonValue bson = Codec.STRING.encode("Hello"); // Deprecated ale funkční

Dekódování (BSON → Java)

// Základní typy
String str = Codec.STRING.decode(bsonValue, EmptyExtraInfo.EMPTY);
int num = Codec.INTEGER.decode(bsonValue, EmptyExtraInfo.EMPTY);
boolean bool = Codec.BOOLEAN.decode(bsonValue, EmptyExtraInfo.EMPTY);

---

ArrayCodec

Pro serializaci polí:

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

// Vytvoření array codeku
ArrayCodec stringArrayCodec = new ArrayCodec<>(Codec.STRING, String[]::new);

// Enkódování
String[] array = {"one", "two", "three"};
BsonArray bsonArray = stringArrayCodec.encode(array, EmptyExtraInfo.EMPTY);

// Dekódování
String[] decoded = stringArrayCodec.decode(bsonArray, EmptyExtraInfo.EMPTY);

---

MapCodec

Pro serializaci map:

import com.hypixel.hytale.codec.codecs.map.MapCodec;

// Vytvoření map codeku
MapCodec stringMapCodec = new MapCodec<>(Codec.STRING, HashMap::new);

// Enkódování
Map map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
BsonDocument bsonDoc = stringMapCodec.encode(map, EmptyExtraInfo.EMPTY);

// Dekódování
Map decoded = stringMapCodec.decode(bsonDoc, EmptyExtraInfo.EMPTY);

---

EnumCodec

Pro serializaci enumů:

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

public enum GameMode {
SURVIVAL, CREATIVE, ADVENTURE
}

// Vytvoření enum codeku
EnumCodec gameModeCodec = new EnumCodec<>(GameMode.class);

// Enkódování (jako string)
BsonValue bson = gameModeCodec.encode(GameMode.SURVIVAL, EmptyExtraInfo.EMPTY);
// Výsledek: BsonString("SURVIVAL")

// Dekódování
GameMode mode = gameModeCodec.decode(new BsonString("CREATIVE"), EmptyExtraInfo.EMPTY);

---

FunctionCodec

Pro konverzi mezi typy:

import com.hypixel.hytale.codec.function.FunctionCodec;

// Příklad: Path jako string
FunctionCodec pathCodec = new FunctionCodec<>(
Codec.STRING, // Podkladový codec
Paths::get, // String → Path
Path::toString // Path → String
);

// Příklad: UUID jako string
FunctionCodec uuidCodec = new FunctionCodec<>(
Codec.STRING,
UUID::fromString,
UUID::toString
);

// Příklad: Duration v sekundách
FunctionCodec durationCodec = new FunctionCodec<>(
Codec.DOUBLE,
v -> Duration.ofNanos((long)(v * TimeUnit.SECONDS.toNanos(1L))),
v -> (double)v.toNanos() / (double)TimeUnit.SECONDS.toNanos(1L)
);

---

BuilderCodec

Pro komplexní objekty s mnoha poli.

Základní Struktura

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

public class PlayerData {
private String name;
private int level;
private boolean premium;

// Výchozí konstruktor je povinný
public PlayerData() {}

// Gettery a settery
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getLevel() { return level; }
public void setLevel(int level) { this.level = level; }
public boolean isPremium() { return premium; }
public void setPremium(boolean premium) { this.premium = premium; }

// Codec definice
public static final BuilderCodec CODEC;

static {
BuilderCodec.Builder builder = BuilderCodec.builder(
PlayerData.class,
PlayerData::new
);

builder.append(
new KeyedCodec<>("Name", Codec.STRING),
PlayerData::setName,
PlayerData::getName
).add();

builder.append(
new KeyedCodec<>("Level", Codec.INTEGER),
PlayerData::setLevel,
PlayerData::getLevel
).add();

builder.append(
new KeyedCodec<>("Premium", Codec.BOOLEAN),
PlayerData::setPremium,
PlayerData::isPremium
).add();

CODEC = builder.build();
}
}

Použití BuilderCodec

// Vytvoření objektu
PlayerData player = new PlayerData();
player.setName("Steve");
player.setLevel(42);
player.setPremium(true);

// Enkódování
BsonValue bson = PlayerData.CODEC.encode(player, EmptyExtraInfo.EMPTY);
// Výsledek: {"Name": "Steve", "Level": 42, "Premium": true}

// Dekódování
BsonDocument doc = BsonDocument.parse("{\"Name\": \"Alex\", \"Level\": 10, \"Premium\": false}");
PlayerData decoded = PlayerData.CODEC.decode(doc, EmptyExtraInfo.EMPTY);

Vnořené Objekty

public class Transform {
private double x, y, z;
private float yaw, pitch;

public static final BuilderCodec CODEC;

static {
BuilderCodec.Builder builder = BuilderCodec.builder(
Transform.class, Transform::new
);

builder.append(new KeyedCodec<>("X", Codec.DOUBLE), Transform::setX, Transform::getX).add();
builder.append(new KeyedCodec<>("Y", Codec.DOUBLE), Transform::setY, Transform::getY).add();
builder.append(new KeyedCodec<>("Z", Codec.DOUBLE), Transform::setZ, Transform::getZ).add();
builder.append(new KeyedCodec<>("Yaw", Codec.FLOAT), Transform::setYaw, Transform::getYaw).add();
builder.append(new KeyedCodec<>("Pitch", Codec.FLOAT), Transform::setPitch, Transform::getPitch).add();

CODEC = builder.build();
}
}

public class Warp {
private String id;
private String world;
private Transform transform;

public static final BuilderCodec CODEC;

static {
BuilderCodec.Builder builder = BuilderCodec.builder(
Warp.class, Warp::new
);

builder.append(new KeyedCodec<>("Id", Codec.STRING), Warp::setId, Warp::getId).add();
builder.append(new KeyedCodec<>("World", Codec.STRING), Warp::setWorld, Warp::getWorld).add();
// Vnořený objekt používá svůj vlastní codec
builder.append(new KeyedCodec<>("Transform", Transform.CODEC), Warp::setTransform, Warp::getTransform).add();

CODEC = builder.build();
}

// Array codec pro seznamy warpů
public static final ArrayCodec ARRAY_CODEC = new ArrayCodec<>(CODEC, Warp[]::new);
}

---

KeyedCodec

Wrapper pro pojmenování klíče v JSON:

// Vytvoření keyed codeku
KeyedCodec nameCodec = new KeyedCodec<>("Name", Codec.STRING);
KeyedCodec levelCodec = new KeyedCodec<>("Level", Codec.INTEGER);
KeyedCodec transformCodec = new KeyedCodec<>("Transform", Transform.CODEC);

// Klíč v JSON bude odpovídat prvnímu argumentu
// "Name": "value"
// "Level": 42
// "Transform": {...}

---

Validace

ValidatableCodec

import com.hypixel.hytale.codec.validation.ValidatableCodec;
import com.hypixel.hytale.codec.validation.ValidationResults;

// BuilderCodec implementuje ValidatableCodec
// Můžeš přidat validaci:

builder.validator((object, results) -> {
if (object.getLevel() < 0) {
results.addError("Level cannot be negative");
}
if (object.getName() == null || object.getName().isEmpty()) {
results.addError("Name is required");
}
});

---

ExtraInfo

Kontext pro kódování/dekódování:

// Prázdný kontext (nejčastější použití)
ExtraInfo info = EmptyExtraInfo.EMPTY;

// Thread-local kontext
ExtraInfo info = ExtraInfo.THREAD_LOCAL.get();

// S verzí
VersionedExtraInfo info = new VersionedExtraInfo(1);

---

Vlastní Codec

Implementace Codec Interface

public class Vector3dCodec implements Codec {

@Override
public Vector3d decode(BsonValue bsonValue, ExtraInfo extraInfo) {
if (bsonValue == null || bsonValue.isNull()) {
return null;
}

BsonDocument doc = bsonValue.asDocument();
double x = doc.getDouble("x").getValue();
double y = doc.getDouble("y").getValue();
double z = doc.getDouble("z").getValue();

return new Vector3d(x, y, z);
}

@Override
public BsonValue encode(Vector3d vector, ExtraInfo extraInfo) {
if (vector == null) {
return BsonNull.VALUE;
}

BsonDocument doc = new BsonDocument();
doc.put("x", new BsonDouble(vector.x));
doc.put("y", new BsonDouble(vector.y));
doc.put("z", new BsonDouble(vector.z));

return doc;
}
}

// Použití
public static final Codec VECTOR3D_CODEC = new Vector3dCodec();

---

Příklad: Kompletní Warp Systém

public class Warp {
private String id;
private String world;
private Vector3d position;
private Vector3f rotation;

public Warp() {}

// Gettery a settery...

// Codecy
public static final BuilderCodec CODEC;
public static final ArrayCodec ARRAY_CODEC;

static {
BuilderCodec.Builder builder = BuilderCodec.builder(Warp.class, Warp::new);

builder.append(new KeyedCodec<>("Id", Codec.STRING), Warp::setId, Warp::getId).add();
builder.append(new KeyedCodec<>("World", Codec.STRING), Warp::setWorld, Warp::getWorld).add();
builder.append(new KeyedCodec<>("Position", VECTOR3D_CODEC), Warp::setPosition, Warp::getPosition).add();
builder.append(new KeyedCodec<>("Rotation", VECTOR3F_CODEC), Warp::setRotation, Warp::getRotation).add();

CODEC = builder.build();
ARRAY_CODEC = new ArrayCodec<>(CODEC, Warp[]::new);
}
}

// Použití při ukládání/načítání
public class WarpManager {

public void saveWarps(List warps) {
Warp[] array = warps.toArray(Warp[]::new);
BsonArray bsonArray = Warp.ARRAY_CODEC.encode(array, EmptyExtraInfo.EMPTY);

BsonDocument document = new BsonDocument("Warps", bsonArray);
BsonUtil.writeDocument(warpsPath, document).join();
}

public List loadWarps() {
BsonDocument document = BsonUtil.readDocument(warpsPath).join();
if (document == null) return new ArrayList<>();

BsonArray bsonArray = document.getArray("Warps");
Warp[] array = Warp.ARRAY_CODEC.decode(bsonArray, EmptyExtraInfo.EMPTY);

return new ArrayList<>(Arrays.asList(array));
}
}

---

Shrnutí

| Typ | Codec | Příklad |
|-----|-------|---------|
| String | Codec.STRING | "text" |
| int | Codec.INTEGER | 42 |
| long | Codec.LONG | 1000 |
| double | Codec.DOUBLE | 3.14 |
| boolean | Codec.BOOLEAN | true |
| Array | ArrayCodec | [...] |
| Map | MapCodec | {...} |
| Enum | EnumCodec | "VALUE" |
| Object | BuilderCodec | {...} |
| Konverze | FunctionCodec | různé |

Last updated: 20. ledna 2026