Jump to content

Capability Issues


sarkozi

Recommended Posts

I'm new to Forge and am trying to figure out how to block player access to a particular inventory slot. I know that with inventory stuff I'm supposed to use capabilities as much as I possibly can, but I'm still struggling to wrap my head around it. The way I approached this at first was to create a custom Slot class and use player.container.inventorySlots.set() to insert it into my desired spot. From there I overrode the slot's canTakeStack() method to make it always return false. It sort of works but exhibits a lot of the syncing issues that make me think I should've implemented it using handlers and capabilities. I'm trying to wrap my head around how I would do that properly but I think I need someone to point me in the right direction. I think if I can override PlayerContainer.slotClick() I'd be able to make it work without capabilities but I can't figure out how to do that either.

Link to comment
Share on other sites

16 hours ago, diesieben07 said:

Assuming you are talking about the vanilla inventory here... You will need to indeed override the Slot instance for that particular slot. IItemHandler is not really of use here (neither are capabilities), because this is vanilla code - which knows of neither of those things. So really you are on the right track, you just need to make sure to do it on both client and server.

Show what you have attempted so far.

Thank you!!! I think I'm confused about how to do it on both sides then. Here's what I've got that's relevant:

MyFirstMod.java (init code):

    @SubscribeEvent
    public void onPlayerLogin(final PlayerEvent.PlayerLoggedInEvent event) {
        /*
            CONTAINER INDEX ORDER:
                0: CRAFTING RESULTS SLOT
                1-4: CRAFTING MATRIX
                5-8: ARMOR SLOTS
        */
        PlayerEntity player = event.getPlayer();
        List<Slot> slots = player.container.inventorySlots;

        slots.set(5, new LockableSlot(player.inventory, 39, 8, 8 * 18));
    }

LockableSlot.java:

public class LockableSlot extends Slot {
    public LockableSlot(IInventory inventoryIn, int index, int xPosition, int yPosition) {
        super(inventoryIn, index, xPosition, yPosition);
    }

    @Override
    public boolean canTakeStack(PlayerEntity playerIn) {
        return false;
    }
}

I've messed around with a ton of other functions but canTakeStack is the only one that I can get to actually do anything. If you could help me fix the syncing it would be incredible thank you!!! Idk if I have to block PlayerContainer.slotClick() somehow?

 

EDIT: I should clarify that even though the class is called LockableSlot, I'm just trying to make something that's permanently locked right now, and am planning on implementing that functionality once I've got that sorted out

EDIT #2: also, yes I am using the vanilla inventory, not sure which non-vanilla inventories you're referring to but I assume you mean from another mod

Edited by sarkozi
Link to comment
Share on other sites

7 hours ago, diesieben07 said:

You should probably write a Slot class that takes in the original Slot and delegates all method calls to it instead of making an entirely new slot.

 

Your issue here is that you are using PlayerLoggedInEvent, which fires on the server only. Even if you needed something on the server only, this would not be enough, because the player entity may be re-created (if you change dimension or respawn). So you either need to use PlayerLoggedInEvent, PlayerRespawnEvent and  PlayerChangedDimensionEvent for the server plus ClientPlayerNetworkEvent.LoggedInEvent and ClientPlayerNetworkEvent.RespawnEvent for the client or you could just use EntityJoinWorldEvent and check for players, as this fires on server and client and fires every time the player joins the world. 

I tried using instanceof to check EntityJoinWorldEvent and casting it to a PlayerEntity, and it works! Can't say I entirely understand how the networking works, but thank you so much for your help! One more question: how would I have known that this particular event is common rather than client- or server-side? Should I know based on the directory structure in the API?

Link to comment
Share on other sites

Sorry to revive a dead thread but I've been playing around with this over the last few days and am having trouble getting it to work the way I hoped it would. When I tried to alter my code so I can toggle the slot's availability, I realized that something is going seriously wrong. None of the new slot's methods are being called on click for some reason, even though hovering and server ticks cause some of them to be called (namely getStack(), isEnabled(), and getHasStack()). My hunch is that in the following code:

    @SubscribeEvent
    public void onEntityJoinWorld(final EntityJoinWorldEvent event) {
        if (event.getEntity() instanceof PlayerEntity) {
            /*
            CONTAINER INDEX ORDER:
                0: CRAFTING RESULTS SLOT
                1-4: CRAFTING MATRIX
                5-8: ARMOR SLOTS
            */
            final int HELMET_INDEX = 5;
            PlayerEntity player = (PlayerEntity) event.getEntity();
            List<Slot> slots = player.container.inventorySlots;
            Slot vanillaHelmetSlot = slots.get(HELMET_INDEX);
            slots.set(HELMET_INDEX, new LockableSlot(player.inventory,
                                                     vanillaHelmetSlot.getSlotIndex(),
                                                     vanillaHelmetSlot.xPos+5, vanillaHelmetSlot.yPos));
        }
    }

my instantiation of a new LockableSlot is basically causing two separate instances, one on the client side and one on the server side. Does that make sense? And if so, how do I fix it? I was considering using a public field like in Forge's Items class, but it would need to be static and final, and it can't be static because I need to feed it an IInventory for its constructor. Hopefully this makes sense, I'm pretty confused about what's going wrong.

Edited by sarkozi
Link to comment
Share on other sites

Okay, so how do I approach making it work? Because as it stands, if I leave the entire class blank:

public class LockableSlot extends Slot {
    public LockableSlot(IInventory inventoryIn, int index, int xPosition, int yPosition) {
        super(inventoryIn, index, xPosition, yPosition);
    }
}

I get a totally unusable slot, when presumably I should be getting a normal, functioning one until I override LockableSlot.canTakeStack(). One idea I had is that maybe the player's inventory is not registering my slot change since I only changed it in my container? I think it's a client-side issue because I didn't run into this back when I was using PlayerLoggedInEvent

Edited by sarkozi
Link to comment
Share on other sites

On 12/26/2020 at 4:38 AM, diesieben07 said:

You should probably write a Slot class that takes in the original Slot and delegates all method calls to it instead of making an entirely new slot.

Trying to figure out what you mean by this -- in order to make this work, I have to replace the existing slot with something new, right? And in order to do that, the new thing has to extend Slot because it needs to be present in the PlayerContainer's inventoryslots array. So I'm not totally clear on how to "wrap" a new class around Slot without just extending and replacing it. Sorry if I'm missing something super obvious.

 

I haven't really looked into debugging Forge yet, I really ought to figure that out. I'll get a git repo up though! Thank you so much for all your help by the way, I really appreciate it.

 

EDIT: here's a repo https://github.com/gsarkozi/headlock

Edited by sarkozi
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.