Posted October 10, 20196 yr Hello there,I want to test the save/write function from the nbt feature of a player simplyfied with this: @SubscribeEvent public void onPlayerLoggedInEvent(PlayerLoggedInEvent event) { //load stuff with deserializeNBT() //print original nbt //change nbt to something different event.player.serializeNBT(); //<-- exception here //deserializeNBT stuff again //read changes and print } But I'll get a NullPointerException: java.lang.NullPointerException: Null string not allowed at java.util.Objects.requireNonNull(Unknown Source) at net.minecraft.nbt.NBTTagString.<init>(NBTTagString.java:20) at net.minecraft.nbt.NBTTagCompound.setString(NBTTagCompound.java:172) at net.minecraft.entity.Entity.serializeNBT(Entity.java:3574) ... I attached the capability normally to the player with the AttachCapabilitiesEvent. The provider also looks quite normal to me: private final ITeleportCapability cap; private static final DefaultTeleportStorage<ITeleportCapability> STORAGE = new DefaultTeleportStorage<>(); @Override public NBTBase serializeNBT() { return STORAGE.writeNBT(CAPABILITY_TELEPORT, cap, null); } The writeNBT method from DefaultTeleportStorage looks like this: @Override public NBTBase writeNBT(Capability<T> capability, T instance, EnumFacing side) { if((instance instanceof ITeleportCapability) == false) { throw new RuntimeException(instance.getClass().getName() + "does not implement ITeleportCapability"); } NBTTagCompound nbt = new NBTTagCompound(); ITeleportCapability cap = (ITeleportCapability) instance; nbt.setTag("integerPartition", new NBTTagInt(instance.getFlags())); return nbt; } It fells like it isn't like a problem on the setup of the capability but more of how I use it. Does somebody know what I am doing wrong?Thank you in advantage!
October 10, 20196 yr Author 25 minutes ago, diesieben07 said: Players don't have an entity-type ID, so serializeNBT does not work for them. What are you trying to achieve? I attached a capability to the player entity and I want to mantain them beyond runtime. I read that the INBTSerializable interface is meant to do exactly that. You said that players don't have entity-type ID, so what if I simply cast the player to entity type? <= [EDIT]: doesn't work [EDIT 2]: The cast may not work because of the ID will not be autofilled I guess. Maybe something like this would work: EntityList.createEntityByIDFromName(resource, world) But I don't know how to fille the resource to refer to the player entity. For a sheep it would look like this: EntityList.createEntityByIDFromName(new ResourceLocation("minecraft", "sheep"), world) But changing "sheep" with "player" doesn't seem like the right thing to do. Edited October 10, 20196 yr by AuraXP
October 10, 20196 yr Author 52 minutes ago, diesieben07 said: As long as the ICapabilityProvider you attach implements INBTSerializable, you do not need to do anything else. Your capability will be automatically serialized when the attached entity is saved to disk. Ok, but deserializing has to be done on the other hand? Because the capability will not load the values from my example from the previous runtime by simply calling getCapability just yet.
October 10, 20196 yr Author 14 minutes ago, diesieben07 said: INBTSerializable has two methods, one for reading and one for writing. You have to implement both properly on your ICapabilityProvider. I thought I did that the right way. In total the provider implements the interface like this: public static class TeleportBreakCapabilityProvider implements ICapabilityProvider, INBTSerializable<NBTBase> { private final ITeleportCapability cap; private static final DefaultTeleportStorage<ITeleportCapability> STORAGE = new DefaultTeleportStorage<>(); public TeleportBreakCapabilityProvider() { this.cap = new TeleportCapability(); } @Override public NBTBase serializeNBT() { return STORAGE.writeNBT(CAPABILITY_TELEPORT, cap, null); } @Override public void deserializeNBT(NBTBase nbt) { STORAGE.readNBT(CAPABILITY_TELEPORT, cap, null, nbt); } ... } I am storing only one integer called "teleportBreak" in the nbt in DefaultTeleportStorage. This class has been implemented like this: public class DefaultTeleportStorage <T extends ITeleportCapability> implements Capability.IStorage<T>{ @Override public NBTBase writeNBT(Capability<T> capability, T instance, EnumFacing side) { NBTTagCompound nbt = new NBTTagCompound(); ITeleportCapability cap = (ITeleportCapability) instance; nbt.setInteger("teleportBreak", cap.getFlags()); return nbt; } @Override public void readNBT(Capability<T> capability, T instance, EnumFacing side, NBTBase nbt) { NBTTagCompound tags = new NBTTagCompound(); ITeleportCapability cap = capability.cast(instance); cap.setFlags(tags.getInteger("teleportBreak")); } } It looks pretty normal to me, so I don't know what's the matter with it not working properly.
October 10, 20196 yr Author 32 minutes ago, diesieben07 said: In readNBT you completely ignore the data that you're told to read from and instead create a new, empty tag compound and restore your data from that. Oh, I am sorry I did not see that. This fixed the problem. Thank you for being the one who helped me out, I really appreciate it. This topic is solved.
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.