this implementation is working, although incomplete:
- The shulker close sound should not be played until the end of the shulker closing animation, which takes approximately 1 second.
- An open shulker box has a different collision box than a closed one - it should be +0.5 in whichever direction the shulker is facing. (During the animation, the bounding box also dynamically changes size - you can see this in vanilla by shooting an arrow into the top of an open shulkerbox facing UP, and then closing it - the arrow will fall and collide with the lid multiple times.
However, resolving both of these issues requires significant internal changes which are beyond the scope of this PR.
previously, these were forced to extend BaseInventory because of the amount of crap in Inventory's interface.
This meant that these inventories had their own slots storage, which would be _mostly_ unused because these inventories aren't real inventories, but rather just delegates.
This lead to a variety of bugs in the past, such as certain API methods on BaseInventory not working correctly for DoubleChestInventory in particular.
Now, BaseInventory just implements the functional part of the inventory implementation, leaving the storage system up to the implementation.
A SimpleInventory class is provided with a simple SplFixedArray storage backing, which is used by most inventories.
EnderChestInventory and DoubleChestInventory now extend BaseInventory directly, and implement custom methods for dealing with their delegates.
now, EnderChestInventory is just a temporary window, much like anvil/enchanting windows. It provides a gateway to the player's PlayerEnderInventory.
This removes one of the remaining obstacles to disallowing null World in Position constructor.
longer term I want to rip this crap out completely, but right now this provides minor maintainability benefits, while also making it slightly less nasty to deal with other containers which animate their blocks, such as barrels and shulker boxes.