Removed pocketmine subdirectory, map PSR-4 style

This commit is contained in:
Dylan K. Taylor
2019-07-30 19:14:57 +01:00
parent 7a77d3dc30
commit 5499ac620c
1044 changed files with 3 additions and 3 deletions

View File

@ -0,0 +1,172 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\inventory\transaction;
use pocketmine\crafting\CraftingRecipe;
use pocketmine\event\inventory\CraftItemEvent;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
use function array_pop;
use function count;
use function intdiv;
/**
* This transaction type is specialized for crafting validation. It shares most of the same semantics of the base
* inventory transaction type, but the requirement for validity is slightly different.
*
* It is expected that the actions in this transaction type will produce an **unbalanced result**, i.e. some inputs won't
* have corresponding outputs, and vice versa. The reason why is because the unmatched inputs are recipe inputs, and
* the unmatched outputs are recipe results.
*
* Therefore, the validity requirement is that the imbalance of the transaction should match the expected inputs and
* outputs of a registered crafting recipe.
*
* This transaction allows multiple repetitions of the same recipe to be crafted in a single batch. In the case of batch
* crafting, the number of unmatched inputs and outputs must be exactly divisible by the expected recipe ingredients and
* results, with no remainder. Any leftovers are expected to be emitted back to the crafting grid.
*/
class CraftingTransaction extends InventoryTransaction{
/** @var CraftingRecipe|null */
protected $recipe;
/** @var int|null */
protected $repetitions;
/** @var Item[] */
protected $inputs = [];
/** @var Item[] */
protected $outputs = [];
/**
* @param Item[] $txItems
* @param Item[] $recipeItems
* @param bool $wildcards
* @param int $iterations
*
* @return int
* @throws TransactionValidationException
*/
protected function matchRecipeItems(array $txItems, array $recipeItems, bool $wildcards, int $iterations = 0) : int{
if(empty($recipeItems)){
throw new TransactionValidationException("No recipe items given");
}
if(empty($txItems)){
throw new TransactionValidationException("No transaction items given");
}
while(!empty($recipeItems)){
/** @var Item $recipeItem */
$recipeItem = array_pop($recipeItems);
$needCount = $recipeItem->getCount();
foreach($recipeItems as $i => $otherRecipeItem){
if($otherRecipeItem->equals($recipeItem)){ //make sure they have the same wildcards set
$needCount += $otherRecipeItem->getCount();
unset($recipeItems[$i]);
}
}
$haveCount = 0;
foreach($txItems as $j => $txItem){
if($txItem->equals($recipeItem, !$wildcards or !$recipeItem->hasAnyDamageValue(), !$wildcards or $recipeItem->hasNamedTag())){
$haveCount += $txItem->getCount();
unset($txItems[$j]);
}
}
if($haveCount % $needCount !== 0){
//wrong count for this output, should divide exactly
throw new TransactionValidationException("Expected an exact multiple of required $recipeItem (given: $haveCount, needed: $needCount)");
}
$multiplier = intdiv($haveCount, $needCount);
if($multiplier < 1){
throw new TransactionValidationException("Expected more than zero items matching $recipeItem (given: $haveCount, needed: $needCount)");
}
if($iterations === 0){
$iterations = $multiplier;
}elseif($multiplier !== $iterations){
//wrong count for this output, should match previous outputs
throw new TransactionValidationException("Expected $recipeItem x$iterations, but found x$multiplier");
}
}
if($iterations < 1){
throw new TransactionValidationException("Tried to craft zero times");
}
if(!empty($txItems)){
//all items should be destroyed in this process
throw new TransactionValidationException("Expected 0 ingredients left over, have " . count($txItems));
}
return $iterations;
}
public function validate() : void{
$this->squashDuplicateSlotChanges();
if(count($this->actions) < 1){
throw new TransactionValidationException("Transaction must have at least one action to be executable");
}
$this->matchItems($this->outputs, $this->inputs);
$failed = 0;
foreach($this->source->getServer()->getCraftingManager()->matchRecipeByOutputs($this->outputs) as $recipe){
try{
//compute number of times recipe was crafted
$this->repetitions = $this->matchRecipeItems($this->outputs, $recipe->getResultsFor($this->source->getCraftingGrid()), false);
//assert that $repetitions x recipe ingredients should be consumed
$this->matchRecipeItems($this->inputs, $recipe->getIngredientList(), true, $this->repetitions);
//Success!
$this->recipe = $recipe;
break;
}catch(TransactionValidationException $e){
//failed
++$failed;
}
}
if($this->recipe === null){
throw new TransactionValidationException("Unable to match a recipe to transaction (tried to match against $failed recipes)");
}
}
protected function callExecuteEvent() : bool{
$ev = new CraftItemEvent($this, $this->recipe, $this->repetitions, $this->inputs, $this->outputs);
$ev->call();
return !$ev->isCancelled();
}
protected function sendInventories() : void{
parent::sendInventories();
/*
* TODO: HACK!
* we can't resend the contents of the crafting window, so we force the client to close it instead.
* So people don't whine about messy desync issues when someone cancels CraftItemEvent, or when a crafting
* transaction goes wrong.
*/
$this->source->sendDataPacket(ContainerClosePacket::create(ContainerIds::NONE));
}
}

View File

@ -0,0 +1,338 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\inventory\transaction;
use pocketmine\event\inventory\InventoryTransactionEvent;
use pocketmine\inventory\Inventory;
use pocketmine\inventory\transaction\action\InventoryAction;
use pocketmine\inventory\transaction\action\SlotChangeAction;
use pocketmine\item\Item;
use pocketmine\player\Player;
use function array_keys;
use function assert;
use function count;
use function get_class;
use function min;
use function shuffle;
use function spl_object_hash;
use function spl_object_id;
/**
* This is the basic type for an inventory transaction. This is used for moving items between inventories, dropping
* items and more. It allows transactions with multiple inputs and outputs.
*
* Validation **does not** depend on ordering. This means that the actions can appear in any order and still be valid.
* The only validity requirement for this transaction type is that the balance of items must add up to zero. This means:
* - No new outputs without matching input amounts
* - No inputs without matching output amounts
* - No userdata changes (item state, NBT, etc)
*
* A transaction is composed of "actions", which are pairs of inputs and outputs which target a specific itemstack in
* a specific location. There are multiple types of inventory actions which might be involved in a transaction.
*
* @see InventoryAction
*/
class InventoryTransaction{
protected $hasExecuted = false;
/** @var Player */
protected $source;
/** @var Inventory[] */
protected $inventories = [];
/** @var InventoryAction[] */
protected $actions = [];
/**
* @param Player $source
* @param InventoryAction[] $actions
*/
public function __construct(Player $source, array $actions = []){
$this->source = $source;
foreach($actions as $action){
$this->addAction($action);
}
}
/**
* @return Player
*/
public function getSource() : Player{
return $this->source;
}
/**
* @return Inventory[]
*/
public function getInventories() : array{
return $this->inventories;
}
/**
* Returns an **unordered** set of actions involved in this transaction.
*
* WARNING: This system is **explicitly designed NOT to care about ordering**. Any order seen in this set has NO
* significance and should not be relied on.
*
* @return InventoryAction[]
*/
public function getActions() : array{
return $this->actions;
}
/**
* @param InventoryAction $action
*/
public function addAction(InventoryAction $action) : void{
if(!isset($this->actions[$hash = spl_object_id($action)])){
$this->actions[$hash] = $action;
$action->onAddToTransaction($this);
}else{
throw new \InvalidArgumentException("Tried to add the same action to a transaction twice");
}
}
/**
* Shuffles actions in the transaction to prevent external things relying on any implicit ordering.
*/
private function shuffleActions() : void{
$keys = array_keys($this->actions);
shuffle($keys);
$actions = [];
foreach($keys as $key){
$actions[$key] = $this->actions[$key];
}
$this->actions = $actions;
}
/**
* @internal This method should not be used by plugins, it's used to add tracked inventories for InventoryActions
* involving inventories.
*
* @param Inventory $inventory
*/
public function addInventory(Inventory $inventory) : void{
if(!isset($this->inventories[$hash = spl_object_id($inventory)])){
$this->inventories[$hash] = $inventory;
}
}
/**
* @param Item[] $needItems
* @param Item[] $haveItems
*
* @throws TransactionValidationException
*/
protected function matchItems(array &$needItems, array &$haveItems) : void{
foreach($this->actions as $key => $action){
if(!$action->getTargetItem()->isNull()){
$needItems[] = $action->getTargetItem();
}
if(!$action->isValid($this->source)){
throw new TransactionValidationException("Action " . get_class($action) . " is not valid in the current transaction");
}
if(!$action->getSourceItem()->isNull()){
$haveItems[] = $action->getSourceItem();
}
}
foreach($needItems as $i => $needItem){
foreach($haveItems as $j => $haveItem){
if($needItem->equals($haveItem)){
$amount = min($needItem->getCount(), $haveItem->getCount());
$needItem->setCount($needItem->getCount() - $amount);
$haveItem->setCount($haveItem->getCount() - $amount);
if($haveItem->getCount() === 0){
unset($haveItems[$j]);
}
if($needItem->getCount() === 0){
unset($needItems[$i]);
break;
}
}
}
}
}
/**
* Iterates over SlotChangeActions in this transaction and compacts any which refer to the same slot in the same
* inventory so they can be correctly handled.
*
* Under normal circumstances, the same slot would never be changed more than once in a single transaction. However,
* due to the way things like the crafting grid are "implemented" in MCPE 1.2 (a.k.a. hacked-in), we may get
* multiple slot changes referring to the same slot in a single transaction. These multiples are not even guaranteed
* to be in the correct order (slot splitting in the crafting grid for example, causes the actions to be sent in the
* wrong order), so this method also tries to chain them into order.
*/
protected function squashDuplicateSlotChanges() : void{
/** @var SlotChangeAction[][] $slotChanges */
$slotChanges = [];
/** @var Inventory[] $inventories */
$inventories = [];
/** @var int[] $slots */
$slots = [];
foreach($this->actions as $key => $action){
if($action instanceof SlotChangeAction){
$slotChanges[$h = (spl_object_hash($action->getInventory()) . "@" . $action->getSlot())][] = $action;
$inventories[$h] = $action->getInventory();
$slots[$h] = $action->getSlot();
}
}
foreach($slotChanges as $hash => $list){
if(count($list) === 1){ //No need to compact slot changes if there is only one on this slot
continue;
}
$inventory = $inventories[$hash];
$slot = $slots[$hash];
if(!$inventory->slotExists($slot)){ //this can get hit for crafting tables because the validation happens after this compaction
throw new TransactionValidationException("Slot $slot does not exist in inventory " . get_class($inventory));
}
$sourceItem = $inventory->getItem($slot);
$targetItem = $this->findResultItem($sourceItem, $list);
if($targetItem === null){
throw new TransactionValidationException("Failed to compact " . count($list) . " duplicate actions");
}
foreach($list as $action){
unset($this->actions[spl_object_id($action)]);
}
if(!$targetItem->equalsExact($sourceItem)){
//sometimes we get actions on the crafting grid whose source and target items are the same, so dump them
$this->addAction(new SlotChangeAction($inventory, $slot, $sourceItem, $targetItem));
}
}
}
/**
* @param Item $needOrigin
* @param SlotChangeAction[] $possibleActions
*
* @return null|Item
*/
protected function findResultItem(Item $needOrigin, array $possibleActions) : ?Item{
assert(!empty($possibleActions));
foreach($possibleActions as $i => $action){
if($action->getSourceItem()->equalsExact($needOrigin)){
$newList = $possibleActions;
unset($newList[$i]);
if(empty($newList)){
return $action->getTargetItem();
}
$result = $this->findResultItem($action->getTargetItem(), $newList);
if($result !== null){
return $result;
}
}
}
return null;
}
/**
* Verifies that the transaction can execute.
*
* @throws TransactionValidationException
*/
public function validate() : void{
$this->squashDuplicateSlotChanges();
$haveItems = [];
$needItems = [];
$this->matchItems($needItems, $haveItems);
if(count($this->actions) === 0){
throw new TransactionValidationException("Inventory transaction must have at least one action to be executable");
}
if(count($haveItems) > 0){
throw new TransactionValidationException("Transaction does not balance (tried to destroy some items)");
}
if(count($needItems) > 0){
throw new TransactionValidationException("Transaction does not balance (tried to create some items)");
}
}
protected function sendInventories() : void{
foreach($this->inventories as $inventory){
$this->source->getNetworkSession()->getInvManager()->syncContents($inventory);
}
}
protected function callExecuteEvent() : bool{
$ev = new InventoryTransactionEvent($this);
$ev->call();
return !$ev->isCancelled();
}
/**
* Executes the group of actions, returning whether the transaction executed successfully or not.
* @return bool
*
* @throws TransactionValidationException
*/
public function execute() : bool{
if($this->hasExecuted()){
$this->sendInventories();
return false;
}
$this->shuffleActions();
$this->validate();
if(!$this->callExecuteEvent()){
$this->sendInventories();
return false;
}
foreach($this->actions as $action){
if(!$action->onPreExecute($this->source)){
$this->sendInventories();
return false;
}
}
foreach($this->actions as $action){
$action->execute($this->source);
}
$this->hasExecuted = true;
return true;
}
/**
* @return bool
*/
public function hasExecuted() : bool{
return $this->hasExecuted;
}
}

