Jump to content

Recommended Posts

Posted (edited)

I created a capability for player to write a custom inventory for each player. But I do not really understant how to get the data stored in the capability.
Heres some classes:

The IStorage

Spoiler

public class IStorageInstance implements Capability.IStorage<AltarCapabilty> {

    @Nullable
    @Override
    public INBT writeNBT(Capability<AltarCapabilty> capability, AltarCapabilty instance, Direction side) {
        ListNBT listnbt = new ListNBT();

        for(int i = 0; i < 9; ++i) {
            ItemStack itemstack = instance.getStackInSlot(i);
            if (!itemstack.isEmpty()) {
                CompoundNBT compoundnbt = new CompoundNBT();
                compoundnbt.putByte("SlotAltar", (byte)i);
                itemstack.save(compoundnbt);
                listnbt.add(compoundnbt);
            }
        }

        return listnbt;
    }

    @Override
    public void readNBT(Capability<AltarCapabilty> capability, AltarCapabilty instance, Direction side, INBT nbt) {
        if(nbt instanceof ListNBT) {
            ListNBT p_70486_1_ = (ListNBT) nbt;

            for(int i = 0; i < 9; ++i) {
                instance.insertItem(i, ItemStack.EMPTY, false);
            }

            for(int k = 0; k < p_70486_1_.size(); ++k) {
                CompoundNBT compoundnbt = p_70486_1_.getCompound(k);
                int j = compoundnbt.getByte("SlotAltar") & 255;
                if (j >= 0 && j < 9) {
                    instance.insertItem(j, ItemStack.of(compoundnbt), false);
                }
            }
        }
    }
}

 

The default capability:

Spoiler

public class DefaultAltarCapability implements AltarCapabilty{

    private NonNullList<ItemStack> items = NonNullList.withSize(9, ItemStack.EMPTY);

    @Override
    public int getSlots() {
        return items.size();
    }

    @Nonnull
    @Override
    public ItemStack getStackInSlot(int slot) {
        return items.get(slot);
    }

    @Nonnull
    @Override
    public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) {
        if(simulate){
            try{
                return items.set(slot, stack);
            } catch (Exception ex){
                System.out.println(ex);
                return stack;
            }
        }

        return items.set(slot, stack);
    }

    @Nonnull
    @Override
    public ItemStack extractItem(int slot, int amount, boolean simulate) {
        if(simulate){
            try{
                items.get(slot).setCount(items.get(slot).getCount() - amount);
                return items.get(slot);
            } catch (Exception ex){
                System.out.println(ex);
                return items.get(slot);
            }
        }

        items.get(slot).setCount(items.get(slot).getCount() - amount);
        return items.get(slot);
    }

    @Override
    public int getSlotLimit(int slot) {
        return items.get(slot).getMaxStackSize();
    }

    @Override
    public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
        return true;
    }

    public NonNullList<ItemStack> getItems() {
        return items;
    }

    public void setItems(NonNullList<ItemStack> items) {
        this.items = items;
    }
}

 

The CapabilitySerializable:

Spoiler

public class AltarProvider implements ICapabilitySerializable<CompoundNBT> {

    private final DefaultAltarCapability defaultAltarCapability = new DefaultAltarCapability();
    private final LazyOptional<AltarCapabilty> altarCapabilty = LazyOptional.of( ()-> defaultAltarCapability);

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
        return altarCapabilty.cast();
    }

    @Override
    public CompoundNBT serializeNBT() {
        if(CapabilityInstance.ALTAR_CAPABILITY == null){
            return new CompoundNBT();
        } else {
            return (CompoundNBT) CapabilityInstance.ALTAR_CAPABILITY.writeNBT(defaultAltarCapability, null);

        }
    }

    @Override
    public void deserializeNBT(CompoundNBT nbt) {
        if(CapabilityInstance.ALTAR_CAPABILITY != null){
            CapabilityInstance.ALTAR_CAPABILITY.readNBT(defaultAltarCapability, null, nbt);
        }
    }

}

 

The tile entity:

Spoiler

public class AltarTileEntity extends LockableTileEntity {


    public AltarTileEntity() {
        super(ModTileEntityTypes.ALTAR.get());

    }





    @Override
    protected ITextComponent getDefaultName() {
        TextComponent nome = new StringTextComponent("Altar");
        return nome;
    }

