96 lines
4.3 KiB
Java
96 lines
4.3 KiB
Java
|
package org.example.examplemod.mixin;
|
||
|
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.Arrays;
|
||
|
import java.util.List;
|
||
|
import java.util.UUID;
|
||
|
import net.minecraft.entity.player.PlayerEntity;
|
||
|
import net.minecraft.nbt.NbtCompound;
|
||
|
import net.minecraft.nbt.NbtElement;
|
||
|
import net.minecraft.nbt.NbtList;
|
||
|
import org.spongepowered.asm.mixin.Mixin;
|
||
|
import org.spongepowered.asm.mixin.Unique;
|
||
|
import org.spongepowered.asm.mixin.injection.At;
|
||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||
|
|
||
|
@Mixin(PlayerEntity.class)
|
||
|
public abstract class PlayerEntityMixin {
|
||
|
@Unique
|
||
|
public List<MyObject> myList = new ArrayList<>();
|
||
|
|
||
|
// I recommend you read writeMyDataToNbt first before trying to understand readCustomDataFromNbt
|
||
|
@Inject(method = "readCustomDataFromNbt", at = @At("TAIL"))
|
||
|
public void readMyDataFromNbt(NbtCompound playerNbt, CallbackInfo ci) {
|
||
|
// read our serialized list
|
||
|
NbtList myListNbt = playerNbt.getList("MyList", NbtElement.COMPOUND_TYPE);
|
||
|
|
||
|
// iterate over its items
|
||
|
for (int i = 0; i < myListNbt.size(); i++) {
|
||
|
// construct the object we need to deserialize
|
||
|
MyObject myObject = new MyObject();
|
||
|
// read the serialized object
|
||
|
NbtCompound myObjectNbt = myListNbt.getCompound(i);
|
||
|
|
||
|
// read properties that are supported and write them to our object
|
||
|
myObject.mySupportedObject = myObjectNbt.getInt("MySupportedObject");
|
||
|
// if mySupportedList was int[], we could've just used getIntArray, but since it's a List<Integer>, we have to do something else
|
||
|
Arrays.stream(myObjectNbt.getIntArray("MySupportedList")).forEach(myInteger -> myObject.mySupportedList.add(myInteger));
|
||
|
|
||
|
// read properties that aren't supported
|
||
|
MyAnotherObject myAnotherObject = new MyAnotherObject();
|
||
|
NbtCompound myNotSupportedObjectNbt = myObjectNbt.getCompound("MyNotSupportedObject");
|
||
|
myAnotherObject.myUuid = myNotSupportedObjectNbt.getUuid("MyUUID");
|
||
|
|
||
|
// write them to our object
|
||
|
myObject.myNotSupportedObject = myAnotherObject;
|
||
|
|
||
|
// finally, add our constructed object to our list
|
||
|
myList.add(myObject);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Inject(method = "writeCustomDataToNbt", at = @At("TAIL"))
|
||
|
public void writeMyDataToNbt(NbtCompound playerNbt, CallbackInfo ci) {
|
||
|
// create a new NBT record for our list
|
||
|
NbtCompound myListNbt = new NbtCompound();
|
||
|
|
||
|
// you can use a regular for-loop if you want, there's no difference. FabricMC wiki uses Iterable#forEach so that's why it's used here
|
||
|
myList.forEach(myObject -> {
|
||
|
// create a new NBT record for our object
|
||
|
NbtCompound myObjectNbt = new NbtCompound();
|
||
|
// write properties that are supported
|
||
|
myObjectNbt.putInt("MySupportedObject", myObject.mySupportedObject);
|
||
|
myObjectNbt.putIntArray("MySupportedList", myObject.mySupportedList);
|
||
|
|
||
|
// write myNotSupportedObject, which doesn't have a method for reading/writing in NbtCompound
|
||
|
NbtCompound myNotSupportedObjectNbt = new NbtCompound();
|
||
|
myNotSupportedObjectNbt.putUuid("MyUUID", myObject.myNotSupportedObject.myUuid);
|
||
|
|
||
|
// you can nest NBT records infinitely
|
||
|
myObjectNbt.put("MyNotSupportedObject", myNotSupportedObjectNbt);
|
||
|
|
||
|
// put our newly created record into the list record
|
||
|
myListNbt.put("MyObject", myObjectNbt);
|
||
|
});
|
||
|
|
||
|
// finally, put our list record into the player's NBT
|
||
|
playerNbt.put("MyList", myListNbt);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// these classes are in the same file for simplicity sake. you should make them public and put them in their own files
|
||
|
class MyObject {
|
||
|
// the NbtCompound class has methods to write and read this object - putInt and getInt
|
||
|
public int mySupportedObject = 0;
|
||
|
// there are even some supported lists! this one uses putIntArray
|
||
|
public List<Integer> mySupportedList = new ArrayList<>();
|
||
|
// if there's no method in NbtCompound to handle your class,
|
||
|
// you'll have to write their properties separately and, when reading, construct the objects using the written properties
|
||
|
// just how are we currently doing with this object
|
||
|
public MyAnotherObject myNotSupportedObject;
|
||
|
}
|
||
|
|
||
|
class MyAnotherObject {
|
||
|
public UUID myUuid;
|
||
|
}
|