Changes

1,442 bytes added ,  18:45, 10 January 2024
m
Line 5: Line 5:  
== Serialization and Deserialization ==
 
== Serialization and Deserialization ==
   −
The primary use for Codecs is to serialize java objects to some serialized type, such as a JsonElement or a Tag, and to deserialize an serialized object back to its proper java type. This is accomplished with <code>Codec#encodeStart</code> and <code>Codec#parse</code>, respectively. Given a Codec<SomeJavaType> and a DynamicOps<SomeSerializedType>, we can convert instances of SomeJavaType to instances of SomeSerializedType and back.
+
The primary use for Codecs is to serialize java objects to some serialized type, such as a JsonElement or a Tag, and to deserialize a serialized object back to its proper java type. This is accomplished with <code>Codec#encodeStart</code> and <code>Codec#parse</code>, respectively. Given a Codec<SomeJavaType> and a DynamicOps<SomeSerializedType>, we can convert instances of SomeJavaType to instances of SomeSerializedType and back.
    
Each of these methods take a [[DynamicOps]] instance and an instance of the object we are serializing or deserializing, and returns a DataResult:
 
Each of these methods take a [[DynamicOps]] instance and an instance of the object we are serializing or deserializing, and returns a DataResult:
Line 18: Line 18:     
// deserialize some Tag instance back to a proper java object
 
// deserialize some Tag instance back to a proper java object
DataResult<SomeJavaType> result = someCodec.parse(NBTOps.INSTANCE, someTag );
+
DataResult<SomeJavaType> result = someCodec.parse(NBTOps.INSTANCE, someTag);
    
// serialize some java object to a JsonElement
 
// serialize some java object to a JsonElement
Line 92: Line 92:  
As previously mentioned, we can use <code>Codec.INT</code> for the integer codec, and <code>Registry.ITEM</code> for the Item codec. We don't have a builtin codec for list-of-blockpos, but we can use BlockPos.CODEC to create one.
 
As previously mentioned, we can use <code>Codec.INT</code> for the integer codec, and <code>Registry.ITEM</code> for the Item codec. We don't have a builtin codec for list-of-blockpos, but we can use BlockPos.CODEC to create one.
   −
== Lists ==
+
==Lists==
 
The <code>Codec#listOf</code> instance method can be used to generate a codec for a List from an existing codec:
 
The <code>Codec#listOf</code> instance method can be used to generate a codec for a List from an existing codec:
    
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
 
// BlockPos.CODEC is a Codec<BlockPos>
 
// BlockPos.CODEC is a Codec<BlockPos>
Codec<List<BlockPos>> = BlockPos.CODEC.listOf();
+
Codec<List<BlockPos>> blockPosListCodec = BlockPos.CODEC.listOf();
 
</syntaxhighlight>
 
</syntaxhighlight>
   Line 166: Line 166:  
Codec.STRING.fieldOf("name").codec());
 
Codec.STRING.fieldOf("name").codec());
   −
JsonElement encodedPair = BOXED_INT_CODEC.encodeStart(JsonOps.INSTANCE, Pair.of(5, "cheese").result().get();
+
JsonElement encodedPair = PAIR_CODEC.encodeStart(JsonOps.INSTANCE, Pair.of(5, "cheese").result().get();
 
</syntaxhighlight>
 
</syntaxhighlight>
 
This codec serializes the above value to:
 
This codec serializes the above value to:
Line 267: Line 267:  
* BlockPlacer and BlockPlacerType
 
* BlockPlacer and BlockPlacerType
 
* ConfiguredDecorator and FeatureDecorator
 
* ConfiguredDecorator and FeatureDecorator
 +
 +
=== Registering MapCodecCodecs for Dispatch Subcodecs ===
 +
 +
When registering a subcodec to any dispatch codec registry, the registered subcodec should be an instance of MapCodecCodec, or the subcodec will be nested in its own object when serialized.
 +
 +
For example, suppose we register a single-field subcodec, where we use fieldOf-and-xmap to convert an int to our int-holding Thing:
 +
 +
<syntaxhighlight lang="java">
 +
public record Thing(int n){}
 +
public static Codec<Thing> CODEC = Codec.INT.fieldOf("n").codec().xmap(Thing::new, Thing::n);
 +
</syntaxhighlight>
 +
 +
This results in this json when serialized:
 +
 +
<syntaxhighlight lang="json">
 +
"some_thing":
 +
{
 +
"type": "ourmod:thing",
 +
"value": {
 +
"n": 5
 +
}
 +
}
 +
</syntaxhighlight>
 +
 +
This occurs because xmap does not produce a MapCodecCodec, and if this nested object is not desired, then our registered subcodec must be a MapCodecCodec.
 +
 +
However, fieldOf() produces a MapCodec, which has a codec() method, which does produce a MapCodecCodec. We can rearrange our codec builder, which then produces a cleaner json:
 +
 +
<syntaxhighlight lang="java">
 +
public static Codec<Thing> CODEC = Codec.INT // Primitive codec
 +
.fieldOf("n") // MapCodec
 +
.xmap(Thing::new, Thing::n) // MapCodec
 +
.codec(); // MapCodecCodec! That's what we want.
 +
</syntaxhighlight>
 +
 +
<syntaxhighlight lang="json">
 +
"some_thing":
 +
{
 +
"type": "ourmod:thing",
 +
"n": 5
 +
}
 +
</syntaxhighlight>
 +
 +
RecordCodecBuilder also produces MapCodecCodecs.
    
=External Links=
 
=External Links=
 
* [https://github.com/Mojang/DataFixerUpper/blob/master/src/main/java/com/mojang/serialization/Codec.java Codecs in Mojang's official public DataFixerUpper repository]
 
* [https://github.com/Mojang/DataFixerUpper/blob/master/src/main/java/com/mojang/serialization/Codec.java Codecs in Mojang's official public DataFixerUpper repository]
 
* [https://kvverti.github.io/Documented-DataFixerUpper/snapshot/com/mojang/serialization/Codec.html#flatXmap-java.util.function.Function-java.util.function.Function- Unofficial Codec Javadocs]
 
* [https://kvverti.github.io/Documented-DataFixerUpper/snapshot/com/mojang/serialization/Codec.html#flatXmap-java.util.function.Function-java.util.function.Function- Unofficial Codec Javadocs]