# Codec and Serialization System

The Hytale server uses a powerful codec system for data serialization and deserialization. This system is used throughout the codebase for configuration, network packets, asset definitions, and data persistence.

## Overview

The codec system provides:

- Type-safe serialization/deserialization
- Support for JSON and BSON formats
- Validation and schema generation
- Composable codecs for complex types
- Builder pattern for object construction

## Core Concepts

### Codec Interface

```java
public interface Codec<T> {
    T decode(DataInput input);
    void encode(T value, DataOutput output);
}
```

### DataInput/DataOutput

Codecs work with abstract `DataInput` and `DataOutput` interfaces that can represent different formats (JSON, BSON, etc.).

## Primitive Codecs

The `Codec` class provides built-in codecs for primitive types:

```java
// String
Codec.STRING              // "hello"

// Numbers
Codec.INTEGER             // 42
Codec.LONG                // 123456789L
Codec.FLOAT               // 3.14f
Codec.DOUBLE              // 3.14159

// Boolean
Codec.BOOLEAN             // true/false

// Byte arrays
Codec.BYTE_ARRAY          // [1, 2, 3]
```

## Collection Codecs

### Lists

```java
// List of strings
Codec<List<String>> stringList = Codec.STRING.listOf();

// List of integers
Codec<List<Integer>> intList = Codec.INTEGER.listOf();

// List of custom objects
Codec<List<MyObject>> objectList = MyObject.CODEC.listOf();
```

### Sets

```java
// Set of strings
Codec<Set<String>> stringSet = Codec.STRING.setOf();
```

### Maps

```java
// Map with string keys
Codec<Map<String, Integer>> stringToInt = Codec.mapOf(Codec.STRING, Codec.INTEGER);

// Map with custom key type
Codec<Map<UUID, PlayerData>> playerMap = Codec.mapOf(UUID_CODEC, PlayerData.CODEC);
```

### Arrays

```java
// Array codec
Codec<String[]> stringArray = Codec.arrayOf(Codec.STRING, String[]::new);
```

## BuilderCodec

`BuilderCodec` is the primary way to create codecs for complex objects:

### Basic Usage

```java
public class Person {
    public static final Codec<Person> CODEC = BuilderCodec.of(Person::new)
        .with("name", Codec.STRING, p -> p.name)
        .with("age", Codec.INTEGER, p -> p.age)
        .with("email", Codec.STRING, p -> p.email)
        .build();
    
    private final String name;
    private final int age;
    private final String email;
    
    private Person(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }
}
```

### With Default Values

```java
public static final Codec<Settings> CODEC = BuilderCodec.of(Settings::new)
    .with("volume", Codec.FLOAT, s -> s.volume, 1.0f)        // Default: 1.0
    .with("muted", Codec.BOOLEAN, s -> s.muted, false)       // Default: false
    .with("language", Codec.STRING, s -> s.language, "en")   // Default: "en"
    .build();
```

### Optional Fields

```java
public static final Codec<User> CODEC = BuilderCodec.of(User::new)
    .with("username", Codec.STRING, u -> u.username)
    .withOptional("nickname", Codec.STRING, u -> u.nickname)  // May be absent
    .build();
```

### Nested Objects

```java
public class Address {
    public static final Codec<Address> CODEC = BuilderCodec.of(Address::new)
        .with("street", Codec.STRING, a -> a.street)
        .with("city", Codec.STRING, a -> a.city)
        .with("zip", Codec.STRING, a -> a.zip)
        .build();
    // ...
}

public class Customer {
    public static final Codec<Customer> CODEC = BuilderCodec.of(Customer::new)
        .with("name", Codec.STRING, c -> c.name)
        .with("address", Address.CODEC, c -> c.address)
        .build();
    // ...
}
```

## KeyedCodec

For objects that have a key/identifier:

```java
public class ItemType {
    public static final KeyedCodec<String, ItemType> KEYED_CODEC = KeyedCodec.of(
        "id",
        Codec.STRING,
        ItemType::getId,
        ItemType.CODEC
    );
    // ...
}
```

## Codec Transformations

### Mapping Values

```java
// Transform between types
Codec<UUID> UUID_CODEC = Codec.STRING.xmap(
    UUID::fromString,    // decode: String -> UUID
    UUID::toString       // encode: UUID -> String
);

// Transform integers to enum
Codec<MyEnum> ENUM_CODEC = Codec.INTEGER.xmap(
    i -> MyEnum.values()[i],
    MyEnum::ordinal
);
```

### Validation

```java
// Validate during decode
Codec<Integer> PORT_CODEC = Codec.INTEGER.validate(
    port -> port > 0 && port < 65536,
    "Port must be between 1 and 65535"
);

// Clamp values
Codec<Float> VOLUME_CODEC = Codec.FLOAT.clamp(0.0f, 1.0f);
```

### Enum Codecs

```java
// Automatic enum codec
Codec<GameMode> GAME_MODE_CODEC = Codec.enumCodec(GameMode.class);

// Custom enum serialization
Codec<Direction> DIRECTION_CODEC = Codec.STRING.xmap(
    Direction::valueOf,
    Direction::name
);
```

