Sponge: InteractItemEvent and InteractBlockEvent behave incorrectly

Created on 22 Jul 2018  ·  31Comments  ·  Source: SpongePowered/Sponge

I am currently running

  • SpongeVanilla version: spongevanilla-1.12.2-7.1.0-BETA-93
  • Java version: OpenJDK Version "1.8.0_171"
  • Operating System: Linux Mint 18.3 Sylvia (Kernel: x86_64 Linux 4.13.0-45-generic)
  • Plugins/Mods: Empty (Only one my experimental plugin)

Issue Description

At the last build for version 1.12.2, the following bugs are observed:
1. InteractBlockEvent is not called when the right mouse button is clicked (this is a SECONDARY event for both hands).
2. InteractBlockEvent for the left hand (PRIMARY event) does not contain data about the used item when the player clicked into the air. EventContext is empty.

My experiment conditions:

  • Main hand: Stick
  • Off hand: Empty

Listener code:

@Listener
public final void onInteractBlock(InteractBlockEvent event) {
    Objects.requireNonNull(event, "event");

    System.out.println(event.getClass().getName());
    System.out.println(event);
}

Console output:

Left button to air

org.spongepowered.api.event.InteractBlockEvent$Primary$MainHand$Impl
MainHand{cancelled=false, cause=Cause[Context=Context[], Stack={EntityPlayerMP['Lignium'/0, l='world', x=-0,53, y=64,00, z=1,22]}], context=Context[], handType=MAIN_HAND, interactionPoint=Optional.empty, source=EntityPlayerMP['Lignium'/0, l='world', x=-0,53, y=64,00, z=1,22], targetBlock=SpongeBlockSnapshot{worldUniqueId=00000000-0000-0000-0000-000000000000, position=(0, 0, 0), blockState=minecraft:air, extendedState=minecraft:air}, targetSide=NONE}

Right button to air

<empty>

Left Button to block

org.spongepowered.api.event.InteractBlockEvent$Primary$MainHand$Impl
MainHand{cancelled=false, cause=Cause[Context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=-0,53, y=64,00, z=1,65], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=-0,53, y=64,00, z=1,65]], Stack={EntityPlayerMP['Lignium'/0, l='world', x=-0,53, y=64,00, z=1,65], com.google.common.util.concurrent.ListenableFutureTask@6c85ea3e}], context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=-0,53, y=64,00, z=1,65], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=-0,53, y=64,00, z=1,65]], handType=MAIN_HAND, interactionPoint=Optional[(-2.370593761577998, 64.0, 1.7115556037860598)], source=EntityPlayerMP['Lignium'/0, l='world', x=-0,53, y=64,00, z=1,65], targetBlock=SpongeBlockSnapshot{worldUniqueId=8a2303f1-f006-4e0d-a866-8ffddde81fd6, position=(-3, 63, 1), blockState=minecraft:stone[variant=stone], extendedState=minecraft:stone[variant=stone]}, targetSide=UP}

Right button to block

org.spongepowered.api.event.InteractBlockEvent$Secondary$MainHand$Impl
MainHand{cancelled=false, cause=Cause[Context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=-0,54, y=64,00, z=0,58], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=-0,54, y=64,00, z=0,58], "sponge:used_item"=SpongeItemStackSnapshot{itemType=minecraft:stick, quantity=1}], Stack={EntityPlayerMP['Lignium'/0, l='world', x=-0,54, y=64,00, z=0,58], com.google.common.util.concurrent.ListenableFutureTask@e404e4c}], context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=-0,54, y=64,00, z=0,58], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=-0,54, y=64,00, z=0,58], "sponge:used_item"=SpongeItemStackSnapshot{itemType=minecraft:stick, quantity=1}], handType=MAIN_HAND, interactionPoint=Optional[(-2.336925506591797, 64.0, 0.6462124586105347)], originalUseBlockResult=UNDEFINED, originalUseItemResult=UNDEFINED, source=EntityPlayerMP['Lignium'/0, l='world', x=-0,54, y=64,00, z=0,58], targetBlock=SpongeBlockSnapshot{worldUniqueId=8a2303f1-f006-4e0d-a866-8ffddde81fd6, position=(-3, 63, 0), blockState=minecraft:stone[variant=stone], extendedState=minecraft:stone[variant=stone]}, targetSide=UP, useBlockResult=UNDEFINED, useItemResult=UNDEFINED}

