Aah okay, I did see something about the frames but had no idea how they worked. Thank you for providing an example. I am not sure when I should be using the frames and when I should not. Is it okay to just always assume I should use them so I can avoid the try/finally?
Also, regarding the PluginContainer
automatically being added. I’m not sure if that is true in my case. Consider a InteractInventoryEvent.Open
event. During this event, I want to stop the player from opening a ShulkerBox
and instead create my own custom inventory and show this to the player. However, this causes the InteractInventoryEvent.Open
event to fire again, which causes the custom inventory to be opened again, which causes… you get it.
Here is some sample code to replicate what I’m seeing:
@Listener
public void onOpenShulkerBox(InteractInventoryEvent.Open event,
@First Player player,
@Getter("getCause") Cause cause,
@Getter("getContext") EventContext context) {
logger.info("Cause: {}", cause.toString());
// Only on blocks
Optional<BlockSnapshot> block = context.get(EventContextKeys.BLOCK_HIT);
if (!block.isPresent()) return;
// Only ShulkerBoxes
Optional<TileEntity> tileEntity = block.get().getLocation().get().getTileEntity();
if (tileEntity.map(te -> te.getType() != TileEntityTypes.SHULKER_BOX).orElse(false)) return;
Inventory custom = Inventory.builder()
.of(InventoryArchetypes.CHEST)
.build(plugin);
custom.query(GridInventory.class)
.query(SlotPos.of(1, 1))
.offer(ItemStack.builder().fromBlockSnapshot(block.get()).build());
player.openInventory(custom);
}
This results in a StackOverflowError
as explained above. I log the cause the first thing I do so we can have a look at it. All iterations before the overflow all log the same cause, which does not contain my plugin, see here:
Cause[
Context=Context [
"sponge:block_hit" =SpongeBlockSnapshot {
worldUniqueId=31e28686-0991-4e87-96ba-aff2920041a2,
position=(-21,
65,
-24 ),
blockState=minecraft:yellow_shulker_box [
facing=up
],
extendedState=minecraft:yellow_shulker_box [
facing=up
]
},
"sponge:used_item" =SpongeItemStackSnapshot {
itemType=ItemAir {
Name=null
},
quantity=0
}
],
Stack= {
EntityPlayerMP [
'VapidLinus' /103,
l='temp_0',
x=-21.13,
y=65.00,
z=-26.69
]
}
]
Changing the code to manually push my plugin cause and aborting if the cause contains my plugin seems to fix the problem:
@Listener
public void onOpenShulkerBox(InteractInventoryEvent.Open event,
@First Player player,
@Getter("getCause") Cause cause,
@Getter("getContext") EventContext context) {
logger.info("Cause: {}", cause.toString());
if (cause.contains(plugin)) {
logger.info("Ha, no overflow! :)");
return;
}
// Only on blocks
Optional<BlockSnapshot> block = context.get(EventContextKeys.BLOCK_HIT);
if (!block.isPresent()) return;
// Only ShulkerBoxes
Optional<TileEntity> tileEntity = block.get().getLocation().get().getTileEntity();
if (tileEntity.map(te -> te.getType() != TileEntityTypes.SHULKER_BOX).orElse(false)) return;
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
frame.pushCause(plugin);
Inventory custom = Inventory.builder()
.of(InventoryArchetypes.CHEST)
.build(plugin);
custom.query(GridInventory.class)
.query(SlotPos.of(1, 1))
.offer(ItemStack.builder().fromBlockSnapshot(block.get()).build());
player.openInventory(custom);
}
}
Now my code only gets executed once because I don’t run the rest of the code if my plugin is in the cause:
[22:22:09 INFO] [ship]: Cause: Cause[Context=Context[“sponge:block_hit”=SpongeBlockSnapshot{worldUniqueId=0d60f7d6-91e0-444a-9118-df7bf3eb1fcf, position=(-11, 65, -30), blockState=minecraft:yellow_shulker_box[facing=up], extendedState=minecraft:yellow_shulker_box[facing=up]}, “sponge:used_item”=SpongeItemStackSnapshot{itemType=ItemAir{Name=null}, quantity=0}], Stack={EntityPlayerMP[‘VapidLinus’/103, l=‘temp_0’, x=-12.27, y=65.00, z=-32.21]}]
[22:22:09 INFO] [ship]: Cause: Cause[Context=Context[“sponge:block_hit”=SpongeBlockSnapshot{worldUniqueId=0d60f7d6-91e0-444a-9118-df7bf3eb1fcf, position=(-11, 65, -30), blockState=minecraft:yellow_shulker_box[facing=up], extendedState=minecraft:yellow_shulker_box[facing=up]}, “sponge:used_item”=SpongeItemStackSnapshot{itemType=ItemAir{Name=null}, quantity=0}], Stack={se.narkling.mc.ship.ShipPlugin@20a65f45, Plugin{id=ship, name=Ship, version=1.0, description=fancy things, authors=[Linus ‘Vapid’ Närkling], source=mods\ship.jar}, EntityPlayerMP[‘VapidLinus’/103, l=‘temp_0’, x=-12.27, y=65.00, z=-32.21]}]
[22:22:09 INFO] [ship]: Ha, no overflow!
There probably is a better way to do it though and I’d appreciate any advice or suggestions.