    @Override
    protected Container createMenu(int containerId,
                                   PlayerInventory playerInventory) {


        Inventory items = loadItems(playerInventory.player);
        return new ModAltarContainer(ModContainers.ALTAR_TYPE.get(),
                containerId,
                playerInventory,
                items);



    }

    @Override
    public int getContainerSize() {
        return 9;
    }

    @Override
    public boolean isEmpty() {
        return true;
    }

    @Override
    public ItemStack getItem(int i) {
        return this.getItems().get(i);
    }

    @Override
    public ItemStack removeItem(int i, int count) {
        ItemStack itemstack = ItemStackHelper.removeItem(this.getItems(), i, count);
        if (!itemstack.isEmpty()) {
            this.setChanged();
        }

        return itemstack;


    }

    @Override
    public ItemStack removeItemNoUpdate(int i) {
        return ItemStackHelper.takeItem(this.getItems(), i);
    }

    @Override
    public void setItem(int i, ItemStack item) {

        this.getItems().set(i, item);
        if (item.getCount() > this.getMaxStackSize()) {
            item.setCount(this.getMaxStackSize());
        }

        this.setChanged();


    }

    @Override
    public boolean stillValid(PlayerEntity playerEntity) {

        if (this.level.getBlockEntity(this.worldPosition) != this) {
            return false;
        } else {
            return !(playerEntity.distanceToSqr((double)this.worldPosition.getX() + 0.5D, (double)this.worldPosition.getY() + 0.5D, (double)this.worldPosition.getZ() + 0.5D) > 64.0D);
        }

    }

    @Override
    public void clearContent() {
        this.getItems().clear();
    }


    protected NonNullList<ItemStack> getItems() {
        return NonNullList.withSize(9, ItemStack.EMPTY);
    }




    private Inventory loadItems(PlayerEntity player){
        NonNullList<ItemStack> items = NonNullList.withSize(9, ItemStack.EMPTY);
        player.getCapability(CapabilityInstance.ALTAR_CAPABILITY).ifPresent(inv ->{
            for(int i = 0; i < 9 ; i++){
                items.set(i, inv.getStackInSlot(i));
            }
        });
        Inventory inventory = new Inventory(9);
        for(int i = 0; i < 9; i++){
            inventory.setItem(i, items.get(i));
        }
        return inventory;
    }



}

 

And the container's class:

Spoiler

@Mod.EventBusSubscriber
public class ModAltarContainer extends Container {

    private static Container containerInstance;
    private IInventory altar;
    private static ContainerType menuType;
    private NonNullList<Slot> altarSlots = NonNullList.withSize(45, new Slot(altar, 0, 0, 0));



    public ModAltarContainer(int i, PlayerInventory playerInventory) {
        this(ModContainers.ALTAR_TYPE.get(), i, playerInventory,
                new Inventory(9));
    }



