Shulker Boxes are terrible
Jikoo opened this issue ยท 3 comments
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 callsIInventory#startOpen
TileEntityShulkerBox#startOpen
both plays the sound (if fieldh
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 aBlockAction
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 customBlockAction
that falsely reports being equal, then breaks the check later prior to sending.
- Queue is checked by iterating over and calling
- 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 resetsh
to its old level.
- Pre-fire,
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:
- Wrap
EntityPlayer
, return true forEntityPlayer#isSpectator
. This bypasses the entirety ofIInventory#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. - Inject our own tile entity for the currently open tile
- Use a transformer to entirely replace the relevant NMS tile entity classes with our own which respect players' settings
- Cry and live with it
/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.
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