OpenInv

4M Downloads

Shulker Boxes are terrible

Jikoo opened this issue ยท 3 comments

commented

So, I've got a working build, (will commit shortly, bit left to clean up) but I'm not happy.

A quick run through the calls made when opening a shulker box:

  • ContainerShulkerBox initialization calls IInventory#startOpen
  • TileEntityShulkerBox#startOpen both plays the sound (if field h is 0) and plays the block animation no matter what. The client will ignore invalid block actions, block actions with an open/close state too high.
    • Of note: The server does not properly update new clients with the box's state. Logging in while a box is open will always display it closed, though attempting to open it will (silently) correct that.
  • WorldServer#playBlockAction adds a BlockAction to the queue if it is not already present.
    • Queue is checked by iterating over and calling BlockAction.equals on the elements. This means we cannot insert another custom BlockAction that falsely reports being equal, then breaks the check later prior to sending.
  • WorldServer#ao drains the queue
    • Pre-fire, TileEntityShulkerBox#c(1, <h, minimum 1>) is called (WorldServer#a(BlockActionData) -> BlockStateList$BlockData#a(World, BlockPosition, int, int) -> BlockTileEntity#a(IBlockData, World, BlockPosition, int, int)). This resets h to its old level.

The current state:
Prior to opening a TileEntityShulkerBox, we add 1 to h. TileEntityShulkerBox#startOpen also increases h by one, resulting in +2 total. 2 ticks later (1 is not enough for the action to be drained from queue), we set h back by 2. This can lead to the shulker box being frozen "open" until next used if accessed by a silentchest user and normal user in the correct order and in very quick succession. Other than that, it's fully functional.
I'm also not a fan of how I get the plugin for use with the runnable, but that's a whole other issue much more related to code cleanliness and health.

There are a couple ways to deal with the problem:

  1. Wrap EntityPlayer, return true for EntityPlayer#isSpectator. This bypasses the entirety of IInventory#startOpen, and should work for any and all containers to be silenced. It will additionally prevent the long-standing (and equally painful to fix) bug with trapped chests emitting signal for a single tick when silently opened.
  2. Inject our own tile entity for the currently open tile
  3. Use a transformer to entirely replace the relevant NMS tile entity classes with our own which respect players' settings
  4. Cry and live with it
commented

Cry and live with it

/gamemode 3 all the way

commented

/gamemode 3 all the way

Interestingly, BlockShulkerBox#interact appears to ignore spectators. I haven't tried it yet, will edit back in a moment.
Edit: Opens fine, dunno. Maybe there's additional handling elsewhere.

commented

Closing this to keep my assigned issues relevant. In case anyone's curious as to my solution, in the end I opted to temporarily force the player into spectate, removing the need for a decent bit of fiddly bits surrounding silentcontainer. 9db1861