    public ModAltarContainer(@Nullable ContainerType<?> containerType,
                             int containerId,
                             PlayerInventory invPlayer,
                             IInventory inventory) {

        super(containerType, containerId);
        containerInstance = this;
        altar = inventory;
        altarSlots.clear();
        menuType = this.getType();
        for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 3; ++j) {
                Slot slot = new Slot(altar, j + i * 3, 62 + j * 18, 17 + i * 18);
                altarSlots.set(j + i * 3, slot);
                this.addSlot(slot);
            }
        }


        for (int k = 0; k < 3; ++k) {
            for (int i1 = 0; i1 < 9; ++i1) {
                Slot slot = new Slot(invPlayer, i1 + k * 9 + 9, 8 + i1 * 18, 84 + k * 18);
                altarSlots.set(i1 + k * 9 + 9, slot);
                this.addSlot(slot);
            }
        }

        for (int l = 0; l < 9; ++l) {
            Slot slot = new Slot(invPlayer, l, 8 + l * 18, 142);
            altarSlots.set(36 + l, slot);
            this.addSlot(slot);
        }
    }



    @Override
    protected Slot addSlot(Slot slot) {
        return super.addSlot(slot);
    }




    @Override
    public boolean stillValid(PlayerEntity jogador) {
        return altar.stillValid(jogador);
    }


    @Override
    public ContainerType<?> getType() {
        return ModContainers.ALTAR_TYPE.get();

    }

    public void removed(PlayerEntity p_75134_1_) {
        super.removed(p_75134_1_);
        this.altar.stopOpen(p_75134_1_);
    }

    @SubscribeEvent
    public static void saveAltarItems(PlayerContainerEvent.Close event){
        PlayerEntity jogador = event.getPlayer();
        if(event.getContainer() instanceof ModAltarContainer){
            saveItems(event.getContainer(), jogador);
        }
        /*
        NonNullList<ItemStack> lista = NonNullList.withSize(9, ItemStack.EMPTY);
        if(event.getContainer().getType().equals(menuType)){
            Container cont = event.getContainer();
            ListNBT listnbt = new ListNBT();
            for(int i = 0; i < 9; i++){
                ItemStack itemstack = cont.getItems().get(i);
                lista.set(i, itemstack);
                CompoundNBT compoundnbt = new CompoundNBT();
                compoundnbt.putByte("SlotAltar", (byte)i);
                itemstack.save(compoundnbt);
                listnbt.add(compoundnbt);
            }

            new InventoryStorage().readNBT(AltarCapabilityDef.ALTAR_INVENTORY,
                    AltarCapabilityDef.ALTAR_INVENTORY.getDefaultInstance(),
                    null,
                    listnbt);


            PlayerEvolution.setStats(lista, jogador);


        }

         */

    }
    public static void saveItems(Container cont, PlayerEntity jogador){


    }



    @Override
    public ItemStack clicked(int p_184996_1_, int p_184996_2_, ClickType p_184996_3_, PlayerEntity p_184996_4_) {
        return super.clicked(p_184996_1_, p_184996_2_, p_184996_3_, p_184996_4_);
    }

    @Override
    public ItemStack quickMoveStack(PlayerEntity p_82846_1_, int p_82846_2_) {
        ItemStack itemstack = ItemStack.EMPTY;
        Slot slot = this.slots.get(p_82846_2_);
        if (slot != null && slot.hasItem()) {
            ItemStack itemstack1 = slot.getItem();
            itemstack = itemstack1.copy();
            if (p_82846_2_ < 9) {
                if (!this.moveItemStackTo(itemstack1, 9, this.slots.size(), true)) {
                    return ItemStack.EMPTY;
                }
            } else if (!this.moveItemStackTo(itemstack1, 0, 9, false)) {
                return ItemStack.EMPTY;
            }

            if (itemstack1.isEmpty()) {
                slot.set(ItemStack.EMPTY);
            } else {
                slot.setChanged();
            }
        }

        return itemstack;
    }

}

 

 

Edited by LuccaPossamai
Posted

Why do you have a tile entity? isn't the capability for the player entity?

What's  the purpose of IStorageInstance? and what's the difference between AltarCapability and DefaultAltarCapability?

I think you're under some fundamental misconception over the capability system. Here's what you need:

1. A capability, and a capability is just a class which holds any arbitrary data you need. Since what you want is an "inventory", forge provides an implementation for that, the ItemStackHandler. If you don't require any custom logic on top of just a holder of ItemStacks, you don't even need to extend it, just use the ItemStackHandler capability.

2. A capability provider, which will manage the capabilities for your player. in it you'll handle serialization, and on the getCapability method, you'll check if the requested capability matches your capability, and if it does, return the lazy capability

3. you'll register the capabilities, and attach them on the proper event handler

4. if you want the inventory to be displayed, and interacted with by the player, you'll need the container and a container screen (not a tile entity, those are for blocks).

Posted

The tile entity in this context just serves to open the container that allows the player to have acess to this inventory. I change for the ItemStackHandler and I works. But, when I enter the world the capability resets.

Posted
6 hours ago, LuccaPossamai said:

The tile entity in this context just serves to open the container that allows the player to have acess to this inventory.

yeah, that's not what tile entities are for. Tile entities are for blocks.

what you need to open the container, is an INamedContainerProvider

6 hours ago, LuccaPossamai said:

I change for the ItemStackHandler and I works. But, when I enter the world the capability resets.

then you're not properly serializing your data, make sure you properly overrode the serializeNBT and deserializeNBT methods in your Capability Provider.

and post your new code if you're still with some issues

Posted

I use this tile entity for a block, and this block the player use to open the inventory(like an ender chest). I changed the capability to an ItemStackHandler. But every time I enter in the game the inventory resets.

The class for ItemStackHandler cap: 

Spoiler

