This is a Minecraft serialization package for automatic serialization and de-serialization of Java and Minecraft objects, to JSON, NBT, and packets. Note that not all objects support all ways of serialization, though they will be specially marked as such.
- All Primitive types and their boxed types (
char,byte,short,int,long,float,double,boolean) - Commonly used Java objects (
String,UUID) - Collections or collection-like of leaf class (
Set,List,Map,Record,Enum,Array).- Note that they must be in leaf class. For example,
List<String>is illegal, butArrayList<String>is good. - Make sure the classes (except record) have a default constructor with no parameters.
- For enum, only leaf class allowed. Parameterized types such as
<T extends Enum & Ixxx>is not allowed. - For record, parameterized types are allowed. You can use
<T extends Record & Ixxx>to represent a record that implements interfaceIxxx.
- Note that they must be in leaf class. For example,
- Commonly used registered Minecraft objects
- Default implementation supports
Item,Block,Enchantment,MobEffect,Potion,EntityType - You can add others yourself using
RLClassHandler. Example:new RLClassHandler<>(Item.class, () -> ForgeRegistries.ITEMS); - Datapack registry not allowed.
- For custom registry, you need to register them through
RLClassHandler. If you are usingL2Registrate, it handles automatically for you.
- Default implementation supports
- Common Minecraft Objects
ResourceLocation,ItemStack,FluidStack
- Classes you defines that are marked as
@SerialClass
Ingredient
- NBT elements:
CompountTag,ListTag - Simple class that serves as record:
BlockPos,Vec3,MobEffectInstance- If you want to use these in json, please create a record.
Note that ItemStack and Ingredient cannot be null: null value will be treated as ItemStack.EMPTY and Ingredient.EMPTY respectively.
To mark a class as serializable, you need to also mark its fields. Here is an example:
// Mark this class as serializable
@SerialClass
public class TestClassA {
// regular field. private is allowed.
@SerialClass.SerialField
private String name;
// final field. During de-serialziation,
// this object will have values injected
// instead of constructed again
@SerialClass.SerialField
private final TestClassB base = new TestClassB(this);
// for collections, being final or not doesn't matter
@SerialClass.SerialField
public final ArrayList<TestClassB> list = new ArrayList<>();
// supports nested collections and maps
@SerialClass.SerialField
public final HashMap<Item, ArrayList<ItemStack>> list = new HashMap<>();
// this field is ignored during serialization
private boolean valid;
// to be de-serializable directly,
// it needs to have a default constructor
@Deprecated
public TestClassA(){
}
// Optional. This method will be called after de-serialization.
@SerialClass.OnInject
public void onInject(){
valid = true;
}
// regular constructor
public TestClassA(String name){
this.name = name;
this.valid = true;
// warning: if the object serialized doesn't match
// its declared class, the algorithm will serialize
// the class name as well. Same for records.
list.add(new TestClassC(this));
}
}
@SerialClass
public class TestClassB {
// do not loop reference
public final TestClassA parent;
@SerialClass.SerialField
public int value;
// This class cannot be constructed directly
// but can still have injections
public TestClassB(TestClassA parent) {
this.parent = parent;
}
}
// inheritance allowed.
// However, they must not have fields of the same name.
@SerialClass
public class TestClassC extends TestClassB {
@SerialClass.SerialField
public double secondValue;
public TestClassB(TestClassA parent) {
super(parent);
}
}
// records don't need annotation
public record TestClassD(int a, TestClassA obj) {
}How to serialize:
public class Test {
public static void jsonConvert() {
TestClassA obj = new TestClassA("abc");
// convert obj to json
JsonElement a = JsonCodec.toJson(obj);
// convert json back to obj, constructing object
TestClassA rec = JsonCodec.from(TestClassA.class, json, null);
//convert obj to json, but mark available type information
JsonElement b = JsonCodec.toJson(a.base, TestClassB.class);
// inject data into existing object
JsonCodec.from(TestClassB.class, c, a.base);
JsonObject json = new JsonObject();
// inject data into existing json object
JsonCodec.toJsonObject(obj, json);
}
}Same for NBT and Packets. Note that NBT has 9 methods of 4 type:
TagCodec::toTag: serialize@SerialClassobject to tagTagCodec::valueToTag: serialize any value to tagTagCodec::fromTag: deserialize@SerialClassobject from tagTagCodec::valueFromTag: deserialize any value from tag Also, it supports 3 different serialization filter:- All: serialize everything
- toClient: serialize fields that are marked as toClient only
- This is for BlockEntity and Entity synchronization
- toTracking: serialize fields that are marked as toTracking only
- This is for Capability syncronization
This library also comes with a networking tool. The BasePacketHandler can
simplify packet handing by a lot. You only need to extend SerialPacketBase,
mark your class as @SerialClass, mark your fields to serialize as @SerialClass.SerialField,
and implement handle method. The method will be executed in main thread.
It also has functions to send a packet to server, to one client, to all clients, to tracking clients of an entity, and to tracking clients of a block.