42 private readonly
int $size;
48 private array $backingInventories = [];
53 private array $slotToInventoryMap = [];
58 private array $inventoryToOffsetMap = [];
61 private bool $modifyingBackingInventory =
false;
67 array $backingInventories
69 parent::__construct();
70 foreach($backingInventories as $backingInventory){
71 $this->backingInventories[spl_object_id($backingInventory)] = $backingInventory;
74 foreach($this->backingInventories as $inventory){
75 $size = $inventory->getSize();
77 $this->inventoryToOffsetMap[spl_object_id($inventory)] = $combinedSize;
78 for($slot = 0; $slot < $size; $slot++){
79 $this->slotToInventoryMap[$combinedSize + $slot] = $inventory;
82 $combinedSize += $size;
84 $this->size = $combinedSize;
86 $weakThis = \WeakReference::create($this);
88 static fn(
Inventory $inventory,
int $slot,
Item $oldItem) => $weakThis->get()?->onBackingSlotChange($inventory, $slot, $oldItem),
89 static fn(
Inventory $inventory, array $oldContents) => $weakThis->get()?->onBackingContentChange($inventory, $oldContents)
91 foreach($this->backingInventories as $inventory){
92 $inventory->getListeners()->add($this->backingInventoryListener);
96 private function onBackingSlotChange(
Inventory $inventory,
int $slot,
Item $oldItem) : void{
97 if($this->modifyingBackingInventory){
101 $offset = $this->inventoryToOffsetMap[spl_object_id($inventory)];
102 $this->onSlotChange($offset + $slot, $oldItem);
108 private function onBackingContentChange(Inventory $inventory, array $oldContents) : void{
109 if($this->modifyingBackingInventory){
113 if(count($this->backingInventories) === 1){
114 $this->onContentChange($oldContents);
116 $offset = $this->inventoryToOffsetMap[spl_object_id($inventory)];
117 for($slot = 0, $limit = $inventory->getSize(); $slot < $limit; $slot++){
118 $this->onSlotChange($offset + $slot, $oldContents[$slot] ?? VanillaItems::AIR());
123 public function __destruct(){
124 foreach($this->backingInventories as $inventory){
125 $inventory->getListeners()->remove($this->backingInventoryListener);
132 private function getInventory(
int $slot) : array{
133 $inventory = $this->slotToInventoryMap[$slot] ?? throw new \InvalidArgumentException(
"Invalid combined inventory slot $slot");
134 $actualSlot = $slot - $this->inventoryToOffsetMap[spl_object_id($inventory)];
135 return [$inventory, $actualSlot];
138 protected function internalSetItem(
int $index, Item $item) : void{
139 [$inventory, $actualSlot] = $this->getInventory($index);
142 $this->modifyingBackingInventory =
true;
144 $inventory->setItem($actualSlot, $item);
146 $this->modifyingBackingInventory =
false;
151 $contentsByInventory = array_fill_keys(array_keys($this->backingInventories), []);
152 foreach($items as $i => $item){
153 [$inventory, $actualSlot] = $this->getInventory($i);
154 $contentsByInventory[spl_object_id($inventory)][$actualSlot] = $item;
156 foreach($contentsByInventory as $splObjectId => $backingInventoryContents){
157 $backingInventory = $this->backingInventories[$splObjectId];
160 $this->modifyingBackingInventory =
true;
162 $backingInventory->setContents($backingInventoryContents);
164 $this->modifyingBackingInventory =
false;
174 [$inventory, $actualSlot] = $this->getInventory($index);
175 return $inventory->getItem($actualSlot);
180 foreach($this->backingInventories as $inventory){
181 $offset = $this->inventoryToOffsetMap[spl_object_id($inventory)];
182 foreach($inventory->getContents($includeEmpty) as $i => $item){
183 $result[$offset + $i] = $item;
191 [$inventory, $actualSlot] = $this->getInventory($slot);
192 return $inventory->getMatchingItemCount($actualSlot, $test, $checkTags);
196 [$inventory, $actualSlot] = $this->getInventory($index);
197 return $inventory->isSlotEmpty($actualSlot);
201 foreach($this->backingInventories as $inventory){
202 $inventory->onOpen($window);
206 public function onClose(InventoryWindow $window) : void{
207 foreach($this->backingInventories as $inventory){
208 $inventory->onClose($window);
213 foreach($this->backingInventories as $inventory){
214 $inventory->removeAllWindows();
219 return array_merge(...array_map(fn(
Inventory $inventory) => $inventory->getViewers(), $this->backingInventories));