public class DefaultAltarCapability extends ItemStackHandler { public DefaultAltarCapability(){ super(9); } }


public class DefaultAltarCapability extends ItemStackHandler {

    public DefaultAltarCapability(){
        super(9);
    }
    
}

 

The Capability.IStorage:

Spoiler

public class IStorageInstance implements Capability.IStorage<DefaultAltarCapability> {

    @Nullable
    @Override
    public INBT writeNBT(Capability<DefaultAltarCapability> capability, DefaultAltarCapability instance, Direction side) {
        ListNBT listnbt = new ListNBT();

        for(int i = 0; i < instance.getSlots(); ++i) {
            ItemStack itemstack = instance.getStackInSlot(i);
            CompoundNBT compoundnbt = new CompoundNBT();
            compoundnbt.putInt("Slot", i);
            itemstack.save(compoundnbt);
            listnbt.add(compoundnbt);

        }
        CompoundNBT nbt = new CompoundNBT();
        nbt.put("Items",listnbt);
        nbt.putInt("Size",listnbt.size());

        return listnbt;
    }

    @Override
    public void readNBT(Capability<DefaultAltarCapability> capability, DefaultAltarCapability instance, Direction side, INBT nbt) {
        if(nbt instanceof  CompoundNBT) {
            System.out.println("É tag");
            CompoundNBT compoundNBT = (CompoundNBT) nbt;
            ListNBT tagList = compoundNBT.getList("Items", Constants.NBT.TAG_COMPOUND);

            for (int i = 0; i < tagList.size(); ++i) {
                instance.insertItem(i, ItemStack.of(tagList.getCompound(i)), false);
            }
        }
    }

}

 

The instance of the capability:

Spoiler

public class CapabilityInstance  {

    @CapabilityInject(DefaultAltarCapability.class)
    public static Capability<DefaultAltarCapability> ALTAR_CAPABILITY = null;

    public static void register(){
        CapabilityManager.INSTANCE.register(DefaultAltarCapability.class, new IStorageInstance(), DefaultAltarCapability::new );
    }


}

 

I'm using this to load the items, a add them to an inventory:

Spoiler

private Inventory loadItems(PlayerEntity player){
        Inventory inventory = new Inventory(9);
        player.getCapability(CapabilityInstance.ALTAR_CAPABILITY).ifPresent(inv ->{
            for(int i = 0; i < inv.getSlots(); i++){
                inventory.setItem(i, inv.getStackInSlot(i));
            }
        });

        return inventory;
    }

 

And using this, to save the items of the container in the cap:

Spoiler

@SubscribeEvent
    public static void saveAltarItems(PlayerContainerEvent.Close event){
        PlayerEntity jogador = event.getPlayer();
        if(event.getContainer() instanceof ModAltarContainer) {
            NonNullList<ItemStack> lista = NonNullList.withSize(9, ItemStack.EMPTY);
            Container cont = event.getContainer();
            jogador.getCapability(CapabilityInstance.ALTAR_CAPABILITY).ifPresent( inv ->{
                for(int i = 0 ; i < inv.getSlots() ; i++){
                    inv.setStackInSlot(i, cont.getItems().get(i));
                    inv.deserializeNBT(inv.serializeNBT());
                }
            });
            //PlayerEvolution.setStats(lista, jogador);
        }
    }

 

 

Posted (edited)
38 minutes ago, LuccaPossamai said:

I use this tile entity for a block, and this block the player use to open the inventory(like an ender chest).

that doesn't mean you need a tile entity, the data is being stored in the player's capability, not the block

 

38 minutes ago, LuccaPossamai said:

The class for ItemStackHandler cap: 



public class DefaultAltarCapability extends ItemStackHandler {

    public DefaultAltarCapability(){
        super(9);
    }
    
}

 

There's no need to extends the ItemStackHandler, just instantiate it

 

38 minutes ago, LuccaPossamai said:

The Capability.IStorage:




public class IStorageInstance implements Capability.IStorage<DefaultAltarCapability> {

    @Nullable
    @Override
    public INBT writeNBT(Capability<DefaultAltarCapability> capability, DefaultAltarCapability instance, Direction side) {
        ListNBT listnbt = new ListNBT();

        for(int i = 0; i < instance.getSlots(); ++i) {
            ItemStack itemstack = instance.getStackInSlot(i);
            CompoundNBT compoundnbt = new CompoundNBT();
            compoundnbt.putInt("Slot", i);
            itemstack.save(compoundnbt);
            listnbt.add(compoundnbt);

        }
        CompoundNBT nbt = new CompoundNBT();
        nbt.put("Items",listnbt);
        nbt.putInt("Size",listnbt.size());

        return listnbt;
    }

