131 protected function matchItems(array &$needItems, array &$haveItems) : void{
134 foreach($this->actions as $key => $action){
135 $targetItem = $action->getTargetItem();
136 if(!$targetItem->isNull()){
137 $needItems[] = $targetItem;
141 $action->validate($this->source);
146 $sourceItem = $action->getSourceItem();
147 if(!$sourceItem->isNull()){
148 $haveItems[] = $sourceItem;
152 foreach($needItems as $i => $needItem){
153 foreach($haveItems as $j => $haveItem){
154 if($needItem->canStackWith($haveItem)){
155 $amount = min($needItem->getCount(), $haveItem->getCount());
156 $needItem->setCount($needItem->getCount() - $amount);
157 $haveItem->setCount($haveItem->getCount() - $amount);
158 if($haveItem->getCount() === 0){
159 unset($haveItems[$j]);
161 if($needItem->getCount() === 0){
162 unset($needItems[$i]);
168 $needItems = array_values($needItems);
169 $haveItems = array_values($haveItems);
187 foreach($this->actions as $key => $action){
189 $slotChanges[$h = (spl_object_hash($action->getInventoryWindow()) .
"@" . $action->getSlot())][] = $action;
190 $inventories[$h] = $action->getInventoryWindow();
191 $slots[$h] = $action->getSlot();
195 foreach(Utils::stringifyKeys($slotChanges) as $hash => $list){
196 if(count($list) === 1){
200 $window = $inventories[$hash];
201 $inventory = $window->getInventory();
202 $slot = $slots[$hash];
203 if(!$inventory->slotExists($slot)){
206 $sourceItem = $inventory->getItem($slot);
208 $targetItem = $this->findResultItem($sourceItem, $list);
209 if($targetItem ===
null){
210 throw new TransactionValidationException(
"Failed to compact " . count($list) .
" duplicate actions");
213 foreach($list as $action){
214 unset($this->actions[spl_object_id($action)]);
217 if(!$targetItem->equalsExact($sourceItem)){
219 $this->addAction(
new SlotChangeAction($window, $slot, $sourceItem, $targetItem));
229 assert(count($possibleActions) > 0);
232 $newList = $possibleActions;
233 foreach($possibleActions as $i => $action){
234 if($action->getSourceItem()->equalsExact($needOrigin)){
235 if($candidate !==
null){
246 $candidate = $action;
250 if($candidate ===
null){
255 if(count($newList) === 0){
256 return $candidate->getTargetItem();
258 return $this->findResultItem($candidate->getTargetItem(), $newList);
296 if($this->hasExecuted()){
302 if(!$this->callExecuteEvent()){
306 foreach($this->actions as $action){
307 if(!$action->onPreExecute($this->source)){
308 throw new TransactionCancelledException(
"One of the actions in this transaction was cancelled");
312 foreach($this->actions as $action){
313 $action->execute($this->source);
316 $this->hasExecuted =
true;