org.spongepowered.api.event.InteractBlockEvent$Secondary$OffHand$Impl
OffHand{cancelled=false, cause=Cause[Context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=-0,54, y=64,00, z=0,58], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=-0,54, y=64,00, z=0,58], "sponge:used_item"=SpongeItemStackSnapshot{itemType=minecraft:air, quantity=0}], Stack={EntityPlayerMP['Lignium'/0, l='world', x=-0,54, y=64,00, z=0,58], com.google.common.util.concurrent.ListenableFutureTask@2978b321}], context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=-0,54, y=64,00, z=0,58], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=-0,54, y=64,00, z=0,58], "sponge:used_item"=SpongeItemStackSnapshot{itemType=minecraft:air, quantity=0}], handType=OFF_HAND, interactionPoint=Optional[(-2.336925506591797, 64.0, 0.6462124586105347)], originalUseBlockResult=UNDEFINED, originalUseItemResult=UNDEFINED, source=EntityPlayerMP['Lignium'/0, l='world', x=-0,54, y=64,00, z=0,58], targetBlock=SpongeBlockSnapshot{worldUniqueId=8a2303f1-f006-4e0d-a866-8ffddde81fd6, position=(-3, 63, 0), blockState=minecraft:stone[variant=stone], extendedState=minecraft:stone[variant=stone]}, targetSide=UP, useBlockResult=UNDEFINED, useItemResult=UNDEFINED}

My conclusion:

Left button to air: Missing context.
Right button to air: Does not fired. Perhaps also there is no context.
Left button to block: Missing data about used item.
Right button to block: Fired SECONDARY event with full data. However, also fired SECONDARY event of the off hand.

event bug 1.12

All 31 comments

Updated report...

@Lignium Have you tested SpongeForge?

@bloodmc No, I tested only SpongeVanilla.

Test this with SF, if you can.

Right button to block: Fired SECONDARY event with full data. However, also fired SECONDARY event of the off hand.

This will happen no matter the platform as we have no idea what you're right clicking with as Vanilla doesn't even know and just sends the packet for both of them.

@bloodmc ^

Yes, the right click on block is not a bug and is working as intended.

Similarly with the InteractItemEvent... :(

@Lignium I suspect there's some confusing at the result you expect.

Are you complaining about lack of context of what the player is holding?
Who is doing the clicking?

Essentially, for the 4 above, can you outline what you see (on each platform), what you expect, and why you have made the issue?

Originally (before your edits) it seemed you believed they wern't being fired at all.

A test plugin would help.

There are inconsistencies with the InteractBlockEvent and InteractItemEvent between SpongeForge and SpongeVanilla as shown in the following image

SpongeEvents

Most notable is the missing events when Holding minecraft:stick, Looking at nothing as this would break something like the GriefPrevention claim inspection wand or the VirtualChest plugin as I have observed on my server since updating SpongeVanilla.

Something has changed, but not all. The event is still inadequately behaving.
The second experiment, the conditions are the same.

Console output:

Left button to air

org.spongepowered.api.event.InteractBlockEvent$Primary$MainHand$Impl
MainHand{cancelled=false, cause=Cause[Context=Context[], Stack={EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42]}], context=Context[], handType=MAIN_HAND, interactionPoint=Optional.empty, source=EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42], targetBlock=SpongeBlockSnapshot{worldUniqueId=00000000-0000-0000-0000-000000000000, position=(0, 0, 0), blockState=minecraft:air, extendedState=minecraft:air}, targetSide=NONE}

Right button to air

org.spongepowered.api.event.InteractBlockEvent$Secondary$MainHand$Impl
MainHand{cancelled=false, cause=Cause[Context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42], "sponge:used_item"=SpongeItemStackSnapshot{itemType=minecraft:stick, quantity=1}], Stack={EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42], com.google.common.util.concurrent.ListenableFutureTask@35996b2b}], context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42], "sponge:used_item"=SpongeItemStackSnapshot{itemType=minecraft:stick, quantity=1}], handType=MAIN_HAND, interactionPoint=Optional[(1.0, 64.0, -1.0)], originalUseBlockResult=UNDEFINED, originalUseItemResult=UNDEFINED, source=EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42], targetBlock=SpongeBlockSnapshot{worldUniqueId=8a2303f1-f006-4e0d-a866-8ffddde81fd6, position=(1, 64, -1), blockState=minecraft:air, extendedState=minecraft:air}, targetSide=NONE, useBlockResult=UNDEFINED, useItemResult=UNDEFINED}

