143 protected function matchItems(array &$needItems, array &$haveItems) : void{
146 foreach($this->actions as $key => $action){
147 $targetItem = $action->getTargetItem();
148 if(!$targetItem->isNull()){
149 $needItems[] = $targetItem;
153 $action->validate($this->source);
158 $sourceItem = $action->getSourceItem();
159 if(!$sourceItem->isNull()){
160 $haveItems[] = $sourceItem;
164 foreach($needItems as $i => $needItem){
165 foreach($haveItems as $j => $haveItem){
166 if($needItem->canStackWith($haveItem)){
167 $amount = min($needItem->getCount(), $haveItem->getCount());
168 $needItem->setCount($needItem->getCount() - $amount);
169 $haveItem->setCount($haveItem->getCount() - $amount);
170 if($haveItem->getCount() === 0){
171 unset($haveItems[$j]);
173 if($needItem->getCount() === 0){
174 unset($needItems[$i]);
180 $needItems = array_values($needItems);
181 $haveItems = array_values($haveItems);
199 foreach($this->actions as $key => $action){
201 $slotChanges[$h = (spl_object_hash($action->getInventory()) .
"@" . $action->getSlot())][] = $action;
202 $inventories[$h] = $action->getInventory();
203 $slots[$h] = $action->getSlot();
207 foreach(Utils::stringifyKeys($slotChanges) as $hash => $list){
208 if(count($list) === 1){
212 $inventory = $inventories[$hash];
213 $slot = $slots[$hash];
214 if(!$inventory->slotExists($slot)){
217 $sourceItem = $inventory->getItem($slot);
219 $targetItem = $this->findResultItem($sourceItem, $list);
220 if($targetItem ===
null){
221 throw new TransactionValidationException(
"Failed to compact " . count($list) .
" duplicate actions");
224 foreach($list as $action){
225 unset($this->actions[spl_object_id($action)]);
228 if(!$targetItem->equalsExact($sourceItem)){
230 $this->addAction(
new SlotChangeAction($inventory, $slot, $sourceItem, $targetItem));
240 assert(count($possibleActions) > 0);
243 $newList = $possibleActions;
244 foreach($possibleActions as $i => $action){
245 if($action->getSourceItem()->equalsExact($needOrigin)){
246 if($candidate !==
null){
257 $candidate = $action;
261 if($candidate ===
null){
266 if(count($newList) === 0){
267 return $candidate->getTargetItem();
269 return $this->findResultItem($candidate->getTargetItem(), $newList);
307 if($this->hasExecuted()){
311 $this->shuffleActions();
315 if(!$this->callExecuteEvent()){
319 foreach($this->actions as $action){
320 if(!$action->onPreExecute($this->source)){
321 throw new TransactionCancelledException(
"One of the actions in this transaction was cancelled");
325 foreach($this->actions as $action){
326 $action->execute($this->source);
329 $this->hasExecuted =
true;