Asset Codecs
Asset Codecs
Section titled “Asset Codecs”Asset codecs extend the core codec system to support Hytale’s asset loading pipeline. They handle asset identification, parent inheritance, tags, contained assets, and polymorphic asset types.
Package Location
Section titled “Package Location”com.hypixel.hytale.assetstore.codec.AssetCodeccom.hypixel.hytale.assetstore.codec.AssetBuilderCodeccom.hypixel.hytale.assetstore.codec.AssetCodecMapCodeccom.hypixel.hytale.assetstore.codec.ContainedAssetCodeccom.hypixel.hytale.assetstore.AssetExtraInfocom.hypixel.hytale.assetstore.AssetRegistrycom.hypixel.hytale.assetstore.AssetStore
Architecture
Section titled “Architecture”flowchart TB
subgraph Asset["Asset Codec Hierarchy"]
AssetCodecI["AssetCodec<K,T><br/>(Interface)"]
AssetBuilder["AssetBuilderCodec<K,T>"]
AssetMap["AssetCodecMapCodec<K,T>"]
Contained["ContainedAssetCodec<K,T>"]
end
subgraph Core["Core Codecs"]
BuilderCodec["BuilderCodec<T>"]
StringCodecMap["StringCodecMapCodec<T,C>"]
CodecI["Codec<T>"]
end
subgraph Store["Asset System"]
AssetStore["AssetStore<K,T,M>"]
AssetRegistry["AssetRegistry"]
AssetExtraInfo["AssetExtraInfo<K>"]
end
AssetBuilder --> BuilderCodec
AssetBuilder -.-> AssetCodecI
AssetMap --> StringCodecMap
AssetMap -.-> AssetCodecI
Contained --> CodecI
AssetStore --> AssetRegistry
AssetExtraInfo --> AssetStore
AssetCodec<K, T> Interface
Section titled “AssetCodec<K, T> Interface”The base interface for all asset codecs. Extends InheritCodec<T> and ValidatableCodec<T>.
package com.hypixel.hytale.assetstore.codec;
import com.hypixel.hytale.assetstore.AssetExtraInfo;import com.hypixel.hytale.assetstore.JsonAsset;import com.hypixel.hytale.codec.KeyedCodec;
public interface AssetCodec<K, T extends JsonAsset<K>> extends InheritCodec<T>, ValidatableCodec<T> { KeyedCodec<K> getKeyCodec(); KeyedCodec<K> getParentCodec(); AssetExtraInfo.Data getData(T asset); T decodeJsonAsset(RawJsonReader reader, AssetExtraInfo<K> extraInfo) throws IOException; T decodeAndInheritJsonAsset(RawJsonReader reader, T parent, AssetExtraInfo<K> extraInfo) throws IOException;}| Method | Description |
|---|---|
getKeyCodec() | Returns the KeyedCodec for the "Id" field |
getParentCodec() | Returns the KeyedCodec for the "Parent" field |
getData(T) | Gets the AssetExtraInfo.Data attached to the asset |
decodeJsonAsset(...) | Decode a fresh asset from JSON |
decodeAndInheritJsonAsset(...) | Decode with inheritance from a parent asset |
The type parameter K is the asset’s key type (typically String) and T is the asset class which must extend JsonAsset<K>.
AssetBuilderCodec<K, T>
Section titled “AssetBuilderCodec<K, T>”Extends BuilderCodec<T> and implements AssetCodec<K, T>. This is the standard codec for single-type assets that are loaded from JSON files.
Key Features
Section titled “Key Features”- Automatically manages
"Id"and"Parent"fields - Injects
AssetExtraInfo.Datainto decoded assets - Inherits all
BuilderCodeccapabilities (fields, validation, versioning) - Built-in
Tagsfield with automatic tag inheritance and expansion
Tags System
Section titled “Tags System”Every AssetBuilderCodec automatically includes a Tags field (type Map<String, String[]>). Tags are a general categorization mechanism:
{ "Tags": { "Material": ["Solid", "Stone"], "Ore": [] }}Tags expand into a flat list automatically. The above example produces: Ore, Material, Solid, Stone, Material=Solid, Material=Stone. Tags are inherited from parent assets and merged.
Creating an AssetBuilderCodec
Section titled “Creating an AssetBuilderCodec”import com.hypixel.hytale.assetstore.codec.AssetBuilderCodec;import com.hypixel.hytale.assetstore.AssetExtraInfo;import com.hypixel.hytale.codec.Codec;import com.hypixel.hytale.codec.KeyedCodec;
AssetBuilderCodec<String, MyAsset> CODEC = AssetBuilderCodec.builder( MyAsset.class, MyAsset::new, Codec.STRING, (asset, id) -> asset.id = id, asset -> asset.id, (asset, data) -> asset.data = data, asset -> asset.data ) .append( new KeyedCodec<>("DisplayName", Codec.STRING), (asset, name) -> asset.displayName = name, asset -> asset.displayName ) .add() .build();Builder Factory Methods
Section titled “Builder Factory Methods”| Method | Description |
|---|---|
AssetBuilderCodec.builder(class, supplier, idCodec, idSetter, idGetter, dataSetter, dataGetter) | New asset codec |
AssetBuilderCodec.builder(class, supplier, parentCodec, idCodec, idSetter, idGetter, dataSetter, dataGetter) | Asset codec with parent BuilderCodec |
AssetBuilderCodec.wrap(BuilderCodec, idCodec, idSetter, idGetter, dataSetter, dataGetter) | Wrap an existing BuilderCodec as an asset codec |
Decode Flow
Section titled “Decode Flow”- Create instance via supplier
- Inject
AssetExtraInfo.DataviadataSetter - If parent exists, run
inherit()to copy parent field values - Decode JSON fields via
decodeAndInheritJson0() - Set the asset ID from
AssetExtraInfo.getKey() - Run
afterDecodeAndValidate()for validation
Schema Generation
Section titled “Schema Generation”AssetBuilderCodec extends the schema with a Parent property that includes inheritance documentation. The schema indicates which root class the parent reference targets and supports the InheritSettings for tooling.
AssetCodecMapCodec<K, T>
Section titled “AssetCodecMapCodec<K, T>”Extends StringCodecMapCodec<T, AssetBuilderCodec<K, T>> and implements AssetCodec<K, T>. Provides polymorphic asset dispatch based on a "Type" discriminator field.
import com.hypixel.hytale.assetstore.codec.AssetCodecMapCodec;import com.hypixel.hytale.codec.Codec;
AssetCodecMapCodec<String, MyAsset> CODEC = new AssetCodecMapCodec<>( Codec.STRING, (asset, id) -> asset.id = id, asset -> asset.id, (asset, data) -> asset.data = data, asset -> asset.data);
CODEC.register("TypeA", TypeAAsset.class, TypeAAsset.BUILDER_CODEC);CODEC.register("TypeB", TypeBAsset.class, TypeBAsset.BUILDER_CODEC);How Registration Works
Section titled “How Registration Works”When register() is called with a BuilderCodec, the AssetCodecMapCodec automatically wraps it in an AssetBuilderCodec via AssetBuilderCodec.wrap(). This means you register plain BuilderCodec instances and the asset wrapping is handled internally.
Type Resolution During Decoding
Section titled “Type Resolution During Decoding”When decoding JSON, the codec:
- Seeks the discriminator field (default
"Type") in the JSON - If no type field is found but a parent exists, uses the parent’s registered type
- Looks up the codec by type string
- Falls back to the default codec if
allowDefaultis true - Delegates to the matched
AssetBuilderCodecfor actual decoding
Constructor Variants
Section titled “Constructor Variants”| Constructor | Description |
|---|---|
AssetCodecMapCodec(idCodec, idSetter, idGetter, dataSetter, dataGetter) | Default "Type" key |
AssetCodecMapCodec(key, idCodec, ...) | Custom discriminator key |
AssetCodecMapCodec(idCodec, ..., allowDefault) | With default codec fallback |
AssetCodecMapCodec(key, idCodec, ..., allowDefault) | Custom key and default fallback |
ContainedAssetCodec<K, T>
Section titled “ContainedAssetCodec<K, T>”A Codec<K> that handles assets embedded inline within other assets. Instead of decoding the contained asset immediately, it captures the raw JSON and registers it as a RawAsset for deferred processing by the AssetStore.
| Mode | Description |
|---|---|
NONE | Not allowed (throws UnsupportedOperationException) |
GENERATE_ID | Generates a unique ID for the contained asset (prefixed with *) |
INHERIT_ID | Uses the parent asset’s key, transformed by the target asset store |
INHERIT_ID_AND_PARENT | Inherits ID and also sets parent from the container’s parent |
INJECT_PARENT | Generates a unique ID but sets the container asset as the parent |
import com.hypixel.hytale.assetstore.codec.ContainedAssetCodec;
ContainedAssetCodec<String, MySubAsset> contained = new ContainedAssetCodec<>(MySubAsset.class, MySubAsset.CODEC);
ContainedAssetCodec<String, MySubAsset> withMode = new ContainedAssetCodec<>(MySubAsset.class, MySubAsset.CODEC, ContainedAssetCodec.Mode.INHERIT_ID);Behavior
Section titled “Behavior”When decoding:
- If the value is a string, it is treated as a reference to an existing asset (the key is decoded directly)
- If the value is an object, it is treated as an inline asset definition:
- The mode determines the ID assignment strategy
- The raw JSON is cloned and stored as a
RawAsset - The
RawAssetis added toAssetExtraInfo.Data.addContainedAsset() - The generated/inherited key is returned
This deferred loading allows the asset store to process contained assets after all top-level assets are loaded, resolving parent references correctly.
JSON Examples
Section titled “JSON Examples”Reference to existing asset:
{ "SubAsset": "my_sub_asset"}Inline asset definition:
{ "SubAsset": { "Parent": "base_sub_asset", "CustomField": 42 }}Schema Output
Section titled “Schema Output”The schema for a ContainedAssetCodec field produces an anyOf schema: either a string reference (key) or a nested object matching the asset codec’s schema.
AssetExtraInfo
Section titled “AssetExtraInfo”AssetExtraInfo<K> extends ExtraInfo and carries asset-specific context through the decode process:
getKey()- The asset’s ID being decodedgetData()- TheAssetExtraInfo.Datafor the current assetgetAssetPath()- The file path of the JSON file being loadedgenerateKey()- Generate a unique key for contained assets (prefixed with*)
AssetExtraInfo.Data
Section titled “AssetExtraInfo.Data”Tracks metadata for a decoded asset:
- Parent key tracking
- Contained asset collection (per asset class)
- Raw tag storage and tag expansion
- Source file path
Integration with AssetStore
Section titled “Integration with AssetStore”The asset codec system integrates with AssetStore and AssetRegistry:
flowchart LR
JSONFile["JSON File"] --> AssetStore
AssetStore --> |creates| AssetExtraInfo
AssetExtraInfo --> |passed to| AssetCodec
AssetCodec --> |decodes| Asset["JsonAsset<K>"]
Asset --> |stored in| AssetMap["AssetMap<K,T>"]
AssetStore --> |processes| ContainedAssets["Contained Assets"]
ContainedAssets --> |decoded with| ParentLookup["Parent Lookup"]
AssetStorereads JSON files and createsAssetExtraInfowith the file path and asset key- The
AssetCodec(eitherAssetBuilderCodecorAssetCodecMapCodec) decodes the JSON - Parent references (
"Parent"field) triggerdecodeAndInheritwhich copies fields from the parent asset - Contained assets are collected as
RawAssetinstances and processed in a second pass - Decoded assets are stored in the
AssetMapand accessible viaAssetRegistry
Related
Section titled “Related”- Serialization Overview - Core Codec<T> interface and built-in codecs
- Component Codecs - BuilderCodec, validation, versioning
- Creating Custom Codecs - Step-by-step guide to building codecs