Posted July 14, 20205 yr There seems to be a lot of conflicting information out there on creating capabilities. On what classes/interfaces you need, what needs to implement what, whether serializeNBT should call writeNBT or the other way around, etc. I understand there's probably a lot of ways to create a capability, but I just want the simplest possible thing. I have a capability which I only want 1 item to use. It'll be able to store an EntityType, and serialize it into a String or deserialize it from a String when needed. Right now I have 2 classes, Pet and PetCapability: public class Pet implements INBTSerializable<CompoundNBT> { private EntityType<?> entityType; public Pet() { this.entityType = null; } @Override public CompoundNBT serializeNBT() { CompoundNBT result = new CompoundNBT(); String entityTypeString = EntityType.getKey(this.entityType).toString(); result.putString("entityType", entityTypeString); return result; } @Override public void deserializeNBT(CompoundNBT nbt) { if (nbt.contains("entityType")) { String entityTypeString = nbt.getString("entityType"); this.entityType = EntityType.byKey(entityTypeString).get(); } } } public class PetCapability { @CapabilityInject(Pet.class) public static Capability<Pet> CAPABILITY_PET = null; public static void register() { CapabilityManager.INSTANCE.register(Pet.class, new PetStorage(), () -> new Pet()); } public static class PetStorage implements IStorage<Pet> { @Override public void readNBT(Capability<Pet> capability, Pet instance, Direction side, INBT nbt) { instance.deserializeNBT((CompoundNBT) nbt); } @Override public INBT writeNBT(Capability<Pet> capability, Pet instance, Direction side) { return instance.serializeNBT(); } } } Where do I go from here? I need a provider to attach to capability to the item right? Are my classes ok? Am I doing something where I shouldn't be doing it? Thanks! Edited July 14, 20205 yr by Ghost20000
July 14, 20205 yr You need an interface to make a capability, I'd say you should call it IPet, Pet should implement it and you should pass in IPet in @CapabilityInject and the first parameter of register. The interface should look something like this with what you're currently doing: public interface IExample { EntityType<?> getEntityType(); void setEntityType(EntityType<?> type); } I strongly recommend you use generics instead if you can, something like this: public interface IExample { <T extends Entity> EntityType<T> getEntityType(); <T extends Entity> void setEntityType(EntityType<T> type); } Ping me or something next post, I'll help you out if I can. Edit: Oh come on, solved as I was posting. Edited July 14, 20205 yr by Novârch It's sad how much time mods spend saying "x is no longer supported on this forum. Please update to a modern version of Minecraft to receive support".
July 14, 20205 yr Author I ended up solving this with some help from the MinecraftByExample repo. public class Pet { private EntityType<?> entityType; public Pet() { this.entityType = null; } public String getEntityTypeString() { if (this.entityType == null) { return null; } return EntityType.getKey(this.entityType).toString(); } public EntityType<?> getEntityType() { return this.entityType; } public void setEntityType(String entityType) { this.entityType = EntityType.byKey(entityType).get(); } public void setEntityType(EntityType<?> entityType) { this.entityType = entityType; } } public class PetCapability { @CapabilityInject(Pet.class) public static Capability<Pet> CAPABILITY_PET = null; public static void register() { CapabilityManager.INSTANCE.register(Pet.class, new PetStorage(), () -> new Pet()); } public static class PetStorage implements IStorage<Pet> { @Override public void readNBT(Capability<Pet> capability, Pet instance, Direction side, INBT nbt) { if (nbt instanceof CompoundNBT && ((CompoundNBT) nbt).contains("type")) { String entityType = ((CompoundNBT) nbt).getString("type"); instance.setEntityType(entityType); } } @Override public INBT writeNBT(Capability<Pet> capability, Pet instance, Direction side) { CompoundNBT result = new CompoundNBT(); String entityTypeString = instance.getEntityTypeString(); if (entityTypeString != null) { result.putString("type", entityTypeString); } return result; } } } public class PetCapabilityProvider implements ICapabilitySerializable<INBT> { private Pet pet = new Pet(); @Override public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) { if (cap == PetCapability.CAPABILITY_PET) { return (LazyOptional<T>) LazyOptional.of(() -> pet); } return LazyOptional.empty(); } @Override public INBT serializeNBT() { return PetCapability.CAPABILITY_PET.writeNBT(pet, null); } @Override public void deserializeNBT(INBT nbt) { PetCapability.CAPABILITY_PET.readNBT(pet, null, nbt); } } Then register in the FMLCommonSetupEvent in your mod event subscriber and in your item class add the following function: @Override public ICapabilityProvider initCapabilities(ItemStack stack, CompoundNBT nbt) { return new PetCapabilityProvider(); } Whenever you want to access the capability, just get the ItemStack and call GetCapability on it. If it's null, something went wrong, but if it's an instance of Pet, you can access it!
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.