Left Button to block

org.spongepowered.api.event.InteractBlockEvent$Primary$MainHand$Impl
MainHand{cancelled=false, cause=Cause[Context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42]], Stack={EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42], com.google.common.util.concurrent.ListenableFutureTask@1ee63f4d}], context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42]], handType=MAIN_HAND, interactionPoint=Optional[(3.4922587104297804, 64.0, -0.4626675815108363)], source=EntityPlayerMP['Lignium'/0, l='world', x=1,39, y=64,00, z=-0,42], targetBlock=SpongeBlockSnapshot{worldUniqueId=8a2303f1-f006-4e0d-a866-8ffddde81fd6, position=(3, 63, -1), blockState=minecraft:stone[variant=stone], extendedState=minecraft:stone[variant=stone]}, targetSide=UP}

Right button to block

org.spongepowered.api.event.InteractBlockEvent$Secondary$MainHand$Impl
MainHand{cancelled=false, cause=Cause[Context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=1,52, y=64,00, z=-0,40], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=1,52, y=64,00, z=-0,40], "sponge:used_item"=SpongeItemStackSnapshot{itemType=minecraft:stick, quantity=1}], Stack={EntityPlayerMP['Lignium'/0, l='world', x=1,52, y=64,00, z=-0,40], com.google.common.util.concurrent.ListenableFutureTask@7634d42d}], context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=1,52, y=64,00, z=-0,40], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=1,52, y=64,00, z=-0,40], "sponge:used_item"=SpongeItemStackSnapshot{itemType=minecraft:stick, quantity=1}], handType=MAIN_HAND, interactionPoint=Optional[(3.5344996452331543, 64.0, -0.49084538221359253)], originalUseBlockResult=UNDEFINED, originalUseItemResult=UNDEFINED, source=EntityPlayerMP['Lignium'/0, l='world', x=1,52, y=64,00, z=-0,40], targetBlock=SpongeBlockSnapshot{worldUniqueId=8a2303f1-f006-4e0d-a866-8ffddde81fd6, position=(3, 63, -1), blockState=minecraft:stone[variant=stone], extendedState=minecraft:stone[variant=stone]}, targetSide=UP, useBlockResult=UNDEFINED, useItemResult=UNDEFINED}

org.spongepowered.api.event.InteractBlockEvent$Secondary$OffHand$Impl
OffHand{cancelled=false, cause=Cause[Context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=1,52, y=64,00, z=-0,40], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=1,52, y=64,00, z=-0,40], "sponge:used_item"=SpongeItemStackSnapshot{itemType=minecraft:air, quantity=0}], Stack={EntityPlayerMP['Lignium'/0, l='world', x=1,52, y=64,00, z=-0,40], com.google.common.util.concurrent.ListenableFutureTask@aca424d}], context=Context["sponge:owner"=EntityPlayerMP['Lignium'/0, l='world', x=1,52, y=64,00, z=-0,40], "sponge:notifier"=EntityPlayerMP['Lignium'/0, l='world', x=1,52, y=64,00, z=-0,40], "sponge:used_item"=SpongeItemStackSnapshot{itemType=minecraft:air, quantity=0}], handType=OFF_HAND, interactionPoint=Optional[(3.5344996452331543, 64.0, -0.49084538221359253)], originalUseBlockResult=UNDEFINED, originalUseItemResult=UNDEFINED, source=EntityPlayerMP['Lignium'/0, l='world', x=1,52, y=64,00, z=-0,40], targetBlock=SpongeBlockSnapshot{worldUniqueId=8a2303f1-f006-4e0d-a866-8ffddde81fd6, position=(3, 63, -1), blockState=minecraft:stone[variant=stone], extendedState=minecraft:stone[variant=stone]}, targetSide=UP, useBlockResult=UNDEFINED, useItemResult=UNDEFINED}

