diff --git a/src/permission/PermissibleBase.php b/src/permission/PermissibleBase.php index a1b43bfd34..87a6ca04c6 100644 --- a/src/permission/PermissibleBase.php +++ b/src/permission/PermissibleBase.php @@ -105,12 +105,14 @@ class PermissibleBase implements Permissible{ throw new PluginException("Plugin " . $plugin->getDescription()->getName() . " is disabled"); } - $result = new PermissionAttachment($plugin, $this); + $result = new PermissionAttachment($plugin); $this->attachments[spl_object_id($result)] = $result; if($name !== null and $value !== null){ $result->setPermission($name, $value); } + $result->subscribePermissible($this); + $this->recalculatePermissions(); return $result; @@ -119,8 +121,9 @@ class PermissibleBase implements Permissible{ public function removeAttachment(PermissionAttachment $attachment) : void{ if(isset($this->attachments[spl_object_id($attachment)])){ unset($this->attachments[spl_object_id($attachment)]); + $attachment->unsubscribePermissible($this); if(($ex = $attachment->getRemovalCallback()) !== null){ - $ex->attachmentRemoved($attachment); + $ex->attachmentRemoved($this, $attachment); } $this->recalculatePermissions(); @@ -213,7 +216,10 @@ class PermissibleBase implements Permissible{ public function destroyCycles() : void{ PermissionManager::getInstance()->unsubscribeFromAllPermissions($this); $this->permissions = []; //PermissionAttachmentInfo doesn't reference Permissible anymore, but it references PermissionAttachment which does - $this->attachments = []; //this might still be a problem if the attachments are still referenced, but we can't do anything about that + foreach($this->attachments as $attachment){ + $attachment->unsubscribePermissible($this); + } + $this->attachments = []; $this->permissionRecalculationCallbacks->clear(); } } diff --git a/src/permission/PermissionAttachment.php b/src/permission/PermissionAttachment.php index 7caad254c6..c66cc7fdfc 100644 --- a/src/permission/PermissionAttachment.php +++ b/src/permission/PermissionAttachment.php @@ -25,6 +25,7 @@ namespace pocketmine\permission; use pocketmine\plugin\Plugin; use pocketmine\plugin\PluginException; +use function spl_object_id; class PermissionAttachment{ /** @var PermissionRemovedExecutor|null */ @@ -33,8 +34,11 @@ class PermissionAttachment{ /** @var bool[] */ private $permissions = []; - /** @var Permissible */ - private $permissible; + /** + * @var Permissible[] + * @phpstan-var array + */ + private $subscribers = []; /** @var Plugin */ private $plugin; @@ -42,12 +46,11 @@ class PermissionAttachment{ /** * @throws PluginException */ - public function __construct(Plugin $plugin, Permissible $permissible){ + public function __construct(Plugin $plugin){ if(!$plugin->isEnabled()){ throw new PluginException("Plugin " . $plugin->getDescription()->getName() . " is disabled"); } - $this->permissible = $permissible; $this->plugin = $plugin; } @@ -63,9 +66,11 @@ class PermissionAttachment{ return $this->removed; } - public function getPermissible() : Permissible{ - return $this->permissible; - } + /** + * @return Permissible[] + * @phpstan-return array + */ + public function getSubscribers() : array{ return $this->subscribers; } /** * @return bool[] @@ -74,9 +79,15 @@ class PermissionAttachment{ return $this->permissions; } + private function recalculatePermissibles() : void{ + foreach($this->subscribers as $permissible){ + $permissible->recalculatePermissions(); + } + } + public function clearPermissions() : void{ $this->permissions = []; - $this->permissible->recalculatePermissions(); + $this->recalculatePermissibles(); } /** @@ -86,7 +97,7 @@ class PermissionAttachment{ foreach($permissions as $key => $value){ $this->permissions[$key] = $value; } - $this->permissible->recalculatePermissions(); + $this->recalculatePermissibles(); } /** @@ -96,7 +107,7 @@ class PermissionAttachment{ foreach($permissions as $node){ unset($this->permissions[$node]); } - $this->permissible->recalculatePermissions(); + $this->recalculatePermissibles(); } /** @@ -120,7 +131,7 @@ class PermissionAttachment{ unset($this->permissions[$name]); } $this->permissions[$name] = $value; - $this->permissible->recalculatePermissions(); + $this->recalculatePermissibles(); } /** @@ -130,11 +141,21 @@ class PermissionAttachment{ $name = $name instanceof Permission ? $name->getName() : $name; if(isset($this->permissions[$name])){ unset($this->permissions[$name]); - $this->permissible->recalculatePermissions(); + $this->recalculatePermissibles(); } } - public function remove() : void{ - $this->permissible->removeAttachment($this); + /** + * @internal + */ + public function subscribePermissible(Permissible $permissible) : void{ + $this->subscribers[spl_object_id($permissible)] = $permissible; + } + + /** + * @internal + */ + public function unsubscribePermissible(Permissible $permissible) : void{ + unset($this->subscribers[spl_object_id($permissible)]); } } diff --git a/src/permission/PermissionRemovedExecutor.php b/src/permission/PermissionRemovedExecutor.php index 606d017ee5..4fbe96ff3f 100644 --- a/src/permission/PermissionRemovedExecutor.php +++ b/src/permission/PermissionRemovedExecutor.php @@ -25,5 +25,5 @@ namespace pocketmine\permission; interface PermissionRemovedExecutor{ - public function attachmentRemoved(PermissionAttachment $attachment) : void; + public function attachmentRemoved(Permissible $permissible, PermissionAttachment $attachment) : void; }