From 6fbb9b6083e80f835ce042e658797d3326c189d6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 9 Jan 2017 13:18:28 +0000 Subject: [PATCH] Check for closed target Levels in Position (#241) More foolproof --- src/pocketmine/level/Level.php | 9 +++++++++ src/pocketmine/level/Position.php | 28 ++++++++++++++++++++++++--- src/pocketmine/level/WeakPosition.php | 13 ++++++++++++- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 95d9d64825..0b10e029f0 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -260,6 +260,8 @@ class Level implements ChunkManager, Metadatable{ /** @var Generator */ private $generatorInstance; + private $closed = false; + public static function chunkHash(int $x, int $z){ return PHP_INT_SIZE === 8 ? (($x & 0xFFFFFFFF) << 32) | ($z & 0xFFFFFFFF) : $x . ":" . $z; } @@ -404,7 +406,12 @@ class Level implements ChunkManager, Metadatable{ return $this->levelId; } + public function isClosed() : bool{ + return $this->closed; + } + public function close(){ + assert(!$this->closed, "Tried to close a level which is already closed"); if($this->getAutoSave()){ $this->save(); @@ -421,6 +428,8 @@ class Level implements ChunkManager, Metadatable{ $this->blockMetadata = null; $this->blockCache = []; $this->temporalPosition = null; + + $this->closed = true; } public function addSound(Sound $sound, array $players = null){ diff --git a/src/pocketmine/level/Position.php b/src/pocketmine/level/Position.php index 78f7b15f72..cd9c3284ef 100644 --- a/src/pocketmine/level/Position.php +++ b/src/pocketmine/level/Position.php @@ -23,6 +23,7 @@ namespace pocketmine\level; use pocketmine\math\Vector3; use pocketmine\utils\LevelException; +use pocketmine\utils\MainLogger; class Position extends Vector3{ @@ -47,19 +48,40 @@ class Position extends Vector3{ } /** - * @return Level + * Returns the target Level, or null if the target is not valid. + * If a reference exists to a Level which is closed, the reference will be destroyed and null will be returned. + * + * @return Level|null */ public function getLevel(){ + if($this->level !== null and $this->level->isClosed()){ + MainLogger::getLogger()->debug("Position was holding a reference to an unloaded Level"); + $this->level = null; + } + return $this->level; } - public function setLevel(Level $level){ + /** + * Sets the target Level of the position. + * + * @param Level|null $level + * + * @return $this + * + * @throws \InvalidArgumentException if the specified Level has been closed + */ + public function setLevel(Level $level = null){ + if($level !== null and $level->isClosed()){ + throw new \InvalidArgumentException("Specified level has been unloaded and cannot be used"); + } + $this->level = $level; return $this; } /** - * Checks if this object has a valid reference to a Level + * Checks if this object has a valid reference to a loaded Level * * @return bool */ diff --git a/src/pocketmine/level/WeakPosition.php b/src/pocketmine/level/WeakPosition.php index 257bbd3ca2..25b821e8f4 100644 --- a/src/pocketmine/level/WeakPosition.php +++ b/src/pocketmine/level/WeakPosition.php @@ -53,7 +53,18 @@ class WeakPosition extends Position{ return Server::getInstance()->getLevel($this->levelId); } - public function setLevel(Level $level){ + /** + * @param Level|null $level + * + * @return $this + * + * @throws \InvalidArgumentException if the specified Level has been closed + */ + public function setLevel(Level $level = null){ + if($level !== null and $level->isClosed()){ + throw new \InvalidArgumentException("Specified level has been unloaded and cannot be used"); + } + $this->levelId = ($level !== null ? $level->getId() : -1); return $this; }