    @Override
    public void readNBT(Capability<DefaultAltarCapability> capability, DefaultAltarCapability instance, Direction side, INBT nbt) {
        if(nbt instanceof  CompoundNBT) {
            System.out.println("É tag");
            CompoundNBT compoundNBT = (CompoundNBT) nbt;
            ListNBT tagList = compoundNBT.getList("Items", Constants.NBT.TAG_COMPOUND);

            for (int i = 0; i < tagList.size(); ++i) {
                instance.insertItem(i, ItemStack.of(tagList.getCompound(i)), false);
            }
        }
    }

}

 

You don't need to use IStorage, plus they're being removed in the next versions. just do the serialization in the provider

 

38 minutes ago, LuccaPossamai said:

The instance of the capability:




public class CapabilityInstance  {

    @CapabilityInject(DefaultAltarCapability.class)
    public static Capability<DefaultAltarCapability> ALTAR_CAPABILITY = null;

    public static void register(){
        CapabilityManager.INSTANCE.register(DefaultAltarCapability.class, new IStorageInstance(), DefaultAltarCapability::new );
    }


}

 

and when your CapabilityInstance.register called?

 

38 minutes ago, LuccaPossamai said:

I'm using this to load the items, a add them to an inventory:




private Inventory loadItems(PlayerEntity player){
        Inventory inventory = new Inventory(9);
        player.getCapability(CapabilityInstance.ALTAR_CAPABILITY).ifPresent(inv ->{
            for(int i = 0; i < inv.getSlots(); i++){
                inventory.setItem(i, inv.getStackInSlot(i));
            }
        });

        return inventory;
    }

And using this, to save the items of the container in the cap:




@SubscribeEvent
    public static void saveAltarItems(PlayerContainerEvent.Close event){
        PlayerEntity jogador = event.getPlayer();
        if(event.getContainer() instanceof ModAltarContainer) {
            NonNullList<ItemStack> lista = NonNullList.withSize(9, ItemStack.EMPTY);
            Container cont = event.getContainer();
            jogador.getCapability(CapabilityInstance.ALTAR_CAPABILITY).ifPresent( inv ->{
                for(int i = 0 ; i < inv.getSlots() ; i++){
                    inv.setStackInSlot(i, cont.getItems().get(i));
                    inv.deserializeNBT(inv.serializeNBT());
                }
            });
            //PlayerEvolution.setStats(lista, jogador);
        }
    }

 

What are these for? why are you converting the ItemStackHandler to an Inventory, to use the ItemStackHandler

 

And you didn't show the CapabilityProvider.

You're over complicating this, I've already explained what it is that you need:

On 5/26/2021 at 11:58 PM, kiou.23 said:

1. A capability, and a capability is just a class which holds any arbitrary data you need. Since what you want is an "inventory", forge provides an implementation for that, the ItemStackHandler. If you don't require any custom logic on top of just a holder of ItemStacks, you don't even need to extend it, just use the ItemStackHandler capability.

2. A capability provider, which will manage the capabilities for your player. in it you'll handle serialization, and on the getCapability method, you'll check if the requested capability matches your capability, and if it does, return the lazy capability

3. you'll register the capabilities, and attach them on the proper event handler

4. if you want the inventory to be displayed, and interacted with by the player, you'll need the container and a container screen (not a tile entity, those are for blocks).

your Capability Provider will provide an ItemStackHandler, in this case, handle serialization in the Provider's serialize and deserialize methods

and you don't need a TE, at least not for this. the TE is meant to store additional data for blocks, since the data you're storing isn't kept in a block, but in the player, you don't need a Tile entity. to open the container you just need an INamedContainerProvider, which passes any data that the Container needs, to the container. and you'll get this data from the Capability

Edited by kiou.23
Posted

Ok, I changed some things. But the inventory still resets. I'm calling the registration of the capability in the setup, maybe this is causing the reset.
The attachEvent:

Spoiler

@Mod.EventBusSubscriber
public class AltarCapabilitySetup {

