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
looks like this was missed in #6639
I checked all other uses of HorizontalFacingTrait and FacesOppositePlacingPlayerTrait and this seems to be the only one.
For blocks, we now use 'block-item state' and 'block-only state', which should be much clearer for people implementing custom stuff.
'block-item state', as the name suggests, sticks to the item when the block is acquired as an item.
'block-only state' applies only to the block and is discarded when the block is acquired as an item.
'type data' for items was also renamed, since 'type' is too ambiguous to be anything but super confusing.
This reverts commit f64dc01bd1.
I forgot that the ItemBlock constructor implicitly strips off any states
of the origin block, which is something that we unfortunately can't do
any other way right now, since the blocks don't remember their default
states.
This commit completely revamps the way that blocks are represented in memory at runtime.
Instead of being represented by legacy Mojang block IDs and metadata, which are dated, limited and unchangeable, we now use custom PM block IDs, which are generated from VanillaBlocks.
This means we have full control of how they are assigned, which opens the doors to finally addressing inconsistencies like glazed terracotta, stripped logs handling, etc.
To represent state, BlockDataReader and BlockDataWriter have been introduced, and are used by blocks with state information to pack said information into a binary form that can be stored on a chunk at runtime.
Conceptually it's pretty similar to legacy metadata, but the actual format shares no resemblance whatsoever to legacy metadata, and is fully controlled by PM.
This means that the 'state data' may change in serialization format at any time, so it should **NOT** be stored on disk or in a config.
In the future, this will be improved using more auto-generated code and attributes, instead of hand-baked decodeState() and encodeState(). For now, this opens the gateway to a significant expansion of features.
It's not ideal, but it's a big step forwards.