diff --git a/src/event/AsyncEventDelegate.php b/src/event/AsyncEventDelegate.php index e598c2d54..c12ed8fc2 100644 --- a/src/event/AsyncEventDelegate.php +++ b/src/event/AsyncEventDelegate.php @@ -25,13 +25,17 @@ namespace pocketmine\event; use pocketmine\promise\Promise; use pocketmine\promise\PromiseResolver; +use pocketmine\timings\Timings; use pocketmine\utils\ObjectSet; use function array_shift; use function count; -final class AsyncEventDelegate extends Event{ +final class AsyncEventDelegate{ /** @phpstan-var ObjectSet> $promises */ private ObjectSet $promises; + /** @var array, int> $delegatesCall */ + private static array $delegatesCallDepth = []; + private const MAX_EVENT_CALL_DEPTH = 50; public function __construct( private AsyncEvent&Event $event @@ -42,9 +46,27 @@ final class AsyncEventDelegate extends Event{ /** * @phpstan-return Promise */ - public function callAsync() : Promise{ + public function call() : Promise{ $this->promises->clear(); - return $this->callDepth($this->callAsyncDepth(...)); + if(!isset(self::$delegatesCallDepth[$class = $this->event::class])){ + self::$delegatesCallDepth[$class] = 0; + } + + if(self::$delegatesCallDepth[$class] >= self::MAX_EVENT_CALL_DEPTH){ + //this exception will be caught by the parent event call if all else fails + throw new \RuntimeException("Recursive event call detected (reached max depth of " . self::MAX_EVENT_CALL_DEPTH . " calls)"); + } + + $timings = Timings::getAsyncEventTimings($this->event); + $timings->startTiming(); + + ++self::$delegatesCallDepth[$class]; + try{ + return $this->callAsyncDepth(); + }finally{ + --self::$delegatesCallDepth[$class]; + $timings->stopTiming(); + } } /** diff --git a/src/event/AsyncEventTrait.php b/src/event/AsyncEventTrait.php index 5fd12aca0..c5da9bac4 100644 --- a/src/event/AsyncEventTrait.php +++ b/src/event/AsyncEventTrait.php @@ -32,9 +32,6 @@ trait AsyncEventTrait { * @phpstan-return Promise */ final public function callAsync() : Promise{ - if(!isset($this->delegate)){ - $this->delegate = new AsyncEventDelegate($this); - } - return $this->delegate->callAsync(); + return (new AsyncEventDelegate($this))->call(); } } diff --git a/src/event/Event.php b/src/event/Event.php index 77746c8e8..7d1d19d70 100644 --- a/src/event/Event.php +++ b/src/event/Event.php @@ -47,32 +47,24 @@ abstract class Event{ * @throws \RuntimeException if event call recursion reaches the max depth limit */ public function call() : void{ - $this->callDepth(function(){ - $handlers = HandlerListManager::global()->getHandlersFor(static::class); - - foreach($handlers as $registration){ - $registration->callEvent($this); - } - }); - } - - /** - * @template T - * @phpstan-param \Closure() : T $closure - * @phpstan-return T - */ - final protected function callDepth(\Closure $closure) : mixed{ if(self::$eventCallDepth >= self::MAX_EVENT_CALL_DEPTH){ //this exception will be caught by the parent event call if all else fails throw new \RuntimeException("Recursive event call detected (reached max depth of " . self::MAX_EVENT_CALL_DEPTH . " calls)"); } + if($this instanceof AsyncEvent){ + throw new \InvalidArgumentException("Cannot call async event synchronously"); + } $timings = Timings::getEventTimings($this); $timings->startTiming(); + $handlers = HandlerListManager::global()->getHandlersFor(static::class); + ++self::$eventCallDepth; try{ - return $closure(); + foreach($handlers as $registration){ + $registration->callEvent($this); + } }finally{ --self::$eventCallDepth; $timings->stopTiming(); diff --git a/src/timings/Timings.php b/src/timings/Timings.php index 0d8a256de..e8d37c898 100644 --- a/src/timings/Timings.php +++ b/src/timings/Timings.php @@ -25,6 +25,7 @@ namespace pocketmine\timings; use pocketmine\block\tile\Tile; use pocketmine\entity\Entity; +use pocketmine\event\AsyncEvent; use pocketmine\event\Event; use pocketmine\network\mcpe\protocol\ClientboundPacket; use pocketmine\network\mcpe\protocol\ServerboundPacket; @@ -113,6 +114,8 @@ abstract class Timings{ /** @var TimingsHandler[] */ private static array $events = []; + /** @var TimingsHandler[] */ + private static array $asyncEvents = []; /** @var TimingsHandler[][] */ private static array $eventHandlers = []; @@ -304,6 +307,15 @@ abstract class Timings{ return self::$events[$eventClass]; } + public static function getAsyncEventTimings(AsyncEvent&Event $event) : TimingsHandler{ + $eventClass = get_class($event); + if(!isset(self::$asyncEvents[$eventClass])){ + self::$asyncEvents[$eventClass] = new TimingsHandler(self::shortenCoreClassName($eventClass, "pocketmine\\event\\"), group: "Events"); + } + + return self::$asyncEvents[$eventClass]; + } + /** * @phpstan-template TEvent of Event * @phpstan-param class-string $event