Jump to content

[1.17.1] Custom Capabilities


TheOrangeInd

Recommended Posts

I'm trying to add a radiation to my mod and I need to store its value for each player. As I understand it, I should use capability for this.
The problem is that I don't understand well the new capability system in 1.17.
So, can I create a capability to store an integer value? What are the main components of capability in its present form?

Link to comment
Share on other sites

Okay. The second link was really helpful to me. Thanks for it.
I managed to implement the capability I needed, but I'm not sure about the correctness of my approach to serialization.
Anyway, I post the resulting code here.
Thanks again for your help.

My interface:

 
Spoiler

 


public interface IRadiation extends INBTSerializable<CompoundTag>
{
    int getRadLevel();
    void setRadLevel(int value);
}

Its implementation:

Spoiler

public class RadiationCapability implements IRadiation
{
    public static final ResourceLocation ID = new ResourceLocation(MainClass.MODID, "radiation_level");
    private static final String NBT_KEY = "thrad.rad";

    @CapabilityInject(IRadiation.class)
    public static Capability<IRadiation> RADIATION_CAPABILITY = null;
    public static void register() { CapabilityManager.INSTANCE.register(IRadiation.class); }

    private int radLevel;

    public RadiationCapability() { this(Configuration.DEFAULT_RAD_LEVEL); }
    public RadiationCapability(int radLevel) { this.radLevel = radLevel; }

    @Override
    public int getRadLevel() { return radLevel; }

    @Override
    public void setRadLevel(int value) { radLevel = value; }

    @Override
    public CompoundTag serializeNBT()
    {
        CompoundTag nbt = new CompoundTag();
        nbt.putInt(NBT_KEY, getRadLevel());
        return nbt;
    }

    @Override
    public void deserializeNBT(CompoundTag nbt)
    {
        setRadLevel(nbt.getInt(NBT_KEY));
    }
}

 

And its provider:

Spoiler

public class RadiationCapProvider implements ICapabilitySerializable<CompoundTag>
{
    private final Capability<IRadiation> capability;
    private final LazyOptional<IRadiation> implementation;

    public RadiationCapProvider(Capability<IRadiation> cap, LazyOptional<IRadiation> impl)
    {
        capability = cap;
        implementation = impl;
    }

    public static RadiationCapProvider from(Capability<IRadiation> cap, NonNullSupplier<IRadiation> impl)
    {
        return new RadiationCapProvider(cap, LazyOptional.of(impl));
    }

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side)
    {
        if(cap == capability) return implementation.cast();
        return LazyOptional.empty();
    }

    @Override
    public CompoundTag serializeNBT()
    {
        return implementation.isPresent() ? implementation.orElse(null).serializeNBT() : new CompoundTag();
    }

    @Override
    public void deserializeNBT(CompoundTag nbt)
    {
        if(implementation.isPresent()) implementation.orElse(null).deserializeNBT(nbt);
    }
}

 

 

Link to comment
Share on other sites

Should I use an instance of my RadiationCapability for this?

Spoiler

public class RadiationCapProvider implements ICapabilitySerializable<CompoundTag>
{
    private final RadiationCapability instance;
    private final Capability<IRadiation> capability;
    private final LazyOptional<IRadiation> implementation;

    public RadiationCapProvider(Capability<IRadiation> cap, LazyOptional<IRadiation> impl)
    {
        capability = cap;
        implementation = impl;
        instance = (RadiationCapability) impl.orElse(null);
    }

    public static RadiationCapProvider from(Capability<IRadiation> cap, NonNullSupplier<IRadiation> impl)
    {
        return new RadiationCapProvider(cap, LazyOptional.of(impl));
    }

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side)
    {
        if(cap == capability) return implementation.cast();
        return LazyOptional.empty();
    }

    @Override
    public CompoundTag serializeNBT()
    {
        return instance.serializeNBT();
    }

    @Override
    public void deserializeNBT(CompoundTag nbt)
    {
        instance.deserializeNBT(nbt);
    }
}

 

 

Link to comment
Share on other sites

Okay. Now I think that I figured out my mistake and this is how my Provider looks now:

Spoiler

public class RadiationCapProvider implements ICapabilitySerializable<CompoundTag>
{
    private final Capability<IRadiation> capability = RadiationCapability.RADIATION_CAPABILITY;
    private final RadiationCapability instance = new RadiationCapability();

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side)
    {
        if(cap == capability) return LazyOptional.of(()->instance).cast();
        return LazyOptional.empty();
    }

    @Override
    public CompoundTag serializeNBT() { return instance.serializeNBT(); }

    @Override
    public void deserializeNBT(CompoundTag nbt) { instance.deserializeNBT(nbt); }
}

 

Link to comment
Share on other sites

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

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

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