Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate transaction slots #6304

Open
wants to merge 16 commits into
base: minor-next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/inventory/ArmorInventory.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@

namespace pocketmine\inventory;

use pocketmine\block\BlockTypeIds;
use pocketmine\entity\Living;
use pocketmine\item\Armor;
use pocketmine\item\Item;
use pocketmine\item\ItemBlock;

class ArmorInventory extends SimpleInventory{
public const SLOT_HEAD = 0;
Expand All @@ -36,6 +39,14 @@ public function __construct(
protected Living $holder
){
parent::__construct(4);

$this->validators->add(static function (Inventory $inventory, Item $item, int $slot) : bool{
return ($item instanceof Armor && $item->getArmorSlot() === $slot) ||
($slot === ArmorInventory::SLOT_HEAD && $item instanceof ItemBlock && (
$item->getBlock()->getTypeId() === BlockTypeIds::CARVED_PUMPKIN ||
$item->getBlock()->getTypeId() === BlockTypeIds::MOB_HEAD
));
});
}

public function getHolder() : Living{
Expand Down
11 changes: 10 additions & 1 deletion src/inventory/BaseInventory.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@

/**
* This class provides everything needed to implement an inventory, minus the underlying storage system.
*
* @phpstan-import-type SlotValidators from SlotSafeInventory
*/
abstract class BaseInventory implements Inventory{
abstract class BaseInventory implements Inventory, SlotSafeInventory{
protected int $maxStackSize = Inventory::MAX_STACK;
/** @var Player[] */
protected array $viewers = [];
Expand All @@ -46,9 +48,12 @@ abstract class BaseInventory implements Inventory{
* @phpstan-var ObjectSet<InventoryListener>
*/
protected ObjectSet $listeners;
/** @phpstan-var SlotValidators */
protected ObjectSet $validators;

public function __construct(){
$this->listeners = new ObjectSet();
$this->validators = new ObjectSet();
}

public function getMaxStackSize() : int{
Expand Down Expand Up @@ -398,4 +403,8 @@ public function slotExists(int $slot) : bool{
public function getListeners() : ObjectSet{
return $this->listeners;
}

public function getSlotValidators() : ObjectSet{
return $this->validators;
}
}
46 changes: 46 additions & 0 deletions src/inventory/SlotSafeInventory.php
Original file line number Diff line number Diff line change
@@ -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\item\Item;
use pocketmine\utils\ObjectSet;

/**
* A "slot safe inventory" has validators which may restrict items
* from being placed in particular slots of the inventory.
*
* @phpstan-type SlotValidators ObjectSet<\Closure(Inventory $inventory, Item $item, int $slot): bool>
*/
interface SlotSafeInventory{
ShockedPlot7560 marked this conversation as resolved.
Show resolved Hide resolved
/**
* 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 true for the transaction to be allowed.
* If one of the validators returns false, 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;
}
12 changes: 12 additions & 0 deletions src/inventory/transaction/action/SlotChangeAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
namespace pocketmine\inventory\transaction\action;

use pocketmine\inventory\Inventory;
use pocketmine\inventory\SlotSafeInventory;
use pocketmine\inventory\transaction\InventoryTransaction;
use pocketmine\inventory\transaction\TransactionValidationException;
use pocketmine\item\Item;
Expand Down Expand Up @@ -74,6 +75,17 @@ public function validate(Player $source) : void{
if($this->targetItem->getCount() > $this->inventory->getMaxStackSize()){
throw new TransactionValidationException("Target item exceeds inventory max stack size");
}
if($this->inventory instanceof SlotSafeInventory && !$this->targetItem->isNull()){
foreach($this->inventory->getSlotValidators() as $validator){
try{
if(!$validator($this->inventory, $this->targetItem, $this->inventorySlot)){
throw new TransactionValidationException("Target item is not accepted by the inventory");
}
}catch(TransactionValidationException $e){
throw new TransactionValidationException("Target item is not accepted by the inventory: " . $e->getMessage());
ShockedPlot7560 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}

/**
Expand Down