This PR breaks the cyclic dependency between `Inventory` and its holder, which unblocks a lot of new developments.
### Related issues & PRs
- Fixes#5033
- Removes a blocker for #6147 (which in turn means that async tasks will eventually be able to work with tiles)
- Removes a blocker for #2684
## Changes
### API changes
- `Player->getCurrentWindow()` now returns `?InventoryWindow` instead of `?Inventory`
- `Player->setCurrentWindow()` now accepts `?InventoryWindow` instead of `?Inventory`
- `InventoryWindow` introduced, which is created for each player viewing the inventory, provides decorative information like holder info for `InventoryTransactionEvent`, and is destroyed when the window is closed, eliminating cyclic references
- Added:
- `player\InventoryWindow`
- `player\PlayerInventoryWindow` - wraps all permanent inventories of Player with type info for transactions
- `inventory\Hotbar` - replaces all hotbar usages in `PlayerInventory`
- `Human->getHotbar()`
- `Human->getMainHandItem()`, `Human->setMainHandItem()`, `Human->getOffHandItem()`, `Human->setOffHandItem()`
- `block\utils\AnimatedContainerLike` & `block\utils\AnimatedContainerLikeTrait` (for chests, shulkerboxes, etc)
- `block\utils\Container` & `block\utils\ContainerTrait` for blocks containing items (chests, etc)
- `block\utils\MenuAccessor` implemented by all blocks that can open inventory menus
- `block\utils\MenuAccessorTrait` used by blocks with menus but without inventories (anvils, crafting tables etc)
- Removed:
- `inventory\DelegateInventory` (only used for ender chests)
- `inventory\PlayerInventory`,
- `inventory\PlayerOffHandInventory`,
- `inventory\PlayerCraftingInventory`,
- `inventory\PlayerCursorInventory` - these have all been internally replaced by `SimpleInventory` & they will appear as `PlayerInventoryWindow` in transactions (check `getType()` against the `PlayerInventoryWindow::TYPE_*` constants to identify them)
- `block\inventory\AnimatedBlockInventoryTrait`, (blocks now handle this logic directly using `AnimatedContainer` and `AnimatedContainerTrait`)
- `block\inventory\BlockInventoryTrait`,
- `block\inventory\BlockInventory`
- Most `BlockInventory` classes have been transitioned to `InventoryWindow` wrappers
- Tiles now all use `SimpleInventory` internally (no cyclic references) except for `Chest` (which uses `CombinedInventory`, without holder info)
- `InventoryOpenEvent` and `InventoryCloseEvent` now provide `InventoryWindow` instead of `Inventory` (to provide type information)
- `InventoryTransaction` and `SlotChangeAction` now provide `InventoryWindow` instead of `Inventory`
- Renamed `TransactionBuilderInventory` to `SlotChangeActionBuilder`
- `TransactionBuilderInventory->getBuilder()` now accepts `InventoryWindow` instead of `Inventory`
- `DoubleChestInventory` superseded by `CombinedInventory` - this new class allows combining any number of inventories behind a single object; mainly used for double chests but plugins could use it to do lots of fun things
### Impacts to plugins
Plugins can now do the following:
```php
$block = $world->getBlockAt($x, $y, $z);
if($block instanceof MenuAccessor){
$block->openToUnchecked($player);
}
```
As compared to the old way:
```php
$tile = $world->getTileAt($x, $y, $z);
if($tile instanceof Container){
$player->setCurrentWindow($tile->getInventory());
}
```
#### Advantages
- No tile access needed
- Works for menu blocks without inventories as well as container blocks
- Less code
### Behavioural changes
Inventories no longer keep permanent cyclic references to their holders.
## Backwards compatibility
This makes significant BC breaks. However, all changes are able to be adapted to and the same amount of information is present on all APIs and events.
## Follow-up
- Implement #6147
- Support inventory inheritance when copying blocks from one position to another
'enchant' just didn't feel right, being a verb.
All these things pertain to the act of enchanting.
This is now also consistent with CraftingTransaction etc. The ship already sailed on EnchantInventory, which will have to be renamed at a later datte. However, that was already inconsistent with 'enchanting table', so that's the odd one out here.
Perhaps this and EnchantOption should be called EnchantingHelper and EnchantingOption respectively. The terminology used is rather inconsistent, but 'enchantment' definitely isn't the right word here.
these have working inventories, and their crafting menus will 'just work' once the items for the associated recipes have been implemented (maps, netherite).
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.