Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Featured Replies

Posted

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 by Ghost20000

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);
}

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 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".

  • 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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

Important Information

By using this site, you agree to our Terms of Use.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.