Skip to content

Conversation

@OhACD
Copy link

@OhACD OhACD commented Oct 22, 2025

This PR adds 'InventoryEvents' into the 'screen-handler-api-v1' module, providing a simple way to handle inventory slot click events, the API introduces 'InventoryEvents.SLOT_CLICK_EVENT', which allows modders to intercept and modify slot interactions (e.g, 'PICKUP', 'SWAP', 'QUICK_MOVE', 'QUICK_CRAFT') with minimal boilerplate, reducing reliance on complex mixins or custom screen handlers.

The plan was for 3 events to be added SLOT_CLICK_EVENT, INVENTORY_OPEN_EVENT and CRAFT_RESULT_EVENT.

Problems Solved:

  • Simplifies inventory event handling, avoiding invasive modifications to 'ScreenHandler' or 'Slot' classes.
  • Reduce mod conflicts by using an event-driven approach.
  • Supports common use cases like item restriction and custom container mechanics.

Test Mod:
Added 'InventoryEventsTest' to the existing test mod, demonstrating Diamond Protection (prevents moving Diamonds in any container)

Changes:

  • Added 'InventoryEvents.java' to 'screen-handler-api-v1'.
  • Added 'InventoryEventsTest.java' to 'testmod'.
  • Updated testmod main class to call 'InventoryEventsTest().onInitialize()'.
  • All classes added have the necessary javadocs for ease of use.

Testing Instructions:

  1. Build and run the mod in a Fabric environment
  2. Try taking out Diamonds from a container
  3. Test multiple actions to take out the Diamond

@OhACD
Copy link
Author

OhACD commented Oct 22, 2025

I just noticed there is a mistake in the docs in the InventoryEvents class where it states that mod authors should manually sync the client state, I've written this before i was correctly syncing everything, It's not required currently and can be missleading

…issues with testing - Everything used to work fine but the mod broke after refactoring into the screen-handler-api-v1 module (the api was built as it's seperate module fabric-inventory-events-v1) a seperate test mod could be provided if needed but i have done ample testing to insure stability and cleanliness
Copy link
Member

@Patbox Patbox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gave some feedback on current implementation.
Also worth noting that this PR:

  • This only handles simple cases of inventory slot click and others. Complex changes naturally will still require mixins.
  • Doesn't really reduce mod conflicts, as proficient devs would know how to handle it.
  • Custom container mechanics and item restrictions shouldn't be implemented purely via click detection, because for example a sorting mod on the server will skip these checks to be faster, which might cause bypasses (wouldn't be the case if you validated it in Slot class, as one should).

*/
ActionResult interact(
ScreenHandler handler,
Slot slot,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be marked as @ Nullable, since you do pass null here.

* @param player The player who clicked the slot
* @param ci Callback info for canceling the method
*/
@Inject(method = "onSlotClick", at = @At("HEAD"), cancellable = true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want for it to hold true that it always runs before actual logic, you would need to move this mixin to network handler, as mods can and do override onSlotClick method

if (result == ActionResult.FAIL) {
ci.cancel();
// Sync client state to prevent desync
handler.syncState();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you should sync it like this. I'm pretty sure vanilla should have system for detecting desyncs natively, if not you should use that instead of syncing entire inventory

@OhACD
Copy link
Author

OhACD commented Oct 22, 2025

I understand, I got told to only start by adding a simple event. I also know that chest protection shouldn't be added like this, this is just a simple proof of concept that makes use of the simple event added. Thank you for the review!

* <p>Canceling with {@code ActionResult.FAIL} stops the click entirely. Returning {@code ActionResult.SUCCESS} allows the action but consumes the event.
*/
@FunctionalInterface
public interface SlotClickCallback {
Copy link
Contributor

@maityyy maityyy Oct 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants