mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-06 11:57:10 +00:00
Validate transaction slots (#6304)
This commit is contained in:
parent
8cb2e577a1
commit
f6e2a1ecce
@ -23,8 +23,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\inventory;
|
namespace pocketmine\inventory;
|
||||||
|
|
||||||
|
use pocketmine\block\BlockTypeIds;
|
||||||
use pocketmine\entity\Living;
|
use pocketmine\entity\Living;
|
||||||
|
use pocketmine\inventory\transaction\action\validator\CallbackSlotValidator;
|
||||||
|
use pocketmine\inventory\transaction\TransactionValidationException;
|
||||||
|
use pocketmine\item\Armor;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\item\ItemBlock;
|
||||||
|
|
||||||
class ArmorInventory extends SimpleInventory{
|
class ArmorInventory extends SimpleInventory{
|
||||||
public const SLOT_HEAD = 0;
|
public const SLOT_HEAD = 0;
|
||||||
@ -36,6 +41,8 @@ class ArmorInventory extends SimpleInventory{
|
|||||||
protected Living $holder
|
protected Living $holder
|
||||||
){
|
){
|
||||||
parent::__construct(4);
|
parent::__construct(4);
|
||||||
|
|
||||||
|
$this->validators->add(new CallbackSlotValidator($this->validate(...)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHolder() : Living{
|
public function getHolder() : Living{
|
||||||
@ -73,4 +80,20 @@ class ArmorInventory extends SimpleInventory{
|
|||||||
public function setBoots(Item $boots) : void{
|
public function setBoots(Item $boots) : void{
|
||||||
$this->setItem(self::SLOT_FEET, $boots);
|
$this->setItem(self::SLOT_FEET, $boots);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function validate(Inventory $inventory, Item $item, int $slot) : ?TransactionValidationException{
|
||||||
|
if($item instanceof Armor){
|
||||||
|
if($item->getArmorSlot() !== $slot){
|
||||||
|
return new TransactionValidationException("Armor item is in wrong slot");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(!($slot === ArmorInventory::SLOT_HEAD && $item instanceof ItemBlock && (
|
||||||
|
$item->getBlock()->getTypeId() === BlockTypeIds::CARVED_PUMPKIN ||
|
||||||
|
$item->getBlock()->getTypeId() === BlockTypeIds::MOB_HEAD
|
||||||
|
))){
|
||||||
|
return new TransactionValidationException("Item is not accepted in an armor slot");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,10 @@ use function spl_object_id;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides everything needed to implement an inventory, minus the underlying storage system.
|
* This class provides everything needed to implement an inventory, minus the underlying storage system.
|
||||||
|
*
|
||||||
|
* @phpstan-import-type SlotValidators from SlotValidatedInventory
|
||||||
*/
|
*/
|
||||||
abstract class BaseInventory implements Inventory{
|
abstract class BaseInventory implements Inventory, SlotValidatedInventory{
|
||||||
protected int $maxStackSize = Inventory::MAX_STACK;
|
protected int $maxStackSize = Inventory::MAX_STACK;
|
||||||
/** @var Player[] */
|
/** @var Player[] */
|
||||||
protected array $viewers = [];
|
protected array $viewers = [];
|
||||||
@ -46,9 +48,12 @@ abstract class BaseInventory implements Inventory{
|
|||||||
* @phpstan-var ObjectSet<InventoryListener>
|
* @phpstan-var ObjectSet<InventoryListener>
|
||||||
*/
|
*/
|
||||||
protected ObjectSet $listeners;
|
protected ObjectSet $listeners;
|
||||||
|
/** @phpstan-var SlotValidators */
|
||||||
|
protected ObjectSet $validators;
|
||||||
|
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
$this->listeners = new ObjectSet();
|
$this->listeners = new ObjectSet();
|
||||||
|
$this->validators = new ObjectSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMaxStackSize() : int{
|
public function getMaxStackSize() : int{
|
||||||
@ -398,4 +403,8 @@ abstract class BaseInventory implements Inventory{
|
|||||||
public function getListeners() : ObjectSet{
|
public function getListeners() : ObjectSet{
|
||||||
return $this->listeners;
|
return $this->listeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getSlotValidators() : ObjectSet{
|
||||||
|
return $this->validators;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
46
src/inventory/SlotValidatedInventory.php
Normal file
46
src/inventory/SlotValidatedInventory.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
use pocketmine\inventory\transaction\action\validator\SlotValidator;
|
||||||
|
use pocketmine\utils\ObjectSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A "slot validated inventory" has validators which may restrict items
|
||||||
|
* from being placed in particular slots of the inventory when transactions are executed.
|
||||||
|
*
|
||||||
|
* @phpstan-type SlotValidators ObjectSet<SlotValidator>
|
||||||
|
*/
|
||||||
|
interface SlotValidatedInventory{
|
||||||
|
/**
|
||||||
|
* Returns a set of validators that will be used to determine whether an item can be placed in a particular slot.
|
||||||
|
* All validators need to return null for the transaction to be allowed.
|
||||||
|
* If one of the validators returns an exception, the transaction will be cancelled.
|
||||||
|
*
|
||||||
|
* There is no guarantee that the validators will be called in any particular order.
|
||||||
|
*
|
||||||
|
* @phpstan-return SlotValidators
|
||||||
|
*/
|
||||||
|
public function getSlotValidators() : ObjectSet;
|
||||||
|
}
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\inventory\transaction\action;
|
namespace pocketmine\inventory\transaction\action;
|
||||||
|
|
||||||
use pocketmine\inventory\Inventory;
|
use pocketmine\inventory\Inventory;
|
||||||
|
use pocketmine\inventory\SlotValidatedInventory;
|
||||||
use pocketmine\inventory\transaction\InventoryTransaction;
|
use pocketmine\inventory\transaction\InventoryTransaction;
|
||||||
use pocketmine\inventory\transaction\TransactionValidationException;
|
use pocketmine\inventory\transaction\TransactionValidationException;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
@ -74,6 +75,14 @@ class SlotChangeAction extends InventoryAction{
|
|||||||
if($this->targetItem->getCount() > $this->inventory->getMaxStackSize()){
|
if($this->targetItem->getCount() > $this->inventory->getMaxStackSize()){
|
||||||
throw new TransactionValidationException("Target item exceeds inventory max stack size");
|
throw new TransactionValidationException("Target item exceeds inventory max stack size");
|
||||||
}
|
}
|
||||||
|
if($this->inventory instanceof SlotValidatedInventory && !$this->targetItem->isNull()){
|
||||||
|
foreach($this->inventory->getSlotValidators() as $validator){
|
||||||
|
$ret = $validator->validate($this->inventory, $this->targetItem, $this->inventorySlot);
|
||||||
|
if($ret !== null){
|
||||||
|
throw new TransactionValidationException("Target item is not accepted by the inventory at slot #" . $this->inventorySlot . ": " . $ret->getMessage(), 0, $ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
<?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\validator;
|
||||||
|
|
||||||
|
use pocketmine\inventory\Inventory;
|
||||||
|
use pocketmine\inventory\transaction\TransactionValidationException;
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\utils\Utils;
|
||||||
|
|
||||||
|
class CallbackSlotValidator implements SlotValidator{
|
||||||
|
/**
|
||||||
|
* @phpstan-param \Closure(Inventory, Item, int) : ?TransactionValidationException $validate
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
private \Closure $validate
|
||||||
|
){
|
||||||
|
Utils::validateCallableSignature(function(Inventory $inventory, Item $item, int $slot) : ?TransactionValidationException{ return null; }, $validate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validate(Inventory $inventory, Item $item, int $slot) : ?TransactionValidationException{
|
||||||
|
return ($this->validate)($inventory, $item, $slot);
|
||||||
|
}
|
||||||
|
}
|
38
src/inventory/transaction/action/validator/SlotValidator.php
Normal file
38
src/inventory/transaction/action/validator/SlotValidator.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?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\validator;
|
||||||
|
|
||||||
|
use pocketmine\inventory\Inventory;
|
||||||
|
use pocketmine\inventory\transaction\TransactionValidationException;
|
||||||
|
use pocketmine\item\Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a slot placement in an inventory.
|
||||||
|
*/
|
||||||
|
interface SlotValidator{
|
||||||
|
/**
|
||||||
|
* Returns null if the slot placement is valid, or a TransactionValidationException if it is not.
|
||||||
|
*/
|
||||||
|
public function validate(Inventory $inventory, Item $item, int $slot) : ?TransactionValidationException;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user