Left button to air: Missing context, BlockSnapshot is NONE (it should be).
Right button to air: Working, but BlockSnapshot is not NONE (it should not be).
Left button to block: Missing data about used item (nothing changed).
Right button to block: Working.

I can confirm that its not acting correctly, one can not throw items like enderpearls, eggs, and snowballs when they are looking at a block.

Full analysis of interaction events at last build (1.12.2-7.1.0-BETA-110):
1) Red - Missing data.
2) Blue - "UsedItem" context, probably should be present (in InteractItemEvent.Secondary.MainHand is present).
3) Orange - Bad data. Should be NONE and Optional.empty.

interact events

@ImMorpheus, thanks for the work and time spent but unfortunately there are still shortcomings...

The conditions of the experiment are the same. In the main hand a stick.

  • Red - Missing the data.
  • Orange - An event wasn't fired. (I understand that this has already been discussed)
  • Violet - Missing the data. I think InteractBlockEvent must containing block hit in the context.
  • Green - Instead of the intersection point with a block - the coordinates of this block.
  • Blue - Invalid the data. InteractItemEvent always contained _none_ and _empty_ for block hit and interaction point data respectively.

What about the "orange" problem? Will it ever be fixed in the future or will it remain as a feature?

interaction

@Lignium

Red: The PR was about right-click events. I will look into left-click.

Green: Can you clarify ?

Orange: that's not an issue. there's no point in firing multiple Interact events for the same packet except breaking a whole lot of things.

@ImMorpheus

Green: Well, look carefully at the values of this data. There should not be integers. There must be coordinates of an intersection point with a block surface, logically.

I am not sure what was already discussed about InteractItemEvent, but it is not fired at all when I am doing a right click on a block.
Tested on "spongeforge-1.12.2-2768-7.1.6-RC3561.jar" and "spongeforge-1.12.2-2768-7.1.5.jar", works fine with "spongeforge-1.12.2-2768-7.1.5-RC3515.jar"...

@GreWeMa that is intentional when the hand is empty https://github.com/SpongePowered/SpongeCommon/pull/2125#issuecomment-453771117

@phit I tested it with an item in hand

@GreWeMa Open an issue with the steps to reproduce your issue. (minimal code snippet + instructions).

@Lignium Keeping in mind that orange is working as intended, ListenableFutureTask can be ignored, is there anything else which is not working ?

@ImMorpheus

SF spongeforge-1.12.2-2768-7.1.5-RC3515.jar:
Works as expected, InteractItemEvent is fired whenever I'm doing a right click.

SF spongeforge-1.12.2-2768-7.1.6-RC3561.jar/spongeforge-1.12.2-2768-7.1.5.jar:
InteractItemEvent is fired when I'm doing a right click at air, it is also fired when I'm doing a right click at a block with a "non-placeable" item in hand (stick, arrow, feather etc.), but when I'm doing a right click at a block with a "placeable" item in hand (dirt, stone, skull etc.) - event is not fired.

Is it a bug, or is it just how the new API works? If its second, then it's not quite comfortable and now I need to use both "InteractItemEvent" and "InteractBlockEvent" in order to do things that I was able to do using only "InteractItemEvent"...

@ImMorpheus If everything else is fixed, then everything is fine.

@ImMorpheus Has the "green" and "blue" problems been fixed? I cannot find the code that reflects this in your pull request.

So I tested it again... This time I made two tests, with an item stack in my hand and without.

  • Red - Missing data about the player. Owner and notifier cannot be used as a source of this data.
  • Violet - Invalid data.
  • Blue - Last time I wrote about it, but you did not fix it. Please look carefully at these values ​​and see what is wrong here.
  • Orange - How did it turn out?!

With an item stack (stick):

interact_test_1

Empty hand:

interact_test_2

@bloodmc As I understand you already fixed the red problem? https://github.com/SpongePowered/SpongeCommon/commit/7de73b25245c0f7d8a5e24091095ab758874ebc0

Only now I noticed that InteractBlockEvent.Primary.MainHand has block_hit context that is not equal to BlockSnapshot.NONE when a player left clicks to air.

