diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 7d6b1287c..f8c673eee 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -34,7 +34,7 @@ use pocketmine\command\ConsoleCommandSender; use pocketmine\command\PluginIdentifiableCommand; use pocketmine\command\SimpleCommandMap; use pocketmine\entity\EntityFactory; -use pocketmine\event\HandlerList; +use pocketmine\event\HandlerListManager; use pocketmine\event\player\PlayerDataSaveEvent; use pocketmine\event\server\CommandEvent; use pocketmine\event\server\DataPacketBroadcastEvent; @@ -1600,7 +1600,7 @@ class Server{ } $this->getLogger()->debug("Removing event handlers"); - HandlerList::unregisterAll(); + HandlerListManager::global()->unregisterAll(); if($this->asyncPool instanceof AsyncPool){ $this->getLogger()->debug("Shutting down async task worker pool"); diff --git a/src/pocketmine/event/Event.php b/src/pocketmine/event/Event.php index 9e96ccc17..7f1cc4bb5 100644 --- a/src/pocketmine/event/Event.php +++ b/src/pocketmine/event/Event.php @@ -55,7 +55,7 @@ abstract class Event{ throw new \RuntimeException("Recursive event call detected (reached max depth of " . self::MAX_EVENT_CALL_DEPTH . " calls)"); } - $handlerList = HandlerList::getHandlerListFor(get_class($this)); + $handlerList = HandlerListManager::global()->getListFor(get_class($this)); assert($handlerList !== null, "Called event should have a valid HandlerList"); ++self::$eventCallDepth; diff --git a/src/pocketmine/event/HandlerList.php b/src/pocketmine/event/HandlerList.php index e5fbb81f8..6d391215f 100644 --- a/src/pocketmine/event/HandlerList.php +++ b/src/pocketmine/event/HandlerList.php @@ -24,77 +24,11 @@ declare(strict_types=1); namespace pocketmine\event; use pocketmine\plugin\Plugin; -use pocketmine\utils\Utils; use function array_fill_keys; use function in_array; use function spl_object_id; class HandlerList{ - /** - * @var HandlerList[] classname => HandlerList - */ - private static $allLists = []; - - /** - * Unregisters all the listeners - * If a Plugin or Listener is passed, all the listeners with that object will be removed - * - * @param Plugin|Listener|null $object - */ - public static function unregisterAll($object = null) : void{ - if($object instanceof Listener or $object instanceof Plugin){ - foreach(self::$allLists as $h){ - $h->unregister($object); - } - }else{ - foreach(self::$allLists as $h){ - foreach($h->handlerSlots as $key => $list){ - $h->handlerSlots[$key] = []; - } - } - } - } - - /** - * Returns the HandlerList for listeners that explicitly handle this event. - * - * Calling this method also lazily initializes the $classMap inheritance tree of handler lists. - * - * @param string $event - * - * @return null|HandlerList - * @throws \ReflectionException - */ - public static function getHandlerListFor(string $event) : ?HandlerList{ - if(isset(self::$allLists[$event])){ - return self::$allLists[$event]; - } - - $class = new \ReflectionClass($event); - $tags = Utils::parseDocComment((string) $class->getDocComment()); - - if($class->isAbstract() && !isset($tags["allowHandle"])){ - return null; - } - - $super = $class; - $parentList = null; - while($parentList === null && ($super = $super->getParentClass()) !== false){ - // skip $noHandle events in the inheritance tree to go to the nearest ancestor - // while loop to allow skipping $noHandle events in the inheritance tree - $parentList = self::getHandlerListFor($super->getName()); - } - - return new HandlerList($event, $parentList); - } - - /** - * @return HandlerList[] - */ - public static function getHandlerLists() : array{ - return self::$allLists; - } - /** @var string */ private $class; @@ -107,7 +41,6 @@ class HandlerList{ $this->class = $class; $this->handlerSlots = array_fill_keys(EventPriority::ALL, []); $this->parentList = $parentList; - self::$allLists[$this->class] = $this; } /** @@ -155,6 +88,10 @@ class HandlerList{ } } + public function clear() : void{ + $this->handlerSlots = array_fill_keys(EventPriority::ALL, []); + } + /** * @param int $priority * diff --git a/src/pocketmine/event/HandlerListManager.php b/src/pocketmine/event/HandlerListManager.php new file mode 100644 index 000000000..0097d7a1c --- /dev/null +++ b/src/pocketmine/event/HandlerListManager.php @@ -0,0 +1,100 @@ + HandlerList + */ + private $allLists = []; + + /** + * Unregisters all the listeners + * If a Plugin or Listener is passed, all the listeners with that object will be removed + * + * @param Plugin|Listener|null $object + */ + public function unregisterAll($object = null) : void{ + if($object instanceof Listener or $object instanceof Plugin){ + foreach($this->allLists as $h){ + $h->unregister($object); + } + }else{ + foreach($this->allLists as $h){ + $h->clear(); + } + } + } + + /** + * Returns the HandlerList for listeners that explicitly handle this event. + * + * Calling this method also lazily initializes the $classMap inheritance tree of handler lists. + * + * @param string $event + * + * @return null|HandlerList + * @throws \ReflectionException + */ + public function getListFor(string $event) : ?HandlerList{ + if(isset($this->allLists[$event])){ + return $this->allLists[$event]; + } + + $class = new \ReflectionClass($event); + $tags = Utils::parseDocComment((string) $class->getDocComment()); + + if($class->isAbstract() && !isset($tags["allowHandle"])){ + return null; + } + + $super = $class; + $parentList = null; + while($parentList === null && ($super = $super->getParentClass()) !== false){ + // skip $noHandle events in the inheritance tree to go to the nearest ancestor + // while loop to allow skipping $noHandle events in the inheritance tree + $parentList = $this->getListFor($super->getName()); + } + + return $this->allLists[$event] = new HandlerList($event, $parentList); + } + + /** + * @return HandlerList[] + */ + public function getAll() : array{ + return $this->allLists; + } +} diff --git a/src/pocketmine/plugin/PluginManager.php b/src/pocketmine/plugin/PluginManager.php index 7dabe5fd9..8c65c9880 100644 --- a/src/pocketmine/plugin/PluginManager.php +++ b/src/pocketmine/plugin/PluginManager.php @@ -26,6 +26,7 @@ namespace pocketmine\plugin; use pocketmine\event\Event; use pocketmine\event\EventPriority; use pocketmine\event\HandlerList; +use pocketmine\event\HandlerListManager; use pocketmine\event\Listener; use pocketmine\event\plugin\PluginDisableEvent; use pocketmine\event\plugin\PluginEnableEvent; @@ -465,7 +466,7 @@ class PluginManager{ $plugin->onEnableStateChange(false); $plugin->getScheduler()->shutdown(); - HandlerList::unregisterAll($plugin); + HandlerListManager::global()->unregisterAll($plugin); $permManager = PermissionManager::getInstance(); foreach($plugin->getDescription()->getPermissions() as $perm){ $permManager->removePermission($perm); @@ -594,7 +595,7 @@ class PluginManager{ * @return HandlerList */ private function getEventListeners(string $event) : HandlerList{ - $list = HandlerList::getHandlerListFor($event); + $list = HandlerListManager::global()->getListFor($event); if($list === null){ throw new PluginException("Abstract events not declaring @allowHandle cannot be handled (tried to register listener for $event)"); }