View File

@ -0,0 +1,28 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\inventory\transaction;
class TransactionValidationException extends \RuntimeException{
}

View File

@ -0,0 +1,48 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\inventory\transaction\action;
use pocketmine\inventory\CreativeInventory;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\player\Player;
/**
* This action is used by creative players to balance transactions involving the creative inventory menu.
* The source item is the item being created ("taken" from the creative menu).
*/
class CreateItemAction extends InventoryAction{
public function __construct(Item $sourceItem){
parent::__construct($sourceItem, ItemFactory::air());
}
public function isValid(Player $source) : bool{
return !$source->hasFiniteResources() and CreativeInventory::contains($this->sourceItem);
}
public function execute(Player $source) : void{
//NOOP
}
}

View File

@ -0,0 +1,47 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\inventory\transaction\action;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\player\Player;
/**
* This action type shows up when a creative player puts an item into the creative inventory menu to destroy it.
* The output is the item destroyed. You can think of this action type like setting an item into /dev/null
*/
class DestroyItemAction extends InventoryAction{
public function __construct(Item $targetItem){
parent::__construct(ItemFactory::air(), $targetItem);
}
public function isValid(Player $source) : bool{
return !$source->hasFiniteResources();
}
public function execute(Player $source) : void{
//NOOP
}
}