Already 8 months have passed, but bugs with these two events are still not fixed. I can’t make a properly working wand to highlight regions (similar to WorldEdit), but with 2 additional functions when air clicks. I am already losing hope that this issue will ever be closed.

From BLOCK_HIT javadoc:

Used when an {@link Entity} interacts with a block.

https://github.com/SpongePowered/SpongeAPI/blob/b2736425ce386018267484f3fed65c9950e5d984/src/main/java/org/spongepowered/api/event/cause/EventContextKeys.java#L78

InteractItemEvent is NOT fired because you've interacted with a block.
If anything, the bug is that EventContextKeys.BLOCK_HIT shouldn't be present

InteractItemEvent is NOT fired because you've interacted with a block.

Yes indeed, everything is correct.

If anything, the bug is that EventContextKeys.BLOCK_HIT shouldn't be present

Do you mean that you need to remove EventContextKeys.BLOCK_HIT from events that involve click to air? If yes, then I agree, it will be logical.

The fact is that _left click to air_ and _right click to block_ lead to firing of parasitic events, such as InteractBlockEvent and InteractItemEvent, for them accordingly. If you cannot remove them for any reason, I will have to distinguish them from useful events. For example, look at the image on the events InteractItemEvent when player right clicks to air and to block. At the moment, they are absolutely indistinguishable from each other, as a result it is impossible to know where a player hit, to block or to air.

Here is my code, which, if these events work correctly, should properly filter out parasitic events:

@Listener
public void onInteractItem(InteractItemEvent event) {
    Objects.requireNonNull(event, "event");

    EventContext context = event.getContext();
    Optional<BlockSnapshot> blockHitBox = context.get(EventContextKeys.BLOCK_HIT);

    // When right click to block the block hit will be BlockSnapshot.NONE.
    // The filter will not be work.

    if (blockHitBox.isPresent() && !blockHitBox.get().equals(BlockSnapshot.NONE)) {
        return;
    }

    // Check item and etc...

    Optional<ItemStackSnapshot> usedItemBox = context.get(EventContextKeys.USED_ITEM);
}

@Listener
public void onInteractBlock(InteractBlockEvent event) {
    Objects.requireNonNull(event, "event");

    EventContext context = event.getContext();
    Optional<BlockSnapshot> blockHitBox = context.get(EventContextKeys.BLOCK_HIT);

    // When left click to air the block hit will be a block snapshot of air.
    // The filter also will not be work.
    // I can certainly check this snapshot for air, but this is a very ugly way.

    if (blockHitBox.isPresent() && blockHitBox.get().equals(BlockSnapshot.NONE)) {
        return;
    }

    // Check item and etc...

    Optional<ItemStackSnapshot> usedItemBox = context.get(EventContextKeys.USED_ITEM);
}

Do you mean that you need to remove EventContextKeys.BLOCK_HIT from events that involve click to air? If yes, then I agree, it will be logical.

It means I'm thinking of removing EventContextKeys.BLOCK_HIT from all InteractItemEvents

For example, look at the image on the events InteractItemEvent when player right clicks to air and to block. At the moment, they are absolutely indistinguishable from each other, as a result it is impossible to know where a player hit, to block or to air.

That's correct. You're using the wrong event.
InteractItemEvent is linked to CPacketPlayerTryUseItem, it doesn't hold the information of whether you've hit a block or not, thus they are indistinguishable.

@ImMorpheus What about interaction points of InteractItemEvents? It is also not presented in the packet? If so, how can explain the existence of an appropriate API access method.

What about interaction points of InteractItemEvents? It is also not presented in the packet? If so, how can explain the existence of an appropriate API access method.

It's not, but we raytrace to provide the interaction point.
I will fix this.

@ImMorpheus So you propose to artificially calculate the point of intersection with a block? To do this, you need to know the standard distance from the game at which player can "reach" blocks, in order to determine when the interaction point should be specified, and when not. However, in this case, it is possible at the same time to provide information about the block, why not?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

randombyte-developer picture randombyte-developer  ·  5Comments

Xemiru picture Xemiru  ·  3Comments

ImMorpheus picture ImMorpheus  ·  4Comments

SjsolisZXA picture SjsolisZXA  ·  3Comments

XakepSDK picture XakepSDK  ·  5Comments