143 protected function matchItems(array &$needItems, array &$haveItems) : void{
146 foreach($this->actions as $key => $action){
147 if(!$action->getTargetItem()->isNull()){
148 $needItems[] = $action->getTargetItem();
152 $action->validate($this->source);
157 if(!$action->getSourceItem()->isNull()){
158 $haveItems[] = $action->getSourceItem();
162 foreach($needItems as $i => $needItem){
163 foreach($haveItems as $j => $haveItem){
164 if($needItem->canStackWith($haveItem)){
165 $amount = min($needItem->getCount(), $haveItem->getCount());
166 $needItem->setCount($needItem->getCount() - $amount);
167 $haveItem->setCount($haveItem->getCount() - $amount);
168 if($haveItem->getCount() === 0){
169 unset($haveItems[$j]);
171 if($needItem->getCount() === 0){
172 unset($needItems[$i]);
178 $needItems = array_values($needItems);
179 $haveItems = array_values($haveItems);
197 foreach($this->actions as $key => $action){
199 $slotChanges[$h = (spl_object_hash($action->getInventory()) .
"@" . $action->getSlot())][] = $action;
200 $inventories[$h] = $action->getInventory();
201 $slots[$h] = $action->getSlot();
205 foreach(Utils::stringifyKeys($slotChanges) as $hash => $list){
206 if(count($list) === 1){
210 $inventory = $inventories[$hash];
211 $slot = $slots[$hash];
212 if(!$inventory->slotExists($slot)){
215 $sourceItem = $inventory->getItem($slot);
217 $targetItem = $this->findResultItem($sourceItem, $list);
218 if($targetItem ===
null){
219 throw new TransactionValidationException(
"Failed to compact " . count($list) .
" duplicate actions");
222 foreach($list as $action){
223 unset($this->actions[spl_object_id($action)]);
226 if(!$targetItem->equalsExact($sourceItem)){
228 $this->addAction(
new SlotChangeAction($inventory, $slot, $sourceItem, $targetItem));
238 assert(count($possibleActions) > 0);
241 $newList = $possibleActions;
242 foreach($possibleActions as $i => $action){
243 if($action->getSourceItem()->equalsExact($needOrigin)){
244 if($candidate !==
null){
255 $candidate = $action;
259 if($candidate ===
null){
264 if(count($newList) === 0){
265 return $candidate->getTargetItem();
267 return $this->findResultItem($candidate->getTargetItem(), $newList);
305 if($this->hasExecuted()){
309 $this->shuffleActions();
313 if(!$this->callExecuteEvent()){
317 foreach($this->actions as $action){
318 if(!$action->onPreExecute($this->source)){
319 throw new TransactionCancelledException(
"One of the actions in this transaction was cancelled");
323 foreach($this->actions as $action){
324 $action->execute($this->source);
327 $this->hasExecuted =
true;