mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-07 18:32:55 +00:00
Removed pocketmine subdirectory, map PSR-4 style
This commit is contained in:
54
src/inventory/AnvilInventory.php
Normal file
54
src/inventory/AnvilInventory.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?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\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class AnvilInventory extends BlockInventory{
|
||||
|
||||
/** @var Position */
|
||||
protected $holder;
|
||||
|
||||
public function __construct(Position $pos){
|
||||
parent::__construct($pos->asPosition(), 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* This override is here for documentation and code completion purposes only.
|
||||
* @return Position
|
||||
*/
|
||||
public function getHolder(){
|
||||
return $this->holder;
|
||||
}
|
||||
|
||||
public function onClose(Player $who) : void{
|
||||
parent::onClose($who);
|
||||
|
||||
foreach($this->getContents() as $item){
|
||||
$who->dropItem($item);
|
||||
}
|
||||
$this->clearAll();
|
||||
}
|
||||
}
|
78
src/inventory/ArmorInventory.php
Normal file
78
src/inventory/ArmorInventory.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?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\entity\Living;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class ArmorInventory extends BaseInventory{
|
||||
public const SLOT_HEAD = 0;
|
||||
public const SLOT_CHEST = 1;
|
||||
public const SLOT_LEGS = 2;
|
||||
public const SLOT_FEET = 3;
|
||||
|
||||
/** @var Living */
|
||||
protected $holder;
|
||||
|
||||
public function __construct(Living $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(4);
|
||||
}
|
||||
|
||||
public function getHolder() : Living{
|
||||
return $this->holder;
|
||||
}
|
||||
|
||||
public function getHelmet() : Item{
|
||||
return $this->getItem(self::SLOT_HEAD);
|
||||
}
|
||||
|
||||
public function getChestplate() : Item{
|
||||
return $this->getItem(self::SLOT_CHEST);
|
||||
}
|
||||
|
||||
public function getLeggings() : Item{
|
||||
return $this->getItem(self::SLOT_LEGS);
|
||||
}
|
||||
|
||||
public function getBoots() : Item{
|
||||
return $this->getItem(self::SLOT_FEET);
|
||||
}
|
||||
|
||||
public function setHelmet(Item $helmet) : void{
|
||||
$this->setItem(self::SLOT_HEAD, $helmet);
|
||||
}
|
||||
|
||||
public function setChestplate(Item $chestplate) : void{
|
||||
$this->setItem(self::SLOT_CHEST, $chestplate);
|
||||
}
|
||||
|
||||
public function setLeggings(Item $leggings) : void{
|
||||
$this->setItem(self::SLOT_LEGS, $leggings);
|
||||
}
|
||||
|
||||
public function setBoots(Item $boots) : void{
|
||||
$this->setItem(self::SLOT_FEET, $boots);
|
||||
}
|
||||
}
|
391
src/inventory/BaseInventory.php
Normal file
391
src/inventory/BaseInventory.php
Normal file
@ -0,0 +1,391 @@
|
||||
<?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\item\ItemFactory;
|
||||
use pocketmine\player\Player;
|
||||
use function array_slice;
|
||||
use function count;
|
||||
use function max;
|
||||
use function min;
|
||||
use function spl_object_id;
|
||||
|
||||
abstract class BaseInventory implements Inventory{
|
||||
|
||||
/** @var int */
|
||||
protected $maxStackSize = Inventory::MAX_STACK;
|
||||
/** @var \SplFixedArray|Item[] */
|
||||
protected $slots = [];
|
||||
/** @var Player[] */
|
||||
protected $viewers = [];
|
||||
/** @var InventoryChangeListener[] */
|
||||
protected $listeners = [];
|
||||
|
||||
/**
|
||||
* @param int $size
|
||||
*/
|
||||
public function __construct(int $size){
|
||||
$this->slots = new \SplFixedArray($size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the inventory.
|
||||
* @return int
|
||||
*/
|
||||
public function getSize() : int{
|
||||
return $this->slots->getSize();
|
||||
}
|
||||
|
||||
public function getMaxStackSize() : int{
|
||||
return $this->maxStackSize;
|
||||
}
|
||||
|
||||
public function getItem(int $index) : Item{
|
||||
return $this->slots[$index] !== null ? clone $this->slots[$index] : ItemFactory::air();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $includeEmpty
|
||||
*
|
||||
* @return Item[]
|
||||
*/
|
||||
public function getContents(bool $includeEmpty = false) : array{
|
||||
$contents = [];
|
||||
|
||||
foreach($this->slots as $i => $slot){
|
||||
if($slot !== null){
|
||||
$contents[$i] = clone $slot;
|
||||
}elseif($includeEmpty){
|
||||
$contents[$i] = ItemFactory::air();
|
||||
}
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Item[] $items
|
||||
* @param bool $send
|
||||
*/
|
||||
public function setContents(array $items, bool $send = true) : void{
|
||||
if(count($items) > $this->getSize()){
|
||||
$items = array_slice($items, 0, $this->getSize(), true);
|
||||
}
|
||||
|
||||
$listeners = $this->listeners;
|
||||
$this->listeners = [];
|
||||
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
|
||||
if(!isset($items[$i])){
|
||||
$this->clear($i, false);
|
||||
}else{
|
||||
$this->setItem($i, $items[$i], false);
|
||||
}
|
||||
}
|
||||
|
||||
$this->addChangeListeners(...$listeners); //don't directly write, in case listeners were added while operation was in progress
|
||||
|
||||
foreach($this->listeners as $listener){
|
||||
$listener->onContentChange($this);
|
||||
}
|
||||
|
||||
if($send){
|
||||
foreach($this->getViewers() as $viewer){
|
||||
$viewer->getNetworkSession()->getInvManager()->syncContents($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setItem(int $index, Item $item, bool $send = true) : void{
|
||||
if($item->isNull()){
|
||||
$item = ItemFactory::air();
|
||||
}else{
|
||||
$item = clone $item;
|
||||
}
|
||||
|
||||
$oldItem = $this->getItem($index);
|
||||
|
||||
$this->slots[$index] = $item->isNull() ? null : $item;
|
||||
$this->onSlotChange($index, $oldItem, $send);
|
||||
}
|
||||
|
||||
public function contains(Item $item) : bool{
|
||||
$count = max(1, $item->getCount());
|
||||
$checkDamage = !$item->hasAnyDamageValue();
|
||||
$checkTags = $item->hasNamedTag();
|
||||
foreach($this->getContents() as $i){
|
||||
if($item->equals($i, $checkDamage, $checkTags)){
|
||||
$count -= $i->getCount();
|
||||
if($count <= 0){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function all(Item $item) : array{
|
||||
$slots = [];
|
||||
$checkDamage = !$item->hasAnyDamageValue();
|
||||
$checkTags = $item->hasNamedTag();
|
||||
foreach($this->getContents() as $index => $i){
|
||||
if($item->equals($i, $checkDamage, $checkTags)){
|
||||
$slots[$index] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
return $slots;
|
||||
}
|
||||
|
||||
public function remove(Item $item) : void{
|
||||
$checkDamage = !$item->hasAnyDamageValue();
|
||||
$checkTags = $item->hasNamedTag();
|
||||
|
||||
foreach($this->getContents() as $index => $i){
|
||||
if($item->equals($i, $checkDamage, $checkTags)){
|
||||
$this->clear($index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function first(Item $item, bool $exact = false) : int{
|
||||
$count = $exact ? $item->getCount() : max(1, $item->getCount());
|
||||
$checkDamage = $exact || !$item->hasAnyDamageValue();
|
||||
$checkTags = $exact || $item->hasNamedTag();
|
||||
|
||||
foreach($this->getContents() as $index => $i){
|
||||
if($item->equals($i, $checkDamage, $checkTags) and ($i->getCount() === $count or (!$exact and $i->getCount() > $count))){
|
||||
return $index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function firstEmpty() : int{
|
||||
foreach($this->slots as $i => $slot){
|
||||
if($slot === null or $slot->isNull()){
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function isSlotEmpty(int $index) : bool{
|
||||
return $this->slots[$index] === null or $this->slots[$index]->isNull();
|
||||
}
|
||||
|
||||
public function canAddItem(Item $item) : bool{
|
||||
$item = clone $item;
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
|
||||
$slot = $this->getItem($i);
|
||||
if($item->equals($slot)){
|
||||
if(($diff = $slot->getMaxStackSize() - $slot->getCount()) > 0){
|
||||
$item->setCount($item->getCount() - $diff);
|
||||
}
|
||||
}elseif($slot->isNull()){
|
||||
$item->setCount($item->getCount() - $this->getMaxStackSize());
|
||||
}
|
||||
|
||||
if($item->getCount() <= 0){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addItem(Item ...$slots) : array{
|
||||
/** @var Item[] $itemSlots */
|
||||
/** @var Item[] $slots */
|
||||
$itemSlots = [];
|
||||
foreach($slots as $slot){
|
||||
if(!$slot->isNull()){
|
||||
$itemSlots[] = clone $slot;
|
||||
}
|
||||
}
|
||||
|
||||
$emptySlots = [];
|
||||
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
|
||||
$item = $this->getItem($i);
|
||||
if($item->isNull()){
|
||||
$emptySlots[] = $i;
|
||||
}
|
||||
|
||||
foreach($itemSlots as $index => $slot){
|
||||
if($slot->equals($item) and $item->getCount() < $item->getMaxStackSize()){
|
||||
$amount = min($item->getMaxStackSize() - $item->getCount(), $slot->getCount(), $this->getMaxStackSize());
|
||||
if($amount > 0){
|
||||
$slot->setCount($slot->getCount() - $amount);
|
||||
$item->setCount($item->getCount() + $amount);
|
||||
$this->setItem($i, $item);
|
||||
if($slot->getCount() <= 0){
|
||||
unset($itemSlots[$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(count($itemSlots) === 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(count($itemSlots) > 0 and count($emptySlots) > 0){
|
||||
foreach($emptySlots as $slotIndex){
|
||||
//This loop only gets the first item, then goes to the next empty slot
|
||||
foreach($itemSlots as $index => $slot){
|
||||
$amount = min($slot->getMaxStackSize(), $slot->getCount(), $this->getMaxStackSize());
|
||||
$slot->setCount($slot->getCount() - $amount);
|
||||
$item = clone $slot;
|
||||
$item->setCount($amount);
|
||||
$this->setItem($slotIndex, $item);
|
||||
if($slot->getCount() <= 0){
|
||||
unset($itemSlots[$index]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $itemSlots;
|
||||
}
|
||||
|
||||
public function removeItem(Item ...$slots) : array{
|
||||
/** @var Item[] $itemSlots */
|
||||
/** @var Item[] $slots */
|
||||
$itemSlots = [];
|
||||
foreach($slots as $slot){
|
||||
if(!$slot->isNull()){
|
||||
$itemSlots[] = clone $slot;
|
||||
}
|
||||
}
|
||||
|
||||
for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
|
||||
$item = $this->getItem($i);
|
||||
if($item->isNull()){
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach($itemSlots as $index => $slot){
|
||||
if($slot->equals($item, !$slot->hasAnyDamageValue(), $slot->hasNamedTag())){
|
||||
$amount = min($item->getCount(), $slot->getCount());
|
||||
$slot->setCount($slot->getCount() - $amount);
|
||||
$item->setCount($item->getCount() - $amount);
|
||||
$this->setItem($i, $item);
|
||||
if($slot->getCount() <= 0){
|
||||
unset($itemSlots[$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(count($itemSlots) === 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $itemSlots;
|
||||
}
|
||||
|
||||
public function clear(int $index, bool $send = true) : void{
|
||||
$this->setItem($index, ItemFactory::air(), $send);
|
||||
}
|
||||
|
||||
public function clearAll(bool $send = true) : void{
|
||||
$this->setContents([], $send);
|
||||
}
|
||||
|
||||
public function swap(int $slot1, int $slot2) : void{
|
||||
$i1 = $this->getItem($slot1);
|
||||
$i2 = $this->getItem($slot2);
|
||||
$this->setItem($slot1, $i2);
|
||||
$this->setItem($slot2, $i1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Player[]
|
||||
*/
|
||||
public function getViewers() : array{
|
||||
return $this->viewers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the inventory window from all players currently viewing it.
|
||||
*/
|
||||
public function removeAllViewers() : void{
|
||||
foreach($this->viewers as $hash => $viewer){
|
||||
if($viewer->getCurrentWindow() === $this){ //this might not be the case for the player's own inventory
|
||||
$viewer->removeCurrentWindow();
|
||||
}
|
||||
unset($this->viewers[$hash]);
|
||||
}
|
||||
}
|
||||
|
||||
public function setMaxStackSize(int $size) : void{
|
||||
$this->maxStackSize = $size;
|
||||
}
|
||||
|
||||
public function onOpen(Player $who) : void{
|
||||
$this->viewers[spl_object_id($who)] = $who;
|
||||
}
|
||||
|
||||
public function onClose(Player $who) : void{
|
||||
unset($this->viewers[spl_object_id($who)]);
|
||||
}
|
||||
|
||||
protected function onSlotChange(int $index, Item $before, bool $send) : void{
|
||||
foreach($this->listeners as $listener){
|
||||
$listener->onSlotChange($this, $index);
|
||||
}
|
||||
if($send){
|
||||
foreach($this->viewers as $viewer){
|
||||
$viewer->getNetworkSession()->getInvManager()->syncSlot($this, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function slotExists(int $slot) : bool{
|
||||
return $slot >= 0 and $slot < $this->slots->getSize();
|
||||
}
|
||||
|
||||
public function addChangeListeners(InventoryChangeListener ...$listeners) : void{
|
||||
foreach($listeners as $listener){
|
||||
$this->listeners[spl_object_id($listener)] = $listener;
|
||||
}
|
||||
}
|
||||
|
||||
public function removeChangeListeners(InventoryChangeListener ...$listeners) : void{
|
||||
foreach($listeners as $listener){
|
||||
unset($this->listeners[spl_object_id($listener)]);
|
||||
}
|
||||
}
|
||||
|
||||
public function getChangeListeners() : array{
|
||||
return $this->listeners;
|
||||
}
|
||||
}
|
43
src/inventory/BlockInventory.php
Normal file
43
src/inventory/BlockInventory.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?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\math\Vector3;
|
||||
|
||||
class BlockInventory extends BaseInventory{
|
||||
/** @var Vector3 */
|
||||
protected $holder;
|
||||
|
||||
public function __construct(Vector3 $holder, int $size){
|
||||
$this->holder = $holder;
|
||||
parent::__construct($size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vector3
|
||||
*/
|
||||
public function getHolder(){
|
||||
return $this->holder;
|
||||
}
|
||||
}
|
33
src/inventory/BrewingStandInventory.php
Normal file
33
src/inventory/BrewingStandInventory.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?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\math\Vector3;
|
||||
|
||||
class BrewingStandInventory extends BlockInventory{
|
||||
|
||||
public function __construct(Vector3 $holder, int $size = 5){
|
||||
parent::__construct($holder, $size);
|
||||
}
|
||||
}
|
65
src/inventory/CallbackInventoryChangeListener.php
Normal file
65
src/inventory/CallbackInventoryChangeListener.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?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\utils\Utils;
|
||||
|
||||
class CallbackInventoryChangeListener implements InventoryChangeListener{
|
||||
|
||||
/** @var \Closure|null */
|
||||
private $onSlotChangeCallback;
|
||||
/** @var \Closure|null */
|
||||
private $onContentChangeCallback;
|
||||
|
||||
public function __construct(?\Closure $onSlotChange, ?\Closure $onContentChange){
|
||||
if($onSlotChange !== null){
|
||||
Utils::validateCallableSignature(function(Inventory $inventory, int $slot){}, $onSlotChange);
|
||||
}
|
||||
if($onContentChange !== null){
|
||||
Utils::validateCallableSignature(function(Inventory $inventory){}, $onContentChange);
|
||||
}
|
||||
|
||||
$this->onSlotChangeCallback = $onSlotChange;
|
||||
$this->onContentChangeCallback = $onContentChange;
|
||||
}
|
||||
|
||||
public static function onAnyChange(\Closure $onChange) : self{
|
||||
return new self(
|
||||
static function(Inventory $inventory, int $unused) use ($onChange) : void{
|
||||
$onChange($inventory);
|
||||
},
|
||||
static function(Inventory $inventory) use ($onChange) : void{
|
||||
$onChange($inventory);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function onSlotChange(Inventory $inventory, int $slot) : void{
|
||||
($this->onSlotChangeCallback)($inventory, $slot);
|
||||
}
|
||||
|
||||
public function onContentChange(Inventory $inventory) : void{
|
||||
($this->onContentChangeCallback)($inventory);
|
||||
}
|
||||
}
|
87
src/inventory/ChestInventory.php
Normal file
87
src/inventory/ChestInventory.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?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\block\tile\Chest;
|
||||
use pocketmine\network\mcpe\protocol\BlockEventPacket;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\ChestCloseSound;
|
||||
use pocketmine\world\sound\ChestOpenSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
use function count;
|
||||
|
||||
class ChestInventory extends BlockInventory{
|
||||
|
||||
/** @var Chest */
|
||||
protected $holder;
|
||||
|
||||
/**
|
||||
* @param Chest $tile
|
||||
*/
|
||||
public function __construct(Chest $tile){
|
||||
parent::__construct($tile, 27);
|
||||
}
|
||||
|
||||
/**
|
||||
* This override is here for documentation and code completion purposes only.
|
||||
* @return Chest
|
||||
*/
|
||||
public function getHolder(){
|
||||
return $this->holder;
|
||||
}
|
||||
|
||||
protected function getOpenSound() : Sound{
|
||||
return new ChestOpenSound();
|
||||
}
|
||||
|
||||
protected function getCloseSound() : Sound{
|
||||
return new ChestCloseSound();
|
||||
}
|
||||
|
||||
public function onOpen(Player $who) : void{
|
||||
parent::onOpen($who);
|
||||
|
||||
if(count($this->getViewers()) === 1 and $this->getHolder()->isValid()){
|
||||
//TODO: this crap really shouldn't be managed by the inventory
|
||||
$this->broadcastBlockEventPacket(true);
|
||||
$this->getHolder()->getWorld()->addSound($this->getHolder()->add(0.5, 0.5, 0.5), $this->getOpenSound());
|
||||
}
|
||||
}
|
||||
|
||||
public function onClose(Player $who) : void{
|
||||
if(count($this->getViewers()) === 1 and $this->getHolder()->isValid()){
|
||||
//TODO: this crap really shouldn't be managed by the inventory
|
||||
$this->broadcastBlockEventPacket(false);
|
||||
$this->getHolder()->getWorld()->addSound($this->getHolder()->add(0.5, 0.5, 0.5), $this->getCloseSound());
|
||||
}
|
||||
parent::onClose($who);
|
||||
}
|
||||
|
||||
protected function broadcastBlockEventPacket(bool $isOpen) : void{
|
||||
$holder = $this->getHolder();
|
||||
|
||||
//event ID is always 1 for a chest
|
||||
$holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(1, $isOpen ? 1 : 0, $holder->asVector3()));
|
||||
}
|
||||
}
|
99
src/inventory/CreativeInventory.php
Normal file
99
src/inventory/CreativeInventory.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?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\Durable;
|
||||
use pocketmine\item\Item;
|
||||
use function file_get_contents;
|
||||
use function json_decode;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
final class CreativeInventory{
|
||||
|
||||
/** @var Item[] */
|
||||
public static $creative = [];
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
public static function init(){
|
||||
self::clear();
|
||||
|
||||
$creativeItems = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla" . DIRECTORY_SEPARATOR . "creativeitems.json"), true);
|
||||
|
||||
foreach($creativeItems as $data){
|
||||
$item = Item::jsonDeserialize($data);
|
||||
if($item->getName() === "Unknown"){
|
||||
continue;
|
||||
}
|
||||
self::add($item);
|
||||
}
|
||||
}
|
||||
|
||||
public static function clear(){
|
||||
self::$creative = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item[]
|
||||
*/
|
||||
public static function getAll() : array{
|
||||
return self::$creative;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return Item|null
|
||||
*/
|
||||
public static function getItem(int $index) : ?Item{
|
||||
return self::$creative[$index] ?? null;
|
||||
}
|
||||
|
||||
public static function getItemIndex(Item $item) : int{
|
||||
foreach(self::$creative as $i => $d){
|
||||
if($item->equals($d, !($item instanceof Durable))){
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static function add(Item $item){
|
||||
self::$creative[] = clone $item;
|
||||
}
|
||||
|
||||
public static function remove(Item $item){
|
||||
$index = self::getItemIndex($item);
|
||||
if($index !== -1){
|
||||
unset(self::$creative[$index]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function contains(Item $item) : bool{
|
||||
return self::getItemIndex($item) !== -1;
|
||||
}
|
||||
}
|
108
src/inventory/DoubleChestInventory.php
Normal file
108
src/inventory/DoubleChestInventory.php
Normal file
@ -0,0 +1,108 @@
|
||||
<?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\block\tile\Chest;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\player\Player;
|
||||
use function count;
|
||||
|
||||
class DoubleChestInventory extends ChestInventory implements InventoryHolder{
|
||||
/** @var ChestInventory */
|
||||
private $left;
|
||||
/** @var ChestInventory */
|
||||
private $right;
|
||||
|
||||
public function __construct(Chest $left, Chest $right){
|
||||
$this->left = $left->getRealInventory();
|
||||
$this->right = $right->getRealInventory();
|
||||
BaseInventory::__construct($this->left->getSize() + $this->right->getSize());
|
||||
}
|
||||
|
||||
public function getInventory(){
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Chest
|
||||
*/
|
||||
public function getHolder(){
|
||||
return $this->left->getHolder();
|
||||
}
|
||||
|
||||
public function getItem(int $index) : Item{
|
||||
return $index < $this->left->getSize() ? $this->left->getItem($index) : $this->right->getItem($index - $this->left->getSize());
|
||||
}
|
||||
|
||||
public function setItem(int $index, Item $item, bool $send = true) : void{
|
||||
$old = $this->getItem($index);
|
||||
$index < $this->left->getSize() ? $this->left->setItem($index, $item, $send) : $this->right->setItem($index - $this->left->getSize(), $item, $send);
|
||||
$this->onSlotChange($index, $old, $send);
|
||||
}
|
||||
|
||||
public function getContents(bool $includeEmpty = false) : array{
|
||||
$result = $this->left->getContents($includeEmpty);
|
||||
$leftSize = $this->left->getSize();
|
||||
|
||||
foreach($this->right->getContents($includeEmpty) as $i => $item){
|
||||
$result[$i + $leftSize] = $item;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function onOpen(Player $who) : void{
|
||||
parent::onOpen($who);
|
||||
|
||||
if(count($this->getViewers()) === 1 and $this->right->getHolder()->isValid()){
|
||||
$this->right->broadcastBlockEventPacket(true);
|
||||
}
|
||||
}
|
||||
|
||||
public function onClose(Player $who) : void{
|
||||
if(count($this->getViewers()) === 1 and $this->right->getHolder()->isValid()){
|
||||
$this->right->broadcastBlockEventPacket(false);
|
||||
}
|
||||
parent::onClose($who);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChestInventory
|
||||
*/
|
||||
public function getLeftSide() : ChestInventory{
|
||||
return $this->left;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChestInventory
|
||||
*/
|
||||
public function getRightSide() : ChestInventory{
|
||||
return $this->right;
|
||||
}
|
||||
|
||||
public function invalidate(){
|
||||
$this->left = null;
|
||||
$this->right = null;
|
||||
}
|
||||
}
|
54
src/inventory/EnchantInventory.php
Normal file
54
src/inventory/EnchantInventory.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?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\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class EnchantInventory extends BlockInventory{
|
||||
|
||||
/** @var Position */
|
||||
protected $holder;
|
||||
|
||||
public function __construct(Position $pos){
|
||||
parent::__construct($pos->asPosition(), 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* This override is here for documentation and code completion purposes only.
|
||||
* @return Position
|
||||
*/
|
||||
public function getHolder(){
|
||||
return $this->holder;
|
||||
}
|
||||
|
||||
public function onClose(Player $who) : void{
|
||||
parent::onClose($who);
|
||||
|
||||
foreach($this->getContents() as $item){
|
||||
$who->dropItem($item);
|
||||
}
|
||||
$this->clearAll();
|
||||
}
|
||||
}
|
66
src/inventory/EnderChestInventory.php
Normal file
66
src/inventory/EnderChestInventory.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?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\block\tile\EnderChest;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\sound\EnderChestCloseSound;
|
||||
use pocketmine\world\sound\EnderChestOpenSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
|
||||
class EnderChestInventory extends ChestInventory{
|
||||
|
||||
/** @var Position */
|
||||
protected $holder;
|
||||
|
||||
public function __construct(){
|
||||
BlockInventory::__construct(new Position(), 27);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the holder's position to that of a tile
|
||||
*
|
||||
* @param EnderChest $enderChest
|
||||
*/
|
||||
public function setHolderPosition(EnderChest $enderChest) : void{
|
||||
$this->holder->setComponents($enderChest->getFloorX(), $enderChest->getFloorY(), $enderChest->getFloorZ());
|
||||
$this->holder->setWorld($enderChest->getWorld());
|
||||
}
|
||||
|
||||
protected function getOpenSound() : Sound{
|
||||
return new EnderChestOpenSound();
|
||||
}
|
||||
|
||||
protected function getCloseSound() : Sound{
|
||||
return new EnderChestCloseSound();
|
||||
}
|
||||
|
||||
/**
|
||||
* This override is here for documentation and code completion purposes only.
|
||||
* @return Position
|
||||
*/
|
||||
public function getHolder(){
|
||||
return $this->holder;
|
||||
}
|
||||
}
|
86
src/inventory/FurnaceInventory.php
Normal file
86
src/inventory/FurnaceInventory.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?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\block\tile\Furnace;
|
||||
use pocketmine\item\Item;
|
||||
|
||||
class FurnaceInventory extends BlockInventory{
|
||||
/** @var Furnace */
|
||||
protected $holder;
|
||||
|
||||
public function __construct(Furnace $tile){
|
||||
parent::__construct($tile, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* This override is here for documentation and code completion purposes only.
|
||||
* @return Furnace
|
||||
*/
|
||||
public function getHolder(){
|
||||
return $this->holder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item
|
||||
*/
|
||||
public function getResult() : Item{
|
||||
return $this->getItem(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item
|
||||
*/
|
||||
public function getFuel() : Item{
|
||||
return $this->getItem(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Item
|
||||
*/
|
||||
public function getSmelting() : Item{
|
||||
return $this->getItem(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Item $item
|
||||
*/
|
||||
public function setResult(Item $item) : void{
|
||||
$this->setItem(2, $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Item $item
|
||||
*/
|
||||
public function setFuel(Item $item) : void{
|
||||
$this->setItem(1, $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Item $item
|
||||
*/
|
||||
public function setSmelting(Item $item) : void{
|
||||
$this->setItem(0, $item);
|
||||
}
|
||||
}
|
33
src/inventory/HopperInventory.php
Normal file
33
src/inventory/HopperInventory.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?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\math\Vector3;
|
||||
|
||||
class HopperInventory extends BlockInventory{
|
||||
|
||||
public function __construct(Vector3 $holder, int $size = 5){
|
||||
parent::__construct($holder, $size);
|
||||
}
|
||||
}
|
229
src/inventory/Inventory.php
Normal file
229
src/inventory/Inventory.php
Normal file
@ -0,0 +1,229 @@
|
||||
<?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);
|
||||
|
||||
/**
|
||||
* Handles the creation of virtual inventories or mapped to an InventoryHolder
|
||||
*/
|
||||
namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
interface Inventory{
|
||||
public const MAX_STACK = 64;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getSize() : int;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMaxStackSize() : int;
|
||||
|
||||
/**
|
||||
* @param int $size
|
||||
*/
|
||||
public function setMaxStackSize(int $size) : void;
|
||||
|
||||
/**
|
||||
* @param int $index
|
||||
*
|
||||
* @return Item
|
||||
*/
|
||||
public function getItem(int $index) : Item;
|
||||
|
||||
/**
|
||||
* Puts an Item in a slot.
|
||||
*
|
||||
* @param int $index
|
||||
* @param Item $item
|
||||
* @param bool $send
|
||||
*/
|
||||
public function setItem(int $index, Item $item, bool $send = true) : void;
|
||||
|
||||
/**
|
||||
* Stores the given Items in the inventory. This will try to fill
|
||||
* existing stacks and empty slots as well as it can.
|
||||
*
|
||||
* Returns the Items that did not fit.
|
||||
*
|
||||
* @param Item ...$slots
|
||||
*
|
||||
* @return Item[]
|
||||
*/
|
||||
public function addItem(Item ...$slots) : array;
|
||||
|
||||
/**
|
||||
* Checks if a given Item can be added to the inventory
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAddItem(Item $item) : bool;
|
||||
|
||||
/**
|
||||
* Removes the given Item from the inventory.
|
||||
* It will return the Items that couldn't be removed.
|
||||
*
|
||||
* @param Item ...$slots
|
||||
*
|
||||
* @return Item[]
|
||||
*/
|
||||
public function removeItem(Item ...$slots) : array;
|
||||
|
||||
/**
|
||||
* @param bool $includeEmpty
|
||||
*
|
||||
* @return Item[]
|
||||
*/
|
||||
public function getContents(bool $includeEmpty = false) : array;
|
||||
|
||||
/**
|
||||
* @param Item[] $items
|
||||
* @param bool $send
|
||||
*/
|
||||
public function setContents(array $items, bool $send = true) : void;
|
||||
|
||||
/**
|
||||
* Checks if the inventory contains any Item with the same material data.
|
||||
* It will check id, amount, and metadata (if not null)
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function contains(Item $item) : bool;
|
||||
|
||||
/**
|
||||
* Will return all the Items that has the same id and metadata (if not null).
|
||||
* Won't check amount
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return Item[]
|
||||
*/
|
||||
public function all(Item $item) : array;
|
||||
|
||||
/**
|
||||
* Returns the first slot number containing an item with the same ID, damage (if not any-damage), NBT (if not empty)
|
||||
* and count >= to the count of the specified item stack.
|
||||
*
|
||||
* If $exact is true, only items with equal ID, damage, NBT and count will match.
|
||||
*
|
||||
* @param Item $item
|
||||
* @param bool $exact
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function first(Item $item, bool $exact = false) : int;
|
||||
|
||||
/**
|
||||
* Returns the first empty slot, or -1 if not found
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function firstEmpty() : int;
|
||||
|
||||
/**
|
||||
* Returns whether the given slot is empty.
|
||||
*
|
||||
* @param int $index
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSlotEmpty(int $index) : bool;
|
||||
|
||||
/**
|
||||
* Will remove all the Items that has the same id and metadata (if not null)
|
||||
*
|
||||
* @param Item $item
|
||||
*/
|
||||
public function remove(Item $item) : void;
|
||||
|
||||
/**
|
||||
* Will clear a specific slot
|
||||
*
|
||||
* @param int $index
|
||||
* @param bool $send
|
||||
*/
|
||||
public function clear(int $index, bool $send = true) : void;
|
||||
|
||||
/**
|
||||
* Clears all the slots
|
||||
*
|
||||
* @param bool $send
|
||||
*/
|
||||
public function clearAll(bool $send = true) : void;
|
||||
|
||||
/**
|
||||
* Swaps the specified slots.
|
||||
*
|
||||
* @param int $slot1
|
||||
* @param int $slot2
|
||||
*/
|
||||
public function swap(int $slot1, int $slot2) : void;
|
||||
|
||||
/**
|
||||
* Gets all the Players viewing the inventory
|
||||
* Players will view their inventory at all times, even when not open.
|
||||
*
|
||||
* @return Player[]
|
||||
*/
|
||||
public function getViewers() : array;
|
||||
|
||||
/**
|
||||
* Called when a player opens this inventory.
|
||||
*
|
||||
* @param Player $who
|
||||
*/
|
||||
public function onOpen(Player $who) : void;
|
||||
|
||||
public function onClose(Player $who) : void;
|
||||
|
||||
/**
|
||||
* Returns whether the specified slot exists in the inventory.
|
||||
*
|
||||
* @param int $slot
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function slotExists(int $slot) : bool;
|
||||
|
||||
/**
|
||||
* @param InventoryChangeListener ...$listeners
|
||||
*/
|
||||
public function addChangeListeners(InventoryChangeListener ...$listeners) : void;
|
||||
|
||||
/**
|
||||
* @param InventoryChangeListener ...$listeners
|
||||
*/
|
||||
public function removeChangeListeners(InventoryChangeListener ...$listeners) : void;
|
||||
|
||||
/**
|
||||
* @return InventoryChangeListener[]
|
||||
*/
|
||||
public function getChangeListeners() : array;
|
||||
}
|
38
src/inventory/InventoryChangeListener.php
Normal file
38
src/inventory/InventoryChangeListener.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;
|
||||
|
||||
/**
|
||||
* Classes implementing this interface can be injected into inventories to receive notifications when content changes
|
||||
* occur.
|
||||
* @see CallbackInventoryChangeListener for a closure-based listener
|
||||
* @see Inventory::addChangeListeners()
|
||||
* @see Inventory::removeChangeListeners()
|
||||
*/
|
||||
interface InventoryChangeListener{
|
||||
|
||||
public function onSlotChange(Inventory $inventory, int $slot) : void;
|
||||
|
||||
public function onContentChange(Inventory $inventory) : void;
|
||||
}
|
34
src/inventory/InventoryHolder.php
Normal file
34
src/inventory/InventoryHolder.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?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;
|
||||
|
||||
interface InventoryHolder{
|
||||
|
||||
/**
|
||||
* Get the object related inventory
|
||||
*
|
||||
* @return Inventory
|
||||
*/
|
||||
public function getInventory();
|
||||
}
|
44
src/inventory/PlayerCursorInventory.php
Normal file
44
src/inventory/PlayerCursorInventory.php
Normal file
@ -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;
|
||||
|
||||
use pocketmine\player\Player;
|
||||
|
||||
class PlayerCursorInventory extends BaseInventory{
|
||||
/** @var Player */
|
||||
protected $holder;
|
||||
|
||||
public function __construct(Player $holder){
|
||||
$this->holder = $holder;
|
||||
parent::__construct(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* This override is here for documentation and code completion purposes only.
|
||||
* @return Player
|
||||
*/
|
||||
public function getHolder(){
|
||||
return $this->holder;
|
||||
}
|
||||
}
|
141
src/inventory/PlayerInventory.php
Normal file
141
src/inventory/PlayerInventory.php
Normal file
@ -0,0 +1,141 @@
|
||||
<?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\entity\Human;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
class PlayerInventory extends BaseInventory{
|
||||
|
||||
/** @var Human */
|
||||
protected $holder;
|
||||
|
||||
/** @var int */
|
||||
protected $itemInHandIndex = 0;
|
||||
|
||||
/**
|
||||
* @param Human $player
|
||||
*/
|
||||
public function __construct(Human $player){
|
||||
$this->holder = $player;
|
||||
parent::__construct(36);
|
||||
}
|
||||
|
||||
public function isHotbarSlot(int $slot) : bool{
|
||||
return $slot >= 0 and $slot <= $this->getHotbarSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $slot
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function throwIfNotHotbarSlot(int $slot) : void{
|
||||
if(!$this->isHotbarSlot($slot)){
|
||||
throw new \InvalidArgumentException("$slot is not a valid hotbar slot index (expected 0 - " . ($this->getHotbarSize() - 1) . ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item in the specified hotbar slot.
|
||||
*
|
||||
* @param int $hotbarSlot
|
||||
*
|
||||
* @return Item
|
||||
*
|
||||
* @throws \InvalidArgumentException if the hotbar slot index is out of range
|
||||
*/
|
||||
public function getHotbarSlotItem(int $hotbarSlot) : Item{
|
||||
$this->throwIfNotHotbarSlot($hotbarSlot);
|
||||
return $this->getItem($hotbarSlot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hotbar slot number the holder is currently holding.
|
||||
* @return int
|
||||
*/
|
||||
public function getHeldItemIndex() : int{
|
||||
return $this->itemInHandIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets which hotbar slot the player is currently loading.
|
||||
*
|
||||
* @param int $hotbarSlot 0-8 index of the hotbar slot to hold
|
||||
* @param bool $send Whether to send updates back to the inventory holder. This should usually be true for plugin calls.
|
||||
* It should only be false to prevent feedback loops of equipment packets between client and server.
|
||||
*
|
||||
* @throws \InvalidArgumentException if the hotbar slot is out of range
|
||||
*/
|
||||
public function setHeldItemIndex(int $hotbarSlot, bool $send = true) : void{
|
||||
$this->throwIfNotHotbarSlot($hotbarSlot);
|
||||
|
||||
$this->itemInHandIndex = $hotbarSlot;
|
||||
|
||||
if($this->holder instanceof Player and $send){
|
||||
$this->holder->getNetworkSession()->getInvManager()->syncSelectedHotbarSlot();
|
||||
}
|
||||
foreach($this->holder->getViewers() as $viewer){
|
||||
$viewer->getNetworkSession()->onMobEquipmentChange($this->holder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently-held item.
|
||||
*
|
||||
* @return Item
|
||||
*/
|
||||
public function getItemInHand() : Item{
|
||||
return $this->getHotbarSlotItem($this->itemInHandIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the item in the currently-held slot to the specified item.
|
||||
*
|
||||
* @param Item $item
|
||||
*/
|
||||
public function setItemInHand(Item $item) : void{
|
||||
$this->setItem($this->getHeldItemIndex(), $item);
|
||||
foreach($this->holder->getViewers() as $viewer){
|
||||
$viewer->getNetworkSession()->onMobEquipmentChange($this->holder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of slots in the hotbar.
|
||||
* @return int
|
||||
*/
|
||||
public function getHotbarSize() : int{
|
||||
return 9;
|
||||
}
|
||||
|
||||
/**
|
||||
* This override is here for documentation and code completion purposes only.
|
||||
* @return Human|Player
|
||||
*/
|
||||
public function getHolder(){
|
||||
return $this->holder;
|
||||
}
|
||||
}
|
172
src/inventory/transaction/CraftingTransaction.php
Normal file
172
src/inventory/transaction/CraftingTransaction.php
Normal 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));
|
||||
}
|
||||
}
|
338
src/inventory/transaction/InventoryTransaction.php
Normal file
338
src/inventory/transaction/InventoryTransaction.php
Normal 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;
|
||||
}
|
||||
}
|
28
src/inventory/transaction/TransactionValidationException.php
Normal file
28
src/inventory/transaction/TransactionValidationException.php
Normal 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{
|
||||
|
||||
}
|
48
src/inventory/transaction/action/CreateItemAction.php
Normal file
48
src/inventory/transaction/action/CreateItemAction.php
Normal 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
|
||||
}
|
||||
}
|
47
src/inventory/transaction/action/DestroyItemAction.php
Normal file
47
src/inventory/transaction/action/DestroyItemAction.php
Normal 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
|
||||
}
|
||||
}
|
62
src/inventory/transaction/action/DropItemAction.php
Normal file
62
src/inventory/transaction/action/DropItemAction.php
Normal 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);
|
||||
}
|
||||
}
|
97
src/inventory/transaction/action/InventoryAction.php
Normal file
97
src/inventory/transaction/action/InventoryAction.php
Normal 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;
|
||||
}
|
107
src/inventory/transaction/action/SlotChangeAction.php
Normal file
107
src/inventory/transaction/action/SlotChangeAction.php
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user