mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-12 16:59:44 +00:00
work on moving inventory network functionality to network layer
This commit is contained in:
parent
9f09dc3dd7
commit
d15284e638
@ -203,17 +203,17 @@ class Furnace extends Spawnable implements Container, Nameable{
|
||||
|
||||
if($prevCookTime !== $this->cookTime){
|
||||
foreach($this->inventory->getViewers() as $v){
|
||||
$v->getNetworkSession()->syncInventoryData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_SMELT_PROGRESS, $this->cookTime);
|
||||
$v->getNetworkSession()->getInvManager()->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_SMELT_PROGRESS, $this->cookTime);
|
||||
}
|
||||
}
|
||||
if($prevRemainingFuelTime !== $this->remainingFuelTime){
|
||||
foreach($this->inventory->getViewers() as $v){
|
||||
$v->getNetworkSession()->syncInventoryData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_REMAINING_FUEL_TIME, $this->remainingFuelTime);
|
||||
$v->getNetworkSession()->getInvManager()->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_REMAINING_FUEL_TIME, $this->remainingFuelTime);
|
||||
}
|
||||
}
|
||||
if($prevMaxFuelTime !== $this->maxFuelTime){
|
||||
foreach($this->inventory->getViewers() as $v){
|
||||
$v->getNetworkSession()->syncInventoryData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_MAX_FUEL_TIME, $this->maxFuelTime);
|
||||
$v->getNetworkSession()->getInvManager()->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_FURNACE_MAX_FUEL_TIME, $this->maxFuelTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,11 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\network\mcpe\protocol\types\WindowTypes;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class AnvilInventory extends ContainerInventory{
|
||||
class AnvilInventory extends BlockInventory{
|
||||
|
||||
/** @var Position */
|
||||
protected $holder;
|
||||
@ -36,10 +35,6 @@ class AnvilInventory extends ContainerInventory{
|
||||
parent::__construct($pos->asPosition(), 2);
|
||||
}
|
||||
|
||||
public function getNetworkType() : int{
|
||||
return WindowTypes::ANVIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* This override is here for documentation and code completion purposes only.
|
||||
* @return Position
|
||||
|
@ -116,7 +116,7 @@ abstract class BaseInventory implements Inventory{
|
||||
|
||||
if($send){
|
||||
foreach($this->getViewers() as $viewer){
|
||||
$viewer->getNetworkSession()->syncInventoryContents($this);
|
||||
$viewer->getNetworkSession()->getInvManager()->syncContents($this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -367,7 +367,7 @@ abstract class BaseInventory implements Inventory{
|
||||
}
|
||||
if($send){
|
||||
foreach($this->viewers as $viewer){
|
||||
$viewer->getNetworkSession()->syncInventorySlot($this, $index);
|
||||
$viewer->getNetworkSession()->getInvManager()->syncSlot($this, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
src/pocketmine/inventory/BlockInventory.php
Normal file
43
src/pocketmine/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;
|
||||
|
||||
abstract class BlockInventory extends BaseInventory{
|
||||
/** @var Vector3 */
|
||||
protected $holder;
|
||||
|
||||
public function __construct(Vector3 $holder, int $size, array $items = []){
|
||||
$this->holder = $holder;
|
||||
parent::__construct($size, $items);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vector3
|
||||
*/
|
||||
public function getHolder(){
|
||||
return $this->holder;
|
||||
}
|
||||
}
|
@ -24,15 +24,10 @@ declare(strict_types=1);
|
||||
namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\types\WindowTypes;
|
||||
|
||||
class BrewingStandInventory extends ContainerInventory{
|
||||
class BrewingStandInventory extends BlockInventory{
|
||||
|
||||
public function __construct(Vector3 $holder, int $size = 5, array $items = []){
|
||||
parent::__construct($holder, $size, $items);
|
||||
}
|
||||
|
||||
public function getNetworkType() : int{
|
||||
return WindowTypes::BREWING_STAND;
|
||||
}
|
||||
}
|
||||
|
@ -25,14 +25,13 @@ namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\block\tile\Chest;
|
||||
use pocketmine\network\mcpe\protocol\BlockEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\WindowTypes;
|
||||
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 ContainerInventory{
|
||||
class ChestInventory extends BlockInventory{
|
||||
|
||||
/** @var Chest */
|
||||
protected $holder;
|
||||
@ -44,10 +43,6 @@ class ChestInventory extends ContainerInventory{
|
||||
parent::__construct($tile, 27);
|
||||
}
|
||||
|
||||
public function getNetworkType() : int{
|
||||
return WindowTypes::CONTAINER;
|
||||
}
|
||||
|
||||
/**
|
||||
* This override is here for documentation and code completion purposes only.
|
||||
* @return Chest
|
||||
|
@ -1,72 +0,0 @@
|
||||
<?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\Entity;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
|
||||
use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
abstract class ContainerInventory extends BaseInventory{
|
||||
/** @var Vector3 */
|
||||
protected $holder;
|
||||
|
||||
public function __construct(Vector3 $holder, int $size, array $items = []){
|
||||
$this->holder = $holder;
|
||||
parent::__construct($size, $items);
|
||||
}
|
||||
|
||||
public function onOpen(Player $who) : void{
|
||||
parent::onOpen($who);
|
||||
|
||||
$windowId = $who->getWindowId($this);
|
||||
$holder = $this->getHolder();
|
||||
if($holder instanceof Entity){
|
||||
$who->sendDataPacket(ContainerOpenPacket::entityInv($windowId, $this->getNetworkType(), $holder->getId()));
|
||||
}elseif($holder instanceof Vector3){
|
||||
$who->sendDataPacket(ContainerOpenPacket::blockInv($windowId, $this->getNetworkType(), $holder->getFloorX(), $holder->getFloorY(), $holder->getFloorZ()));
|
||||
}
|
||||
|
||||
$who->getNetworkSession()->syncInventoryContents($this);
|
||||
}
|
||||
|
||||
public function onClose(Player $who) : void{
|
||||
$who->sendDataPacket(ContainerClosePacket::create($who->getWindowId($this)));
|
||||
parent::onClose($who);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Minecraft PE inventory type used to show the inventory window to clients.
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getNetworkType() : int;
|
||||
|
||||
/**
|
||||
* @return Vector3
|
||||
*/
|
||||
public function getHolder(){
|
||||
return $this->holder;
|
||||
}
|
||||
}
|
@ -23,11 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\network\mcpe\protocol\types\WindowTypes;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class EnchantInventory extends ContainerInventory{
|
||||
class EnchantInventory extends BlockInventory{
|
||||
|
||||
/** @var Position */
|
||||
protected $holder;
|
||||
@ -36,10 +35,6 @@ class EnchantInventory extends ContainerInventory{
|
||||
parent::__construct($pos->asPosition(), 2);
|
||||
}
|
||||
|
||||
public function getNetworkType() : int{
|
||||
return WindowTypes::ENCHANTMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* This override is here for documentation and code completion purposes only.
|
||||
* @return Position
|
||||
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
||||
namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\block\tile\EnderChest;
|
||||
use pocketmine\network\mcpe\protocol\types\WindowTypes;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\sound\EnderChestCloseSound;
|
||||
use pocketmine\world\sound\EnderChestOpenSound;
|
||||
@ -36,11 +35,7 @@ class EnderChestInventory extends ChestInventory{
|
||||
protected $holder;
|
||||
|
||||
public function __construct(){
|
||||
ContainerInventory::__construct(new Position(), 27);
|
||||
}
|
||||
|
||||
public function getNetworkType() : int{
|
||||
return WindowTypes::CONTAINER;
|
||||
BlockInventory::__construct(new Position(), 27);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,9 +25,8 @@ namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\block\tile\Furnace;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\network\mcpe\protocol\types\WindowTypes;
|
||||
|
||||
class FurnaceInventory extends ContainerInventory{
|
||||
class FurnaceInventory extends BlockInventory{
|
||||
/** @var Furnace */
|
||||
protected $holder;
|
||||
|
||||
@ -35,10 +34,6 @@ class FurnaceInventory extends ContainerInventory{
|
||||
parent::__construct($tile, 3);
|
||||
}
|
||||
|
||||
public function getNetworkType() : int{
|
||||
return WindowTypes::FURNACE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This override is here for documentation and code completion purposes only.
|
||||
* @return Furnace
|
||||
|
@ -24,15 +24,10 @@ declare(strict_types=1);
|
||||
namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\protocol\types\WindowTypes;
|
||||
|
||||
class HopperInventory extends ContainerInventory{
|
||||
class HopperInventory extends BlockInventory{
|
||||
|
||||
public function __construct(Vector3 $holder, int $size = 5, array $items = []){
|
||||
parent::__construct($holder, $size, $items);
|
||||
}
|
||||
|
||||
public function getNetworkType() : int{
|
||||
return WindowTypes::HOPPER;
|
||||
}
|
||||
}
|
||||
|
@ -137,12 +137,12 @@ class PlayerInventory extends BaseInventory{
|
||||
if(!is_array($target)){
|
||||
$target->sendDataPacket($pk);
|
||||
if($target === $this->getHolder()){
|
||||
$target->getNetworkSession()->syncInventorySlot($this, $this->getHeldItemIndex());
|
||||
$target->getNetworkSession()->getInvManager()->syncSlot($this, $this->getHeldItemIndex());
|
||||
}
|
||||
}else{
|
||||
$this->getHolder()->getWorld()->getServer()->broadcastPacket($target, $pk);
|
||||
if(in_array($this->getHolder(), $target, true)){
|
||||
$target->getNetworkSession()->syncInventorySlot($this, $this->getHeldItemIndex());
|
||||
$target->getNetworkSession()->getInvManager()->syncSlot($this, $this->getHeldItemIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -282,7 +282,7 @@ class InventoryTransaction{
|
||||
|
||||
protected function sendInventories() : void{
|
||||
foreach($this->inventories as $inventory){
|
||||
$this->source->getNetworkSession()->syncInventoryContents($inventory);
|
||||
$this->source->getNetworkSession()->getInvManager()->syncContents($inventory);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ class SlotChangeAction extends InventoryAction{
|
||||
$this->inventory->setItem($this->inventorySlot, $this->targetItem, false);
|
||||
foreach($this->inventory->getViewers() as $viewer){
|
||||
if($viewer !== $source){
|
||||
$viewer->getNetworkSession()->syncInventorySlot($this->inventory, $this->inventorySlot);
|
||||
$viewer->getNetworkSession()->getInvManager()->syncSlot($this->inventory, $this->inventorySlot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
157
src/pocketmine/network/mcpe/InventoryManager.php
Normal file
157
src/pocketmine/network/mcpe/InventoryManager.php
Normal file
@ -0,0 +1,157 @@
|
||||
<?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\network\mcpe;
|
||||
|
||||
use pocketmine\inventory\AnvilInventory;
|
||||
use pocketmine\inventory\BlockInventory;
|
||||
use pocketmine\inventory\BrewingStandInventory;
|
||||
use pocketmine\inventory\CreativeInventory;
|
||||
use pocketmine\inventory\EnchantInventory;
|
||||
use pocketmine\inventory\FurnaceInventory;
|
||||
use pocketmine\inventory\HopperInventory;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
|
||||
use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
|
||||
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\WindowTypes;
|
||||
use pocketmine\player\Player;
|
||||
use function array_search;
|
||||
use function max;
|
||||
|
||||
class InventoryManager{
|
||||
|
||||
/** @var Player */
|
||||
private $player;
|
||||
/** @var NetworkSession */
|
||||
private $session;
|
||||
|
||||
/** @var Inventory[] */
|
||||
private $windowMap = [];
|
||||
/** @var int */
|
||||
private $lastInventoryNetworkId = ContainerIds::FIRST;
|
||||
|
||||
public function __construct(Player $player, NetworkSession $session){
|
||||
$this->player = $player;
|
||||
$this->session = $session;
|
||||
|
||||
$this->windowMap[ContainerIds::INVENTORY] = $this->player->getInventory();
|
||||
$this->windowMap[ContainerIds::ARMOR] = $this->player->getArmorInventory();
|
||||
$this->windowMap[ContainerIds::CURSOR] = $this->player->getCursorInventory();
|
||||
}
|
||||
|
||||
public function getWindowId(Inventory $inventory) : ?int{
|
||||
return ($id = array_search($inventory, $this->windowMap, true)) !== false ? $id : null;
|
||||
}
|
||||
|
||||
public function getCurrentWindowId() : int{
|
||||
return $this->lastInventoryNetworkId;
|
||||
}
|
||||
|
||||
public function getWindow(int $windowId) : ?Inventory{
|
||||
return $this->windowMap[$windowId] ?? null;
|
||||
}
|
||||
|
||||
public function onCurrentWindowChange(Inventory $inventory) : void{
|
||||
$this->onCurrentWindowRemove();
|
||||
$this->windowMap[$this->lastInventoryNetworkId = max(ContainerIds::FIRST, ($this->lastInventoryNetworkId + 1) % ContainerIds::LAST)] = $inventory;
|
||||
|
||||
$pk = $this->createContainerOpen($this->lastInventoryNetworkId, $inventory);
|
||||
if($pk !== null){
|
||||
$this->session->sendDataPacket($pk);
|
||||
$this->syncContents($inventory);
|
||||
}else{
|
||||
throw new \UnsupportedOperationException("Unsupported inventory type");
|
||||
}
|
||||
}
|
||||
|
||||
protected function createContainerOpen(int $id, Inventory $inv) : ?ContainerOpenPacket{
|
||||
//TODO: allow plugins to inject this
|
||||
if($inv instanceof BlockInventory){
|
||||
switch(true){
|
||||
case $inv instanceof FurnaceInventory:
|
||||
//TODO: specialized furnace types
|
||||
return ContainerOpenPacket::blockInvVec3($id, WindowTypes::FURNACE, $inv->getHolder());
|
||||
case $inv instanceof EnchantInventory:
|
||||
return ContainerOpenPacket::blockInvVec3($id, WindowTypes::ENCHANTMENT, $inv->getHolder());
|
||||
case $inv instanceof BrewingStandInventory:
|
||||
return ContainerOpenPacket::blockInvVec3($id, WindowTypes::BREWING_STAND, $inv->getHolder());
|
||||
case $inv instanceof AnvilInventory:
|
||||
return ContainerOpenPacket::blockInvVec3($id, WindowTypes::ANVIL, $inv->getHolder());
|
||||
case $inv instanceof HopperInventory:
|
||||
return ContainerOpenPacket::blockInvVec3($id, WindowTypes::HOPPER, $inv->getHolder());
|
||||
default:
|
||||
return ContainerOpenPacket::blockInvVec3($id, WindowTypes::CONTAINER, $inv->getHolder());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onCurrentWindowRemove() : void{
|
||||
if(isset($this->windowMap[$this->lastInventoryNetworkId])){
|
||||
unset($this->windowMap[$this->lastInventoryNetworkId]);
|
||||
$this->session->sendDataPacket(ContainerClosePacket::create($this->lastInventoryNetworkId));
|
||||
}
|
||||
}
|
||||
|
||||
public function syncSlot(Inventory $inventory, int $slot) : void{
|
||||
$windowId = $this->getWindowId($inventory);
|
||||
if($windowId !== null){
|
||||
$this->session->sendDataPacket(InventorySlotPacket::create($windowId, $slot, $inventory->getItem($slot)));
|
||||
}
|
||||
}
|
||||
|
||||
public function syncContents(Inventory $inventory) : void{
|
||||
$windowId = $this->getWindowId($inventory);
|
||||
if($windowId !== null){
|
||||
$this->session->sendDataPacket(InventoryContentPacket::create($windowId, $inventory->getContents(true)));
|
||||
}
|
||||
}
|
||||
|
||||
public function syncAll() : void{
|
||||
foreach($this->player->getAllWindows() as $inventory){
|
||||
$this->syncContents($inventory);
|
||||
}
|
||||
}
|
||||
|
||||
public function syncData(Inventory $inventory, int $propertyId, int $value) : void{
|
||||
$windowId = $this->getWindowId($inventory);
|
||||
if($windowId !== null){
|
||||
$this->session->sendDataPacket(ContainerSetDataPacket::create($windowId, $propertyId, $value));
|
||||
}
|
||||
}
|
||||
|
||||
public function syncCreative() : void{
|
||||
$items = [];
|
||||
if(!$this->player->isSpectator()){ //fill it for all gamemodes except spectator
|
||||
foreach(CreativeInventory::getAll() as $i => $item){
|
||||
$items[$i] = clone $item;
|
||||
}
|
||||
}
|
||||
|
||||
$this->session->sendDataPacket(InventoryContentPacket::create(ContainerIds::CREATIVE, $items));
|
||||
}
|
||||
}
|
@ -29,8 +29,6 @@ use pocketmine\event\player\PlayerCreationEvent;
|
||||
use pocketmine\event\server\DataPacketReceiveEvent;
|
||||
use pocketmine\event\server\DataPacketSendEvent;
|
||||
use pocketmine\form\Form;
|
||||
use pocketmine\inventory\CreativeInventory;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\BadPacketException;
|
||||
use pocketmine\network\mcpe\handler\DeathPacketHandler;
|
||||
@ -45,11 +43,8 @@ use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
|
||||
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
|
||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||
use pocketmine\network\mcpe\protocol\ContainerSetDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\DisconnectPacket;
|
||||
use pocketmine\network\mcpe\protocol\GarbageServerboundPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
|
||||
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
|
||||
use pocketmine\network\mcpe\protocol\MobEffectPacket;
|
||||
use pocketmine\network\mcpe\protocol\ModalFormRequestPacket;
|
||||
@ -67,7 +62,6 @@ use pocketmine\network\mcpe\protocol\TransferPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\CommandData;
|
||||
use pocketmine\network\mcpe\protocol\types\CommandEnum;
|
||||
use pocketmine\network\mcpe\protocol\types\CommandParameter;
|
||||
use pocketmine\network\mcpe\protocol\types\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
||||
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
|
||||
@ -139,6 +133,9 @@ class NetworkSession{
|
||||
/** @var \SplQueue|CompressBatchPromise[] */
|
||||
private $compressedQueue;
|
||||
|
||||
/** @var InventoryManager|null */
|
||||
private $invManager = null;
|
||||
|
||||
public function __construct(Server $server, NetworkSessionManager $manager, NetworkInterface $interface, string $ip, int $port){
|
||||
$this->server = $server;
|
||||
$this->manager = $manager;
|
||||
@ -176,6 +173,8 @@ class NetworkSession{
|
||||
* @see Player::__construct()
|
||||
*/
|
||||
$this->player = new $class($this->server, $this, $this->info, $this->authenticated);
|
||||
|
||||
$this->invManager = new InventoryManager($this->player, $this);
|
||||
}
|
||||
|
||||
public function getPlayer() : ?Player{
|
||||
@ -443,6 +442,8 @@ class NetworkSession{
|
||||
$this->connected = false;
|
||||
$this->manager->remove($this);
|
||||
$this->logger->info("Session closed due to $reason");
|
||||
|
||||
$this->invManager = null; //break cycles - TODO: this really ought to be deferred until it's safe
|
||||
}
|
||||
}
|
||||
|
||||
@ -594,7 +595,7 @@ class NetworkSession{
|
||||
$this->player->sendData($this->player->getViewers());
|
||||
|
||||
$this->syncAdventureSettings($this->player);
|
||||
$this->syncAllInventoryContents();
|
||||
$this->invManager->syncAll();
|
||||
$this->setHandler(new InGamePacketHandler($this->player, $this));
|
||||
}
|
||||
|
||||
@ -629,7 +630,7 @@ class NetworkSession{
|
||||
$this->sendDataPacket(SetPlayerGameTypePacket::create(self::getClientFriendlyGamemode($mode)));
|
||||
$this->syncAdventureSettings($this->player);
|
||||
if(!$isRollback){
|
||||
$this->syncCreativeInventoryContents();
|
||||
$this->invManager->syncCreative();
|
||||
}
|
||||
}
|
||||
|
||||
@ -765,42 +766,11 @@ class NetworkSession{
|
||||
|
||||
}
|
||||
|
||||
public function syncInventorySlot(Inventory $inventory, int $slot) : void{
|
||||
$windowId = $this->player->getWindowId($inventory);
|
||||
if($windowId !== null){
|
||||
$this->sendDataPacket(InventorySlotPacket::create($windowId, $slot, $inventory->getItem($slot)));
|
||||
}
|
||||
}
|
||||
|
||||
public function syncInventoryContents(Inventory $inventory) : void{
|
||||
$windowId = $this->player->getWindowId($inventory);
|
||||
if($windowId !== null){
|
||||
$this->sendDataPacket(InventoryContentPacket::create($windowId, $inventory->getContents(true)));
|
||||
}
|
||||
}
|
||||
|
||||
public function syncAllInventoryContents() : void{
|
||||
foreach($this->player->getAllWindows() as $inventory){
|
||||
$this->syncInventoryContents($inventory);
|
||||
}
|
||||
}
|
||||
|
||||
public function syncInventoryData(Inventory $inventory, int $propertyId, int $value) : void{
|
||||
$windowId = $this->player->getWindowId($inventory);
|
||||
if($windowId !== null){
|
||||
$this->sendDataPacket(ContainerSetDataPacket::create($windowId, $propertyId, $value));
|
||||
}
|
||||
}
|
||||
|
||||
public function syncCreativeInventoryContents() : void{
|
||||
$items = [];
|
||||
if(!$this->player->isSpectator()){ //fill it for all gamemodes except spectator
|
||||
foreach(CreativeInventory::getAll() as $i => $item){
|
||||
$items[$i] = clone $item;
|
||||
}
|
||||
}
|
||||
|
||||
$this->sendDataPacket(InventoryContentPacket::create(ContainerIds::CREATIVE, $items));
|
||||
/**
|
||||
* @return InventoryManager
|
||||
*/
|
||||
public function getInvManager() : InventoryManager{
|
||||
return $this->invManager;
|
||||
}
|
||||
|
||||
public function onMobArmorChange(Living $mob) : void{
|
||||
|
@ -162,7 +162,7 @@ class InGamePacketHandler extends PacketHandler{
|
||||
|
||||
public function handleInventoryTransaction(InventoryTransactionPacket $packet) : bool{
|
||||
if($this->player->isSpectator()){
|
||||
$this->session->syncAllInventoryContents();
|
||||
$this->session->getInvManager()->syncAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -172,7 +172,7 @@ class InGamePacketHandler extends PacketHandler{
|
||||
$result = $this->handleNormalTransaction($packet->trData);
|
||||
}elseif($packet->trData instanceof MismatchTransactionData){
|
||||
$this->session->getLogger()->debug("Mismatch transaction received");
|
||||
$this->session->syncAllInventoryContents();
|
||||
$this->session->getInvManager()->syncAll();
|
||||
$result = true;
|
||||
}elseif($packet->trData instanceof UseItemTransactionData){
|
||||
$result = $this->handleUseItemTransaction($packet->trData);
|
||||
@ -183,7 +183,7 @@ class InGamePacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
if(!$result){
|
||||
$this->session->syncAllInventoryContents();
|
||||
$this->session->getInvManager()->syncAll();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
@ -344,7 +344,7 @@ class InGamePacketHandler extends PacketHandler{
|
||||
switch($data->getActionType()){
|
||||
case ReleaseItemTransactionData::ACTION_RELEASE:
|
||||
if(!$this->player->releaseHeldItem()){
|
||||
$this->session->syncInventoryContents($this->player->getInventory());
|
||||
$this->session->getInvManager()->syncContents($this->player->getInventory());
|
||||
}
|
||||
return true;
|
||||
case ReleaseItemTransactionData::ACTION_CONSUME:
|
||||
@ -462,7 +462,21 @@ class InGamePacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
public function handleContainerClose(ContainerClosePacket $packet) : bool{
|
||||
return $this->player->doCloseWindow($packet->windowId);
|
||||
$this->player->doCloseInventory();
|
||||
|
||||
if($packet->windowId === 255){
|
||||
//Closed a fake window
|
||||
return true;
|
||||
}
|
||||
|
||||
$window = $this->player->getCurrentWindow();
|
||||
if($window !== null and $packet->windowId === $this->session->getInvManager()->getCurrentWindowId()){
|
||||
$this->player->removeCurrentWindow();
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->session->getLogger()->debug("Attempted to close inventory with network ID $packet->windowId, but current is " . $this->session->getInvManager()->getCurrentWindowId());
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handlePlayerHotbar(PlayerHotbarPacket $packet) : bool{
|
||||
|
@ -91,8 +91,8 @@ class PreSpawnPacketHandler extends PacketHandler{
|
||||
$this->player->sendPotionEffects($this->player);
|
||||
$this->player->sendData($this->player);
|
||||
|
||||
$this->session->syncAllInventoryContents();
|
||||
$this->session->syncCreativeInventoryContents();
|
||||
$this->session->getInvManager()->syncAll();
|
||||
$this->session->getInvManager()->syncCreative();
|
||||
$this->player->getInventory()->sendHeldItem($this->player);
|
||||
$this->session->queueCompressed($this->server->getCraftingManager()->getCraftingDataPacket());
|
||||
|
||||
|
@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\protocol;
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\network\mcpe\handler\PacketHandler;
|
||||
|
||||
class ContainerOpenPacket extends DataPacket implements ClientboundPacket{
|
||||
@ -52,6 +53,10 @@ class ContainerOpenPacket extends DataPacket implements ClientboundPacket{
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function blockInvVec3(int $windowId, int $windowType, Vector3 $vector3) : self{
|
||||
return self::blockInv($windowId, $windowType, $vector3->getFloorX(), $vector3->getFloorY(), $vector3->getFloorZ());
|
||||
}
|
||||
|
||||
public static function entityInv(int $windowId, int $windowType, int $entityUniqueId) : self{
|
||||
$result = new self;
|
||||
$result->windowId = $windowId;
|
||||
|
@ -171,7 +171,7 @@ class NetworkInventoryAction{
|
||||
public function createInventoryAction(Player $player) : ?InventoryAction{
|
||||
switch($this->sourceType){
|
||||
case self::SOURCE_CONTAINER:
|
||||
$window = $player->getWindow($this->windowId);
|
||||
$window = $player->getNetworkSession()->getInvManager()->getWindow($this->windowId);
|
||||
if($window !== null){
|
||||
return new SlotChangeAction($window, $this->inventorySlot, $this->oldItem, $this->newItem);
|
||||
}
|
||||
|
@ -92,7 +92,6 @@ use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
|
||||
use pocketmine\network\mcpe\protocol\SetTitlePacket;
|
||||
use pocketmine\network\mcpe\protocol\types\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\EntityMetadataFlags;
|
||||
use pocketmine\network\mcpe\protocol\types\EntityMetadataProperties;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerMetadataFlags;
|
||||
@ -111,7 +110,6 @@ use pocketmine\world\particle\PunchBlockParticle;
|
||||
use pocketmine\world\Position;
|
||||
use pocketmine\world\World;
|
||||
use function abs;
|
||||
use function array_search;
|
||||
use function assert;
|
||||
use function ceil;
|
||||
use function count;
|
||||
@ -119,7 +117,6 @@ use function explode;
|
||||
use function floor;
|
||||
use function get_class;
|
||||
use function is_int;
|
||||
use function max;
|
||||
use function microtime;
|
||||
use function min;
|
||||
use function preg_match;
|
||||
@ -182,10 +179,6 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
||||
/** @var PlayerInfo */
|
||||
protected $playerInfo;
|
||||
|
||||
/** @var int */
|
||||
protected $lastInventoryNetworkId = 2;
|
||||
/** @var Inventory[] network ID => inventory */
|
||||
protected $networkIdToInventoryMap = [];
|
||||
/** @var Inventory|null */
|
||||
protected $currentWindow = null;
|
||||
/** @var Inventory[] */
|
||||
@ -2316,10 +2309,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
||||
$this->loadQueue = [];
|
||||
|
||||
$this->removeCurrentWindow();
|
||||
foreach($this->permanentWindows as $objectId => $inventory){
|
||||
$this->closeInventoryInternal($inventory, true);
|
||||
}
|
||||
assert(empty($this->networkIdToInventoryMap));
|
||||
$this->removePermanentInventories();
|
||||
|
||||
$this->perm->clearPermissions();
|
||||
|
||||
@ -2570,15 +2560,11 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
||||
}
|
||||
|
||||
protected function addDefaultWindows(){
|
||||
$this->openInventoryInternal($this->getInventory(), ContainerIds::INVENTORY, true);
|
||||
|
||||
$this->openInventoryInternal($this->getArmorInventory(), ContainerIds::ARMOR, true);
|
||||
|
||||
$this->cursorInventory = new PlayerCursorInventory($this);
|
||||
$this->openInventoryInternal($this->cursorInventory, ContainerIds::CURSOR, true);
|
||||
|
||||
$this->craftingGrid = new CraftingGrid($this, CraftingGrid::SIZE_SMALL);
|
||||
|
||||
$this->addPermanentInventories($this->inventory, $this->armorInventory, $this->cursorInventory);
|
||||
|
||||
//TODO: more windows
|
||||
}
|
||||
|
||||
@ -2621,29 +2607,6 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Called by the network session when a player closes a window.
|
||||
*
|
||||
* @param int $windowId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function doCloseWindow(int $windowId) : bool{
|
||||
$this->doCloseInventory();
|
||||
|
||||
if($windowId === $this->lastInventoryNetworkId and $this->currentWindow !== null){
|
||||
$this->removeCurrentWindow();
|
||||
return true;
|
||||
}
|
||||
if($windowId === 255){
|
||||
//Closed a fake window
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->logger->debug("Attempted to close inventory with network ID $windowId, but current is $this->lastInventoryNetworkId");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inventory the player is currently viewing. This might be a chest, furnace, or any other container.
|
||||
*
|
||||
@ -2673,9 +2636,9 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
||||
//TODO: client side race condition here makes the opening work incorrectly
|
||||
$this->removeCurrentWindow();
|
||||
|
||||
$networkId = $this->lastInventoryNetworkId = max(ContainerIds::FIRST, ($this->lastInventoryNetworkId + 1) % ContainerIds::LAST);
|
||||
|
||||
$this->openInventoryInternal($inventory, $networkId, false);
|
||||
$this->logger->debug("Opening inventory " . get_class($inventory) . "#" . spl_object_id($inventory));
|
||||
$this->networkSession->getInvManager()->onCurrentWindowChange($inventory);
|
||||
$inventory->onOpen($this);
|
||||
$this->currentWindow = $inventory;
|
||||
return true;
|
||||
}
|
||||
@ -2683,61 +2646,28 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
||||
public function removeCurrentWindow() : void{
|
||||
if($this->currentWindow !== null){
|
||||
(new InventoryCloseEvent($this->currentWindow, $this))->call();
|
||||
$this->closeInventoryInternal($this->currentWindow, false);
|
||||
|
||||
$this->logger->debug("Closing inventory " . get_class($this->currentWindow) . "#" . spl_object_id($this->currentWindow));
|
||||
$this->currentWindow->onClose($this);
|
||||
if($this->isConnected()){
|
||||
$this->networkSession->getInvManager()->onCurrentWindowRemove();
|
||||
}
|
||||
$this->currentWindow = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the window ID which the inventory has for this player, or -1 if the window is not open to the player.
|
||||
*
|
||||
* @param Inventory $inventory
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getWindowId(Inventory $inventory) : ?int{
|
||||
return ($id = array_search($inventory, $this->networkIdToInventoryMap, true)) !== false ? $id : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inventory window open to the player with the specified window ID, or null if no window is open with
|
||||
* that ID.
|
||||
*
|
||||
* @param int $windowId
|
||||
*
|
||||
* @return Inventory|null
|
||||
*/
|
||||
public function getWindow(int $windowId) : ?Inventory{
|
||||
return $this->networkIdToInventoryMap[$windowId] ?? null;
|
||||
}
|
||||
|
||||
protected function openInventoryInternal(Inventory $inventory, int $networkId, bool $permanent) : void{
|
||||
$this->logger->debug("Opening inventory " . get_class($inventory) . "#" . spl_object_id($inventory) . " with network ID $networkId");
|
||||
$this->networkIdToInventoryMap[$networkId] = $inventory;
|
||||
$inventory->onOpen($this);
|
||||
if($permanent){
|
||||
protected function addPermanentInventories(Inventory ...$inventories) : void{
|
||||
foreach($inventories as $inventory){
|
||||
$inventory->onOpen($this);
|
||||
$this->permanentWindows[spl_object_id($inventory)] = $inventory;
|
||||
}
|
||||
}
|
||||
|
||||
protected function closeInventoryInternal(Inventory $inventory, bool $force) : bool{
|
||||
$this->logger->debug("Closing inventory " . get_class($inventory) . "#" . spl_object_id($inventory));
|
||||
$objectId = spl_object_id($inventory);
|
||||
if($inventory === $this->currentWindow){
|
||||
$this->currentWindow = null;
|
||||
}elseif(isset($this->permanentWindows[$objectId])){
|
||||
if(!$force){
|
||||
throw new \InvalidArgumentException("Cannot remove fixed window " . get_class($inventory) . " from " . $this->getName());
|
||||
}
|
||||
unset($this->permanentWindows[$objectId]);
|
||||
}else{
|
||||
return false;
|
||||
protected function removePermanentInventories() : void{
|
||||
foreach($this->permanentWindows as $inventory){
|
||||
$inventory->onClose($this);
|
||||
}
|
||||
|
||||
$inventory->onClose($this);
|
||||
$networkId = $this->getWindowId($inventory);
|
||||
assert($networkId !== null);
|
||||
unset($this->networkIdToInventoryMap[$networkId]);
|
||||
return true;
|
||||
$this->permanentWindows = [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user