mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-27 05:40:01 +00:00
Rework inventory window open/close handling
- This fixes InventoryOpenEvent and InventoryCloseEvent being fired for persistent windows. Close #2950 - The ability to specify a custom network ID to assign the inventory to in addWindow() has been removed. - The ability to assign a non-removable window in addWindow() has been removed. - The ability to remove non-removable windows in removeWindow() and removeAllWindows() has been removed. This was previously needed for internal purposes.
This commit is contained in:
parent
c77e75fa93
commit
50a7fc0ba3
@ -2424,7 +2424,11 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
|||||||
$this->usedChunks = [];
|
$this->usedChunks = [];
|
||||||
$this->loadQueue = [];
|
$this->loadQueue = [];
|
||||||
|
|
||||||
$this->removeAllWindows(true);
|
$this->removeAllWindows();
|
||||||
|
foreach($this->permanentWindows as $networkId => $bool){
|
||||||
|
$this->closeInventoryInternal($this->windowIndex[$networkId], true);
|
||||||
|
}
|
||||||
|
assert(empty($this->windowIndex) && empty($this->windows));
|
||||||
$this->windows = [];
|
$this->windows = [];
|
||||||
$this->windowIndex = [];
|
$this->windowIndex = [];
|
||||||
|
|
||||||
@ -2435,8 +2439,8 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
|||||||
|
|
||||||
protected function onDispose() : void{
|
protected function onDispose() : void{
|
||||||
$this->disconnect("Player destroyed");
|
$this->disconnect("Player destroyed");
|
||||||
$this->cursorInventory->removeAllViewers(true);
|
$this->cursorInventory->removeAllViewers();
|
||||||
$this->craftingGrid->removeAllViewers(true);
|
$this->craftingGrid->removeAllViewers();
|
||||||
parent::onDispose();
|
parent::onDispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2678,12 +2682,12 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function addDefaultWindows(){
|
protected function addDefaultWindows(){
|
||||||
$this->addWindow($this->getInventory(), ContainerIds::INVENTORY, true);
|
$this->openInventoryInternal($this->getInventory(), ContainerIds::INVENTORY, true);
|
||||||
|
|
||||||
$this->addWindow($this->getArmorInventory(), ContainerIds::ARMOR, true);
|
$this->openInventoryInternal($this->getArmorInventory(), ContainerIds::ARMOR, true);
|
||||||
|
|
||||||
$this->cursorInventory = new PlayerCursorInventory($this);
|
$this->cursorInventory = new PlayerCursorInventory($this);
|
||||||
$this->addWindow($this->cursorInventory, ContainerIds::CURSOR, true);
|
$this->openInventoryInternal($this->cursorInventory, ContainerIds::CURSOR, true);
|
||||||
|
|
||||||
$this->craftingGrid = new CraftingGrid($this, CraftingGrid::SIZE_SMALL);
|
$this->craftingGrid = new CraftingGrid($this, CraftingGrid::SIZE_SMALL);
|
||||||
|
|
||||||
@ -2778,25 +2782,50 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
|||||||
return $this->windowIndex[$windowId] ?? null;
|
return $this->windowIndex[$windowId] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function openInventoryInternal(Inventory $inventory, int $networkId, bool $permanent) : void{
|
||||||
|
$this->windowIndex[$networkId] = $inventory;
|
||||||
|
$this->windows[spl_object_id($inventory)] = $networkId;
|
||||||
|
$inventory->onOpen($this);
|
||||||
|
if($permanent){
|
||||||
|
$this->logger->debug("Opening permanent inventory " . get_class($inventory) . " with network ID $networkId");
|
||||||
|
$this->permanentWindows[$networkId] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function closeInventoryInternal(Inventory $inventory, bool $force) : bool{
|
||||||
|
$objectId = spl_object_id($inventory);
|
||||||
|
$networkId = $this->windows[$objectId] ?? null;
|
||||||
|
if($networkId !== null){
|
||||||
|
if(isset($this->permanentWindows[$networkId])){
|
||||||
|
if(!$force){
|
||||||
|
throw new \InvalidArgumentException("Cannot remove fixed window " . get_class($inventory) . " from " . $this->getName());
|
||||||
|
}
|
||||||
|
$this->logger->debug("Closing permanent inventory " . get_class($inventory) . " with network ID $networkId");
|
||||||
|
}
|
||||||
|
|
||||||
|
$inventory->onClose($this);
|
||||||
|
unset($this->windows[$objectId], $this->windowIndex[$networkId], $this->permanentWindows[$networkId]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens an inventory window to the player. Returns the ID of the created window, or the existing window ID if the
|
* Opens an inventory window to the player. Returns the ID of the created window, or the existing window ID if the
|
||||||
* player is already viewing the specified inventory.
|
* player is already viewing the specified inventory.
|
||||||
*
|
*
|
||||||
* @param Inventory $inventory
|
* @param Inventory $inventory
|
||||||
* @param int|null $forceNetworkId Forces a special ID for the window
|
|
||||||
* @param bool $isPermanent Prevents the window being removed if true.
|
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*
|
*
|
||||||
* @throws \InvalidArgumentException if a forceID which is already in use is specified
|
* @throws \InvalidArgumentException if a forceID which is already in use is specified
|
||||||
* @throws \InvalidStateException if trying to add a window without forceID when no slots are free
|
* @throws \InvalidStateException if trying to add a window without forceID when no slots are free
|
||||||
*/
|
*/
|
||||||
public function addWindow(Inventory $inventory, ?int $forceNetworkId = null, bool $isPermanent = false) : int{
|
public function addWindow(Inventory $inventory) : int{
|
||||||
if(($id = $this->getWindowId($inventory)) !== ContainerIds::NONE){
|
if(($id = $this->getWindowId($inventory)) !== ContainerIds::NONE){
|
||||||
return $id;
|
return $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($forceNetworkId === null){
|
|
||||||
$networkId = $this->lastInventoryNetworkId;
|
$networkId = $this->lastInventoryNetworkId;
|
||||||
do{
|
do{
|
||||||
$networkId = max(ContainerIds::FIRST, ($networkId + 1) % ContainerIds::LAST);
|
$networkId = max(ContainerIds::FIRST, ($networkId + 1) % ContainerIds::LAST);
|
||||||
@ -2805,12 +2834,6 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
|||||||
}
|
}
|
||||||
}while(isset($this->windowIndex[$networkId]));
|
}while(isset($this->windowIndex[$networkId]));
|
||||||
$this->lastInventoryNetworkId = $networkId;
|
$this->lastInventoryNetworkId = $networkId;
|
||||||
}else{
|
|
||||||
$networkId = $forceNetworkId;
|
|
||||||
if(isset($this->windowIndex[$networkId])){
|
|
||||||
throw new \InvalidArgumentException("Requested force ID $forceNetworkId already in use");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$ev = new InventoryOpenEvent($inventory, $this);
|
$ev = new InventoryOpenEvent($inventory, $this);
|
||||||
$ev->call();
|
$ev->call();
|
||||||
@ -2818,12 +2841,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->windowIndex[$networkId] = $inventory;
|
$this->openInventoryInternal($inventory, $networkId, false);
|
||||||
$this->windows[spl_object_id($inventory)] = $networkId;
|
|
||||||
$inventory->onOpen($this);
|
|
||||||
if($isPermanent){
|
|
||||||
$this->permanentWindows[spl_object_id($inventory)] = true;
|
|
||||||
}
|
|
||||||
return $networkId;
|
return $networkId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2831,36 +2849,26 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
|
|||||||
* Removes an inventory window from the player.
|
* Removes an inventory window from the player.
|
||||||
*
|
*
|
||||||
* @param Inventory $inventory
|
* @param Inventory $inventory
|
||||||
* @param bool $force Forces removal of permanent windows such as normal inventory, cursor
|
|
||||||
*
|
*
|
||||||
* @throws \InvalidArgumentException if trying to remove a fixed inventory window without the `force` parameter as true
|
* @throws \InvalidArgumentException if trying to remove a fixed inventory window
|
||||||
*/
|
*/
|
||||||
public function removeWindow(Inventory $inventory, bool $force = false){
|
public function removeWindow(Inventory $inventory){
|
||||||
$objectId = spl_object_id($inventory);
|
if($this->closeInventoryInternal($inventory, false)){
|
||||||
if(!$force and isset($this->permanentWindows[$objectId])){
|
|
||||||
throw new \InvalidArgumentException("Cannot remove fixed window " . get_class($inventory) . " from " . $this->getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
$networkId = $this->windows[$objectId] ?? null;
|
|
||||||
if($networkId !== null){
|
|
||||||
(new InventoryCloseEvent($inventory, $this))->call();
|
(new InventoryCloseEvent($inventory, $this))->call();
|
||||||
$inventory->onClose($this);
|
|
||||||
unset($this->windows[$objectId], $this->windowIndex[$networkId], $this->permanentWindows[$objectId]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all inventory windows from the player. By default this WILL NOT remove permanent windows.
|
* Removes all inventory windows from the player. This WILL NOT remove permanent inventories such as the player's
|
||||||
*
|
* own inventory.
|
||||||
* @param bool $removePermanentWindows Whether to remove permanent windows.
|
|
||||||
*/
|
*/
|
||||||
public function removeAllWindows(bool $removePermanentWindows = false){
|
public function removeAllWindows(){
|
||||||
foreach($this->windowIndex as $networkId => $window){
|
foreach($this->windowIndex as $networkId => $window){
|
||||||
if(!$removePermanentWindows and isset($this->permanentWindows[spl_object_id($window)])){
|
if(isset($this->permanentWindows[$networkId])){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->removeWindow($window, $removePermanentWindows);
|
$this->removeWindow($window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ class BrewingStand extends Spawnable implements Container, Nameable{
|
|||||||
|
|
||||||
public function close() : void{
|
public function close() : void{
|
||||||
if(!$this->closed){
|
if(!$this->closed){
|
||||||
$this->inventory->removeAllViewers(true);
|
$this->inventory->removeAllViewers();
|
||||||
$this->inventory = null;
|
$this->inventory = null;
|
||||||
|
|
||||||
parent::close();
|
parent::close();
|
||||||
|
@ -96,11 +96,11 @@ class Chest extends Spawnable implements Container, Nameable{
|
|||||||
|
|
||||||
public function close() : void{
|
public function close() : void{
|
||||||
if(!$this->closed){
|
if(!$this->closed){
|
||||||
$this->inventory->removeAllViewers(true);
|
$this->inventory->removeAllViewers();
|
||||||
|
|
||||||
if($this->doubleInventory !== null){
|
if($this->doubleInventory !== null){
|
||||||
if($this->isPaired() and $this->world->isChunkLoaded($this->pairX >> 4, $this->pairZ >> 4)){
|
if($this->isPaired() and $this->world->isChunkLoaded($this->pairX >> 4, $this->pairZ >> 4)){
|
||||||
$this->doubleInventory->removeAllViewers(true);
|
$this->doubleInventory->removeAllViewers();
|
||||||
$this->doubleInventory->invalidate();
|
$this->doubleInventory->invalidate();
|
||||||
if(($pair = $this->getPair()) !== null){
|
if(($pair = $this->getPair()) !== null){
|
||||||
$pair->doubleInventory = null;
|
$pair->doubleInventory = null;
|
||||||
|
@ -100,7 +100,7 @@ class Furnace extends Spawnable implements Container, Nameable{
|
|||||||
|
|
||||||
public function close() : void{
|
public function close() : void{
|
||||||
if(!$this->closed){
|
if(!$this->closed){
|
||||||
$this->inventory->removeAllViewers(true);
|
$this->inventory->removeAllViewers();
|
||||||
$this->inventory = null;
|
$this->inventory = null;
|
||||||
|
|
||||||
parent::close();
|
parent::close();
|
||||||
|
@ -62,7 +62,7 @@ class Hopper extends Spawnable implements Container, Nameable{
|
|||||||
|
|
||||||
public function close() : void{
|
public function close() : void{
|
||||||
if(!$this->closed){
|
if(!$this->closed){
|
||||||
$this->inventory->removeAllViewers(true);
|
$this->inventory->removeAllViewers();
|
||||||
$this->inventory = null;
|
$this->inventory = null;
|
||||||
|
|
||||||
parent::close();
|
parent::close();
|
||||||
|
@ -855,8 +855,8 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function onDispose() : void{
|
protected function onDispose() : void{
|
||||||
$this->inventory->removeAllViewers(true);
|
$this->inventory->removeAllViewers();
|
||||||
$this->enderChestInventory->removeAllViewers(true);
|
$this->enderChestInventory->removeAllViewers();
|
||||||
parent::onDispose();
|
parent::onDispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -918,7 +918,7 @@ abstract class Living extends Entity implements Damageable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function onDispose() : void{
|
protected function onDispose() : void{
|
||||||
$this->armorInventory->removeAllViewers(true);
|
$this->armorInventory->removeAllViewers();
|
||||||
parent::onDispose();
|
parent::onDispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,12 +339,10 @@ abstract class BaseInventory implements Inventory{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the inventory window from all players currently viewing it.
|
* Removes the inventory window from all players currently viewing it.
|
||||||
*
|
|
||||||
* @param bool $force Force removal of permanent windows such as the player's own inventory. Used internally.
|
|
||||||
*/
|
*/
|
||||||
public function removeAllViewers(bool $force = false) : void{
|
public function removeAllViewers() : void{
|
||||||
foreach($this->viewers as $hash => $viewer){
|
foreach($this->viewers as $hash => $viewer){
|
||||||
$viewer->removeWindow($this, $force);
|
$viewer->removeWindow($this);
|
||||||
unset($this->viewers[$hash]);
|
unset($this->viewers[$hash]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user