    @SubscribeEvent
    public static void attachEntityCapabilities(AttachCapabilitiesEvent<Entity> event) {
        if(event.getObject() instanceof  PlayerEntity) {
            event.addCapability(new ResourceLocation(ExampleMod.MOD_ID, "altar_inventory"), new CapabilityInstance());
        }
    }
    
}

 

And the Provider/Serializable:

Spoiler

public class CapabilityInstance implements ICapabilityProvider, ICapabilitySerializable {

    @CapabilityInject(ItemStackHandler.class)
    public static Capability<ItemStackHandler> ALTAR_CAPABILITY = null;

    private final ItemStackHandler ALTAR_HANDLER = new ItemStackHandler(9);

    private final LazyOptional<ItemStackHandler> ALTAR_LAZY = LazyOptional.of(()-> ALTAR_HANDLER);

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
        return ALTAR_LAZY.cast();
    }

    @Override
    public INBT serializeNBT() {
        if(ALTAR_CAPABILITY == null){
            return new CompoundNBT();
        } else {
            return ALTAR_CAPABILITY.writeNBT(ALTAR_HANDLER, null);
        }
    }

    @Override
    public void deserializeNBT(INBT nbt) {
        if(ALTAR_CAPABILITY != null) {
            ALTAR_CAPABILITY.readNBT(ALTAR_HANDLER, null, nbt);
        }
    }
    public static void register() {
        CapabilityManager.INSTANCE.register(CapabilityInstance.class, new Capability.IStorage<CapabilityInstance>() {
            @Nullable
            @Override
            public INBT writeNBT(Capability<CapabilityInstance> capability, CapabilityInstance instance, Direction side) {
                return instance.serializeNBT();
            }

            @Override
            public void readNBT(Capability<CapabilityInstance> capability, CapabilityInstance instance, Direction side, INBT nbt) {
                instance.serializeNBT();
            }
        }, CapabilityInstance::new);
    }


}

 

 

Posted (edited)
1 hour ago, LuccaPossamai said:

Ok, I changed some things. But the inventory still resets. I'm calling the registration of the capability in the setup, maybe this is causing the reset.
The attachEvent:

  Reveal hidden contents






@Mod.EventBusSubscriber
public class AltarCapabilitySetup {

    @SubscribeEvent
    public static void attachEntityCapabilities(AttachCapabilitiesEvent<Entity> event) {
        if(event.getObject() instanceof  PlayerEntity) {
            event.addCapability(new ResourceLocation(ExampleMod.MOD_ID, "altar_inventory"), new CapabilityInstance());
        }
    }
    
}

 

And the Provider/Serializable:

  Reveal hidden contents






public class CapabilityInstance implements ICapabilityProvider, ICapabilitySerializable {

    @CapabilityInject(ItemStackHandler.class)
    public static Capability<ItemStackHandler> ALTAR_CAPABILITY = null;

    private final ItemStackHandler ALTAR_HANDLER = new ItemStackHandler(9);

    private final LazyOptional<ItemStackHandler> ALTAR_LAZY = LazyOptional.of(()-> ALTAR_HANDLER);

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
        return ALTAR_LAZY.cast();
    }

    @Override
    public INBT serializeNBT() {
        if(ALTAR_CAPABILITY == null){
            return new CompoundNBT();
        } else {
            return ALTAR_CAPABILITY.writeNBT(ALTAR_HANDLER, null);
        }
    }

    @Override
    public void deserializeNBT(INBT nbt) {
        if(ALTAR_CAPABILITY != null) {
            ALTAR_CAPABILITY.readNBT(ALTAR_HANDLER, null, nbt);
        }
    }
    public static void register() {
        CapabilityManager.INSTANCE.register(CapabilityInstance.class, new Capability.IStorage<CapabilityInstance>() {
            @Nullable
            @Override
            public INBT writeNBT(Capability<CapabilityInstance> capability, CapabilityInstance instance, Direction side) {
                return instance.serializeNBT();
            }

            @Override
            public void readNBT(Capability<CapabilityInstance> capability, CapabilityInstance instance, Direction side, INBT nbt) {
                instance.serializeNBT();
            }
        }, CapabilityInstance::new);
    }


}

 

 

in the provider's serializeNBT you call the IStorage's writeNBT, but in the IStorage's writeNBT you call the provider's serializeNBT. You never actually serialize your data.

 

1. You don't need an IStorage, just do the serialization in the provider itself.