View File

@ -0,0 +1,62 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\inventory\transaction\action;
use pocketmine\event\player\PlayerDropItemEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\player\Player;
/**
* Represents an action involving dropping an item into the world.
*/
class DropItemAction extends InventoryAction{
public function __construct(Item $targetItem){
parent::__construct(ItemFactory::air(), $targetItem);
}
public function isValid(Player $source) : bool{
return !$this->targetItem->isNull();
}
public function onPreExecute(Player $source) : bool{
$ev = new PlayerDropItemEvent($source, $this->targetItem);
$ev->call();
if($ev->isCancelled()){
return false;
}
return true;
}
/**
* Drops the target item in front of the player.
*
* @param Player $source
*/
public function execute(Player $source) : void{
$source->dropItem($this->targetItem);
}
}

View File

@ -0,0 +1,97 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\inventory\transaction\action;
use pocketmine\inventory\transaction\InventoryTransaction;
use pocketmine\item\Item;
use pocketmine\player\Player;
/**
* Represents an action involving a change that applies in some way to an inventory or other item-source.
*/
abstract class InventoryAction{
/** @var Item */
protected $sourceItem;
/** @var Item */
protected $targetItem;
public function __construct(Item $sourceItem, Item $targetItem){
$this->sourceItem = $sourceItem;
$this->targetItem = $targetItem;
}
/**
* Returns the item that was present before the action took place.
* @return Item
*/
public function getSourceItem() : Item{
return clone $this->sourceItem;
}
/**
* Returns the item that the action attempted to replace the source item with.
* @return Item
*/
public function getTargetItem() : Item{
return clone $this->targetItem;
}
/**
* Returns whether this action is currently valid. This should perform any necessary sanity checks.
*
* @param Player $source
*
* @return bool
*/
abstract public function isValid(Player $source) : bool;
/**
* Called when the action is added to the specified InventoryTransaction.
*
* @param InventoryTransaction $transaction
*/
public function onAddToTransaction(InventoryTransaction $transaction) : void{
}
/**
* Called by inventory transactions before any actions are processed. If this returns false, the transaction will
* be cancelled.
*
* @param Player $source
*
* @return bool
*/
public function onPreExecute(Player $source) : bool{
return true;
}
/**
* Performs actions needed to complete the inventory-action server-side. This will only be called if the transaction
* which it is part of is considered valid.
*
* @param Player $source
*/
abstract public function execute(Player $source) : void;
}

