117 [$windowId, $slotId] =
ItemStackContainerIdTranslator::translate($info->getContainerName()->getContainerId(), $this->inventoryManager->getCurrentWindowId(), $info->getSlotId());
118 $windowAndSlot = $this->inventoryManager->locateWindowAndSlot($windowId, $slotId);
119 if($windowAndSlot ===
null){
120 throw new ItemStackRequestProcessException(
"No open inventory matches container UI ID: " . $info->getContainerName()->getContainerId() .
", slot ID: " . $info->getSlotId());
122 [$window, $slot] = $windowAndSlot;
123 $inventory = $window->getInventory();
124 if(!$inventory->slotExists($slot)){
125 throw new ItemStackRequestProcessException(
"No such inventory slot :" . $this->prettyWindowAndSlot($window, $slot));
128 if($info->getStackId() !== $this->request->getRequestId()){
129 $this->matchItemStack($window, $slot, $info->getStackId());
132 return [$this->builder->getActionBuilder($window), $slot];
151 return $this->takeCreatedItem($count);
153 $this->requestSlotInfos[] = $slotInfo;
154 [$inventory, $slot] = $this->getBuilderInventoryAndSlot($slotInfo);
157 throw new ItemStackRequestProcessException($this->prettyWindowAndSlot($inventory->getInventoryWindow(), $slot) .
": Cannot take less than 1 items from a stack");
160 $existingItem = $inventory->getItem($slot);
161 if($existingItem->getCount() < $count){
162 throw new ItemStackRequestProcessException($this->prettyWindowAndSlot($inventory->getInventoryWindow(), $slot) .
": Cannot take $count items from a stack of " . $existingItem->getCount());
165 $removed = $existingItem->pop($count);
166 $inventory->setItem($slot, $existingItem);
205 if($item !== null && $item->isNull()){
208 if($this->nextCreatedItem !==
null){
211 if($this->createdItemFromCreativeInventory && $this->createdItemsTakenCount > 0){
212 $this->nextCreatedItem->setCount($this->createdItemsTakenCount);
214 }elseif($this->createdItemsTakenCount < $this->nextCreatedItem->getCount()){
215 throw new ItemStackRequestProcessException(
"Not all of the previous created item was taken");
218 $this->nextCreatedItem = $item;
219 $this->createdItemFromCreativeInventory = $creative;
220 $this->createdItemsTakenCount = 0;
227 if($this->specialTransaction !== null){
230 if($repetitions < 1){
233 if($repetitions > 256){
237 throw new ItemStackRequestProcessException(
"Cannot craft a recipe more than 256 times");
239 $craftingManager = $this->player->getServer()->getCraftingManager();
240 $recipeIndex = $recipeId - CraftingDataCache::RECIPE_ID_OFFSET;
241 $recipe = $craftingManager->getCraftingRecipeFromIndex($recipeIndex);
242 if($recipe ===
null){
243 throw new ItemStackRequestProcessException(
"No such crafting recipe index: $recipeIndex");
246 $this->specialTransaction =
new CraftingTransaction($this->player, $craftingManager, [], $recipe, $repetitions);
252 $craftingResults = $recipe->getResultsFor($this->player->getCraftingGrid());
253 foreach($craftingResults as $k => $craftingResult){
254 $craftingResult->setCount($craftingResult->getCount() * $repetitions);
255 $this->craftingResults[$k] = $craftingResult;
257 if(count($this->craftingResults) === 1){
259 $this->setNextCreatedItem($this->craftingResults[array_key_first($this->craftingResults)]);
313 $this->transferItems($action->getSource(), $action->getDestination(), $action->getCount());
315 $this->requestSlotInfos[] = $action->getSlot1();
316 $this->requestSlotInfos[] = $action->getSlot2();
318 [$inventory1, $slot1] = $this->getBuilderInventoryAndSlot($action->getSlot1());
319 [$inventory2, $slot2] = $this->getBuilderInventoryAndSlot($action->getSlot2());
321 $item1 = $inventory1->getItem($slot1);
322 $item2 = $inventory2->getItem($slot2);
323 $inventory1->setItem($slot1, $item2);
324 $inventory2->setItem($slot2, $item1);
325 }elseif($action instanceof DropStackRequestAction){
327 $dropped = $this->removeItemFromSlot($action->getSource(), $action->getCount());
328 $this->builder->addAction(
new DropItemAction($dropped));
330 }elseif($action instanceof DestroyStackRequestAction){
331 $destroyed = $this->removeItemFromSlot($action->getSource(), $action->getCount());
332 $this->builder->addAction(
new DestroyItemAction($destroyed));
334 }elseif($action instanceof CreativeCreateStackRequestAction){
335 $item = $this->player->getCreativeInventory()->getItem($action->getCreativeItemId());
337 throw new ItemStackRequestProcessException(
"No such creative item index: " . $action->getCreativeItemId());
340 $this->setNextCreatedItem($item,
true);
341 }elseif($action instanceof CraftRecipeStackRequestAction){
342 $window = $this->player->getCurrentWindow();
343 if($window instanceof EnchantingTableInventoryWindow){
344 $optionId = $this->inventoryManager->getEnchantingTableOptionIndex($action->getRecipeId());
345 if($optionId !==
null && ($option = $window->getOption($optionId)) !==
null){
346 $this->specialTransaction =
new EnchantingTransaction($this->player, $option, $optionId + 1);
347 $this->setNextCreatedItem($window->getOutput($optionId));
350 $this->beginCrafting($action->getRecipeId(), $action->getRepetitions());
352 }elseif($action instanceof CraftRecipeAutoStackRequestAction){
353 $this->beginCrafting($action->getRecipeId(), $action->getRepetitions());
354 }elseif($action instanceof CraftingConsumeInputStackRequestAction){
355 $this->assertDoingCrafting();
356 $this->removeItemFromSlot($action->getSource(), $action->getCount());
358 }elseif($action instanceof CraftingCreateSpecificResultStackRequestAction){
359 $this->assertDoingCrafting();
361 $nextResultItem = $this->craftingResults[$action->getResultIndex()] ??
null;
362 if($nextResultItem ===
null){
363 throw new ItemStackRequestProcessException(
"No such crafting result index: " . $action->getResultIndex());
365 $this->setNextCreatedItem($nextResultItem);
366 }elseif($action instanceof DeprecatedCraftingResultsStackRequestAction){
368 }elseif($action instanceof MineBlockStackRequestAction){
369 $slot = $action->getHotbarSlot();
370 $this->requestSlotInfos[] =
new ItemStackRequestSlotInfo(
new FullContainerName(ContainerUIIds::HOTBAR), $slot, $action->getStackId());
371 $inventory = $this->player->getInventory();
372 $usedItem = $inventory->slotExists($slot) ? $inventory->getItem($slot) :
null;
373 $predictedDamage = $action->getPredictedDurability();
374 if($usedItem instanceof Durable && $predictedDamage >= 0 && $predictedDamage <= $usedItem->getMaxDurability()){
375 $usedItem->setDamage($predictedDamage);
376 $inventoryWindow = $this->inventoryManager->getInventoryWindow($inventory) ??
throw new AssumptionFailedError(
"The player's inventory should always have an inventory window");
377 $this->inventoryManager->addPredictedSlotChange($inventoryWindow, $slot, $usedItem);
380 throw new ItemStackRequestProcessException(
"Unhandled item stack request action");