2. your lazy altar isn't actually lazy. google the concept up. don't initialize the the field on instantiation, instead wait until the capability is requested to initialize it, then cache it.

3. no need to implement ICapabilityProvider, only ICapabilitySerializable, also, you should define the generic parameter of the interface.

4. don't put your capability instance on the capability provider class. that's separation of concerns 101

5. on your getCapability, make sure that the capability being requested is the one you're providing!

Hold on, I have a mod with a private repo that uses capabilities. I'll make it public to share it here so you can see some examples

 

EDIT: here's some examples https://github.com/jvcmarcenes/skbackpacks

EDIT2: I had forgot, for serializing ItemStackHandlers you can use of CapabilityItemHandler.ITEM_HANDLER_CAPABILITY write/read method

Edited by kiou.23
Posted

Ok, with an example the things just get so many clear now. Thanks btw. But, I'm confused. How do I register this Capability. I mean, I tried but, with the serialization, there is no IStorage. I looked in your code, and do not find a field that you register the cap. 

Posted
7 hours ago, LuccaPossamai said:

Ok, with an example the things just get so many clear now. Thanks btw. But, I'm confused. How do I register this Capability. I mean, I tried but, with the serialization, there is no IStorage. I looked in your code, and do not find a field that you register the cap. 

since that's just using an ItemStackHandler, I used the ITEM_HANDLER capability that already exists in CapabilityItemHandler

Bur for registration you just create a field, in a class like ModCapabilities, of type Capability<Your Capability class>, and use @CapabilityInject()

and I didn't have to use an attach event because I'm using the capability in a custom Item. but for attaching it's the same thing, just listen to the proper event, and call event.addCapabicall, then give it the cap ID and an instance of the cap provider

Posted
3 minutes ago, LuccaPossamai said:

It worked, thanks. When the player dies, the capability should reset? If yes, how do I do to no reset?