View File

@ -0,0 +1,107 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\inventory\transaction\action;
use pocketmine\inventory\Inventory;
use pocketmine\inventory\transaction\InventoryTransaction;
use pocketmine\item\Item;
use pocketmine\player\Player;
/**
* Represents an action causing a change in an inventory slot.
*/
class SlotChangeAction extends InventoryAction{
/** @var Inventory */
protected $inventory;
/** @var int */
private $inventorySlot;
/**
* @param Inventory $inventory
* @param int $inventorySlot
* @param Item $sourceItem
* @param Item $targetItem
*/
public function __construct(Inventory $inventory, int $inventorySlot, Item $sourceItem, Item $targetItem){
parent::__construct($sourceItem, $targetItem);
$this->inventory = $inventory;
$this->inventorySlot = $inventorySlot;
}
/**
* Returns the inventory involved in this action.
*
* @return Inventory
*/
public function getInventory() : Inventory{
return $this->inventory;
}
/**
* Returns the slot in the inventory which this action modified.
* @return int
*/
public function getSlot() : int{
return $this->inventorySlot;
}
/**
* Checks if the item in the inventory at the specified slot is the same as this action's source item.
*
* @param Player $source
*
* @return bool
*/
public function isValid(Player $source) : bool{
return (
$this->inventory->slotExists($this->inventorySlot) and
$this->inventory->getItem($this->inventorySlot)->equalsExact($this->sourceItem)
);
}
/**
* Adds this action's target inventory to the transaction's inventory list.
*
* @param InventoryTransaction $transaction
*
*/
public function onAddToTransaction(InventoryTransaction $transaction) : void{
$transaction->addInventory($this->inventory);
}
/**
* Sets the item into the target inventory.
*
* @param Player $source
*/
public function execute(Player $source) : void{
$this->inventory->setItem($this->inventorySlot, $this->targetItem, false);
foreach($this->inventory->getViewers() as $viewer){
if($viewer !== $source){
$viewer->getNetworkSession()->getInvManager()->syncSlot($this->inventory, $this->inventorySlot);
}
}
}
}