## Complex Examples

### Polymorphic Types

```java
// For types with multiple implementations
public interface Shape {
    Codec<Shape> CODEC = Codec.dispatch(
        "type",
        Codec.STRING,
        shape -> shape.getType(),
        type -> switch (type) {
            case "circle" -> Circle.CODEC;
            case "rectangle" -> Rectangle.CODEC;
            default -> throw new IllegalArgumentException("Unknown shape: " + type);
        }
    );
    
    String getType();
}

public class Circle implements Shape {
    public static final Codec<Circle> CODEC = BuilderCodec.of(Circle::new)
        .with("radius", Codec.DOUBLE, c -> c.radius)
        .build();
    
    @Override
    public String getType() { return "circle"; }
    // ...
}
```

### Recursive Types

```java
public class TreeNode {
    public static final Codec<TreeNode> CODEC = BuilderCodec.of(TreeNode::new)
        .with("value", Codec.STRING, n -> n.value)
        .with("children", Codec.lazy(() -> TreeNode.CODEC.listOf()), n -> n.children, List.of())
        .build();
    
    private final String value;
    private final List<TreeNode> children;
    // ...
}
```

### Record Types (Java 16+)

```java
public record Point(double x, double y, double z) {
    public static final Codec<Point> CODEC = BuilderCodec.of(Point::new)
        .with("x", Codec.DOUBLE, Point::x)
        .with("y", Codec.DOUBLE, Point::y)
        .with("z", Codec.DOUBLE, Point::z)
        .build();
}
```

## Vector and Math Codecs

The math library provides codecs for common types:

```java
// 3D Vector (double)
Vector3d.CODEC  // {"x": 1.0, "y": 2.0, "z": 3.0}

// 3D Vector (int)
Vector3i.CODEC  // {"x": 1, "y": 2, "z": 3}

// 2D Vector
Vector2d.CODEC  // {"x": 1.0, "y": 2.0}
```

## Working with JSON

### Encoding to JSON

```java
// Create JSON output
JsonDataOutput output = new JsonDataOutput();
MyObject.CODEC.encode(myObject, output);
String json = output.toJsonString();
```

### Decoding from JSON

```java
// Parse JSON input
JsonDataInput input = JsonDataInput.fromString(jsonString);
MyObject obj = MyObject.CODEC.decode(input);
```

## Working with BSON

### BSON Encoding/Decoding

```java
// BSON output
BsonDataOutput output = new BsonDataOutput();
MyObject.CODEC.encode(myObject, output);
BsonDocument bson = output.toBsonDocument();

// BSON input
BsonDataInput input = new BsonDataInput(bsonDocument);
MyObject obj = MyObject.CODEC.decode(input);
```

## Schema Generation

Codecs can generate JSON schemas for documentation:

```java
// Generate schema
JsonSchema schema = MyObject.CODEC.generateSchema();
String schemaJson = schema.toJson();
```

## Best Practices

1. **Make codecs static final** - Codecs are immutable and should be reused
2. **Use BuilderCodec for objects** - It's the most flexible approach
3. **Provide defaults** - Use sensible defaults for optional fields
4. **Validate input** - Use validation to catch errors early
5. **Keep codecs near their classes** - Define codec as a static field in the class
6. **Test serialization roundtrips** - Ensure encode/decode produces identical objects
7. **Use meaningful field names** - JSON keys should be clear and consistent
8. **Handle null carefully** - Use Optional or defaults for nullable fields
9. **Consider versioning** - Plan for schema evolution
10. **Document complex codecs** - Add comments for non-obvious serialization

## Error Handling

### Decode Errors

```java
try {
    MyObject obj = MyObject.CODEC.decode(input);
} catch (CodecException e) {
    // Handle missing fields, wrong types, validation failures
    logger.error("Failed to decode: " + e.getMessage());
}
```

### Validation Errors

```java
Codec<Integer> validated = Codec.INTEGER.validate(
    i -> i > 0,
    "Value must be positive"
);

// Throws CodecException with message "Value must be positive"
validated.decode(input);  // if input is <= 0
```

## Integration with Assets

Asset types use codecs for JSON definitions:

```java
public class BlockType {
    public static final Codec<BlockType> CODEC = BuilderCodec.of(BlockType::new)
        .with("id", Codec.STRING, b -> b.id)
        .with("name", Codec.STRING, b -> b.name)
        .with("hardness", Codec.FLOAT, b -> b.hardness, 1.0f)
        .with("drops", Codec.STRING.listOf(), b -> b.drops, List.of())
        .build();
    // ...
}
```

## Integration with Packets

Network packets use codecs for serialization:

```java
public class PlayerPositionPacket implements Packet {
    public static final Codec<PlayerPositionPacket> CODEC = BuilderCodec.of(PlayerPositionPacket::new)
        .with("playerId", UUID_CODEC, p -> p.playerId)
        .with("position", Vector3d.CODEC, p -> p.position)
        .with("yaw", Codec.FLOAT, p -> p.yaw)
        .with("pitch", Codec.FLOAT, p -> p.pitch)
        .build();
    // ...
}
```