yes, you have to copy all values from the old capability into the new one, do this in the PlayerEvent.Clone

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Version 1.19 - Forge 41.0.63 I want to create a wolf entity that I can ride, so far it seems to be working, but the problem is that when I get on the wolf, I can’t control it. I then discovered that the issue is that the server doesn’t detect that I’m riding the wolf, so I’m struggling with synchronization. However, it seems to not be working properly. As I understand it, the server receives the packet but doesn’t register it correctly. I’m a bit new to Java, and I’ll try to provide all the relevant code and prints *The comments and prints are translated by chatgpt since they were originally in Spanish* Thank you very much in advance No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. MountableWolfEntity package com.vals.valscraft.entity; import com.vals.valscraft.network.MountSyncPacket; import com.vals.valscraft.network.NetworkHandler; import net.minecraft.client.Minecraft; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.animal.Wolf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.Entity; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.network.PacketDistributor; public class MountableWolfEntity extends Wolf { private boolean hasSaddle; private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(MountableWolfEntity.class, EntityDataSerializers.BYTE); public MountableWolfEntity(EntityType<? extends Wolf> type, Level level) { super(type, level); this.hasSaddle = false; } @Override protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(DATA_ID_FLAGS, (byte)0); } public static AttributeSupplier.Builder createAttributes() { return Wolf.createAttributes() .add(Attributes.MAX_HEALTH, 20.0) .add(Attributes.MOVEMENT_SPEED, 0.3); } @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); if (itemstack.getItem() == Items.SADDLE && !this.hasSaddle()) { if (!player.isCreative()) { itemstack.shrink(1); } this.setSaddle(true); return InteractionResult.SUCCESS; } else if (!level.isClientSide && this.hasSaddle()) { player.startRiding(this); MountSyncPacket packet = new MountSyncPacket(true); // 'true' means the player is mounted NetworkHandler.CHANNEL.sendToServer(packet); // Ensure the server handles the packet return InteractionResult.SUCCESS; } return InteractionResult.PASS; } @Override public void travel(Vec3 travelVector) { if (this.isVehicle() && this.getControllingPassenger() instanceof Player) { System.out.println("The wolf has a passenger."); System.out.println("The passenger is a player."); Player player = (Player) this.getControllingPassenger(); // Ensure the player is the controller this.setYRot(player.getYRot()); this.yRotO = this.getYRot(); this.setXRot(player.getXRot() * 0.5F); this.setRot(this.getYRot(), this.getXRot()); this.yBodyRot = this.getYRot(); this.yHeadRot = this.yBodyRot; float forward = player.zza; float strafe = player.xxa; if (forward <= 0.0F) { forward *= 0.25F; } this.flyingSpeed = this.getSpeed() * 0.1F; this.setSpeed((float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 1.5F); this.setDeltaMovement(new Vec3(strafe, travelVector.y, forward).scale(this.getSpeed())); this.calculateEntityAnimation(this, false); } else { // The wolf does not have a passenger or the passenger is not a player System.out.println("No player is mounted, or the passenger is not a player."); super.travel(travelVector); } } public boolean hasSaddle() { return this.hasSaddle; } public void setSaddle(boolean hasSaddle) { this.hasSaddle = hasSaddle; } @Override protected void dropEquipment() { super.dropEquipment(); if (this.hasSaddle()) { this.spawnAtLocation(Items.SADDLE); this.setSaddle(false); } } @SubscribeEvent public static void onServerTick(TickEvent.ServerTickEvent event) { if (event.phase == TickEvent.Phase.START) { MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer(); if (server != null) { for (ServerPlayer player : server.getPlayerList().getPlayers()) { if (player.isPassenger() && player.getVehicle() instanceof MountableWolfEntity) { MountableWolfEntity wolf = (MountableWolfEntity) player.getVehicle(); System.out.println("Tick: " + player.getName().getString() + " is correctly mounted on " + wolf); } } } } } private boolean lastMountedState = false; @Override public void tick() { super.tick(); if (!this.level.isClientSide) { // Only on the server boolean isMounted = this.isVehicle() && this.getControllingPassenger() instanceof Player; // Only print if the state changed if (isMounted != lastMountedState) { if (isMounted) { Player player = (Player) this.getControllingPassenger(); // Verify the passenger is a player System.out.println("Server: Player " + player.getName().getString() + " is now mounted."); } else { System.out.println("Server: The wolf no longer has a passenger."); } lastMountedState = isMounted; } } } @Override public void addPassenger(Entity passenger) { super.addPassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(true)); } } } @Override public void removePassenger(Entity passenger) { super.removePassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is no longer mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(false)); } } } @Override public boolean isControlledByLocalInstance() { Entity entity = this.getControllingPassenger(); return entity instanceof Player; } @Override public void positionRider(Entity passenger) { if (this.hasPassenger(passenger)) { double xOffset = Math.cos(Math.toRadians(this.getYRot() + 90)) * 0.4; double zOffset = Math.sin(Math.toRadians(this.getYRot() + 90)) * 0.4; passenger.setPos(this.getX() + xOffset, this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset(), this.getZ() + zOffset); } } } MountSyncPacket package com.vals.valscraft.network; import com.vals.valscraft.entity.MountableWolfEntity; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class MountSyncPacket { private final boolean isMounted; public MountSyncPacket(boolean isMounted) { this.isMounted = isMounted; } public void encode(FriendlyByteBuf buffer) { buffer.writeBoolean(isMounted); } public static MountSyncPacket decode(FriendlyByteBuf buffer) { return new MountSyncPacket(buffer.readBoolean()); } public void handle(NetworkEvent.Context context) { context.enqueueWork(() -> { ServerPlayer player = context.getSender(); // Get the player from the context if (player != null) { // Verifies if the player has dismounted if (!isMounted) { Entity vehicle = player.getVehicle(); if (vehicle instanceof MountableWolfEntity wolf) { // Logic to remove the player as a passenger wolf.removePassenger(player); System.out.println("Server: Player " + player.getName().getString() + " is no longer mounted."); } } } }); context.setPacketHandled(true); // Marks the packet as handled } } networkHandler package com.vals.valscraft.network; import com.vals.valscraft.valscraft; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class NetworkHandler { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel( new ResourceLocation(valscraft.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); public static void init() { int packetId = 0; // Register the mount synchronization packet CHANNEL.registerMessage( packetId++, MountSyncPacket.class, MountSyncPacket::encode, MountSyncPacket::decode, (msg, context) -> msg.handle(context.get()) // Get the context with context.get() ); } }  
    • Do you use features of inventory profiles next (ipnext) or is there a change without it?
    • Remove rubidium - you are already using embeddium, which is a fork of rubidium
  • Topics

×
×
  • Create New...

Important Information

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