NetworkSession: explicitly unregister effect manager hooks on dispose,

close #3455
This commit is contained in:
Dylan K. Taylor 2020-05-14 10:58:37 +01:00
parent 36c5d9117d
commit 3dafee6aa6
2 changed files with 38 additions and 18 deletions

View File

@ -23,14 +23,13 @@ declare(strict_types=1);
namespace pocketmine\entity\effect; namespace pocketmine\entity\effect;
use Ds\Set;
use pocketmine\entity\Living; use pocketmine\entity\Living;
use pocketmine\event\entity\EntityEffectAddEvent; use pocketmine\event\entity\EntityEffectAddEvent;
use pocketmine\event\entity\EntityEffectRemoveEvent; use pocketmine\event\entity\EntityEffectRemoveEvent;
use pocketmine\utils\Color; use pocketmine\utils\Color;
use pocketmine\utils\Utils;
use function abs; use function abs;
use function count; use function count;
use function spl_object_id;
class EffectManager{ class EffectManager{
@ -46,19 +45,21 @@ class EffectManager{
protected $onlyAmbientEffects = false; protected $onlyAmbientEffects = false;
/** /**
* @var \Closure[] * @var \Closure[]|Set
* @phpstan-var (\Closure(EffectInstance, bool $replacesOldEffect) : void)[] * @phpstan-var Set<\Closure(EffectInstance, bool $replacesOldEffect) : void>
*/ */
protected $effectAddHooks = []; protected $effectAddHooks;
/** /**
* @var \Closure[] * @var \Closure[]|Set
* @phpstan-var (\Closure(EffectInstance) : void)[] * @phpstan-var Set<\Closure(EffectInstance) : void>
*/ */
protected $effectRemoveHooks = []; protected $effectRemoveHooks;
public function __construct(Living $entity){ public function __construct(Living $entity){
$this->entity = $entity; $this->entity = $entity;
$this->bubbleColor = new Color(0, 0, 0, 0); $this->bubbleColor = new Color(0, 0, 0, 0);
$this->effectAddHooks = new Set();
$this->effectRemoveHooks = new Set();
} }
/** /**
@ -222,18 +223,18 @@ class EffectManager{
} }
/** /**
* @phpstan-param \Closure(EffectInstance, bool $replacesOldEffect) : void $closure * @return \Closure[]|Set
* @phpstan-return Set<\Closure(EffectInstance, bool $replacesOldEffect) : void>
*/ */
public function onEffectAdd(\Closure $closure) : void{ public function getEffectAddHooks() : Set{
Utils::validateCallableSignature(function(EffectInstance $effect, bool $replacesOldEffect) : void{}, $closure); return $this->effectAddHooks;
$this->effectAddHooks[spl_object_id($closure)] = $closure;
} }
/** /**
* @phpstan-param \Closure(EffectInstance) : void $closure * @return \Closure[]|Set
* @phpstan-return Set<\Closure(EffectInstance) : void>
*/ */
public function onEffectRemove(\Closure $closure) : void{ public function getEffectRemoveHooks() : Set{
Utils::validateCallableSignature(function(EffectInstance $effect) : void{}, $closure); return $this->effectRemoveHooks;
$this->effectRemoveHooks[spl_object_id($closure)] = $closure;
} }
} }

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe; namespace pocketmine\network\mcpe;
use Ds\Set;
use Mdanter\Ecc\Crypto\Key\PublicKeyInterface; use Mdanter\Ecc\Crypto\Key\PublicKeyInterface;
use pocketmine\entity\Attribute; use pocketmine\entity\Attribute;
use pocketmine\entity\effect\EffectInstance; use pocketmine\entity\effect\EffectInstance;
@ -166,6 +167,12 @@ class NetworkSession{
/** @var PacketSender */ /** @var PacketSender */
private $sender; private $sender;
/**
* @var \Closure[]|Set
* @phpstan-var Set<\Closure() : void>
*/
private $disposeHooks;
public function __construct(Server $server, NetworkSessionManager $manager, PacketPool $packetPool, PacketSender $sender, Compressor $compressor, string $ip, int $port){ public function __construct(Server $server, NetworkSessionManager $manager, PacketPool $packetPool, PacketSender $sender, Compressor $compressor, string $ip, int $port){
$this->server = $server; $this->server = $server;
$this->manager = $manager; $this->manager = $manager;
@ -179,6 +186,8 @@ class NetworkSession{
$this->compressor = $compressor; $this->compressor = $compressor;
$this->packetPool = $packetPool; $this->packetPool = $packetPool;
$this->disposeHooks = new Set();
$this->connectTime = time(); $this->connectTime = time();
$this->setHandler(new LoginPacketHandler( $this->setHandler(new LoginPacketHandler(
@ -218,12 +227,18 @@ class NetworkSession{
$this->player = new $class($this->server, $this, $this->info, $this->authenticated); $this->player = new $class($this->server, $this, $this->info, $this->authenticated);
$this->invManager = new InventoryManager($this->player, $this); $this->invManager = new InventoryManager($this->player, $this);
$this->player->getEffects()->onEffectAdd(function(EffectInstance $effect, bool $replacesOldEffect) : void{
$effectManager = $this->player->getEffects();
$effectManager->getEffectAddHooks()->add($effectAddHook = function(EffectInstance $effect, bool $replacesOldEffect) : void{
$this->onEntityEffectAdded($this->player, $effect, $replacesOldEffect); $this->onEntityEffectAdded($this->player, $effect, $replacesOldEffect);
}); });
$this->player->getEffects()->onEffectRemove(function(EffectInstance $effect) : void{ $effectManager->getEffectRemoveHooks()->add($effectRemoveHook = function(EffectInstance $effect) : void{
$this->onEntityEffectRemoved($this->player, $effect); $this->onEntityEffectRemoved($this->player, $effect);
}); });
$this->disposeHooks->add(static function() use ($effectManager, $effectAddHook, $effectRemoveHook) : void{
$effectManager->getEffectAddHooks()->remove($effectAddHook);
$effectManager->getEffectRemoveHooks()->remove($effectRemoveHook);
});
} }
public function getPlayer() : ?Player{ public function getPlayer() : ?Player{
@ -467,6 +482,10 @@ class NetworkSession{
$this->disconnectGuard = true; $this->disconnectGuard = true;
$func(); $func();
$this->disconnectGuard = false; $this->disconnectGuard = false;
foreach($this->disposeHooks as $callback){
$callback();
}
$this->disposeHooks->clear();
$this->setHandler(null); $this->setHandler(null);
$this->connected = false; $this->connected = false;
$this->manager->remove($this); $this->manager->remove($this);