PermissionAttachment may now reference zero or more permissibles

this makes PermissionAttachment more and more like Permission, except that it doesn't have a name.
Right now, the only value of this API change is that it allows breaking references to dead Permissibles, but in the future it should be possible to reuse a single PermissionAttachment on multiple Permissibles.
This commit is contained in:
Dylan K. Taylor 2021-04-12 15:57:24 +01:00
parent 4b715aaba7
commit 666670bc6f
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
3 changed files with 45 additions and 18 deletions

View File

@ -105,12 +105,14 @@ class PermissibleBase implements Permissible{
throw new PluginException("Plugin " . $plugin->getDescription()->getName() . " is disabled"); 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; $this->attachments[spl_object_id($result)] = $result;
if($name !== null and $value !== null){ if($name !== null and $value !== null){
$result->setPermission($name, $value); $result->setPermission($name, $value);
} }
$result->subscribePermissible($this);
$this->recalculatePermissions(); $this->recalculatePermissions();
return $result; return $result;
@ -119,8 +121,9 @@ class PermissibleBase implements Permissible{
public function removeAttachment(PermissionAttachment $attachment) : void{ public function removeAttachment(PermissionAttachment $attachment) : void{
if(isset($this->attachments[spl_object_id($attachment)])){ if(isset($this->attachments[spl_object_id($attachment)])){
unset($this->attachments[spl_object_id($attachment)]); unset($this->attachments[spl_object_id($attachment)]);
$attachment->unsubscribePermissible($this);
if(($ex = $attachment->getRemovalCallback()) !== null){ if(($ex = $attachment->getRemovalCallback()) !== null){
$ex->attachmentRemoved($attachment); $ex->attachmentRemoved($this, $attachment);
} }
$this->recalculatePermissions(); $this->recalculatePermissions();
@ -213,7 +216,10 @@ class PermissibleBase implements Permissible{
public function destroyCycles() : void{ public function destroyCycles() : void{
PermissionManager::getInstance()->unsubscribeFromAllPermissions($this); PermissionManager::getInstance()->unsubscribeFromAllPermissions($this);
$this->permissions = []; //PermissionAttachmentInfo doesn't reference Permissible anymore, but it references PermissionAttachment which does $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(); $this->permissionRecalculationCallbacks->clear();
} }
} }

View File

@ -25,6 +25,7 @@ namespace pocketmine\permission;
use pocketmine\plugin\Plugin; use pocketmine\plugin\Plugin;
use pocketmine\plugin\PluginException; use pocketmine\plugin\PluginException;
use function spl_object_id;
class PermissionAttachment{ class PermissionAttachment{
/** @var PermissionRemovedExecutor|null */ /** @var PermissionRemovedExecutor|null */
@ -33,8 +34,11 @@ class PermissionAttachment{
/** @var bool[] */ /** @var bool[] */
private $permissions = []; private $permissions = [];
/** @var Permissible */ /**
private $permissible; * @var Permissible[]
* @phpstan-var array<int, Permissible>
*/
private $subscribers = [];
/** @var Plugin */ /** @var Plugin */
private $plugin; private $plugin;
@ -42,12 +46,11 @@ class PermissionAttachment{
/** /**
* @throws PluginException * @throws PluginException
*/ */
public function __construct(Plugin $plugin, Permissible $permissible){ public function __construct(Plugin $plugin){
if(!$plugin->isEnabled()){ if(!$plugin->isEnabled()){
throw new PluginException("Plugin " . $plugin->getDescription()->getName() . " is disabled"); throw new PluginException("Plugin " . $plugin->getDescription()->getName() . " is disabled");
} }
$this->permissible = $permissible;
$this->plugin = $plugin; $this->plugin = $plugin;
} }
@ -63,9 +66,11 @@ class PermissionAttachment{
return $this->removed; return $this->removed;
} }
public function getPermissible() : Permissible{ /**
return $this->permissible; * @return Permissible[]
} * @phpstan-return array<int, Permissible>
*/
public function getSubscribers() : array{ return $this->subscribers; }
/** /**
* @return bool[] * @return bool[]
@ -74,9 +79,15 @@ class PermissionAttachment{
return $this->permissions; return $this->permissions;
} }
private function recalculatePermissibles() : void{
foreach($this->subscribers as $permissible){
$permissible->recalculatePermissions();
}
}
public function clearPermissions() : void{ public function clearPermissions() : void{
$this->permissions = []; $this->permissions = [];
$this->permissible->recalculatePermissions(); $this->recalculatePermissibles();
} }
/** /**
@ -86,7 +97,7 @@ class PermissionAttachment{
foreach($permissions as $key => $value){ foreach($permissions as $key => $value){
$this->permissions[$key] = $value; $this->permissions[$key] = $value;
} }
$this->permissible->recalculatePermissions(); $this->recalculatePermissibles();
} }
/** /**
@ -96,7 +107,7 @@ class PermissionAttachment{
foreach($permissions as $node){ foreach($permissions as $node){
unset($this->permissions[$node]); unset($this->permissions[$node]);
} }
$this->permissible->recalculatePermissions(); $this->recalculatePermissibles();
} }
/** /**
@ -120,7 +131,7 @@ class PermissionAttachment{
unset($this->permissions[$name]); unset($this->permissions[$name]);
} }
$this->permissions[$name] = $value; $this->permissions[$name] = $value;
$this->permissible->recalculatePermissions(); $this->recalculatePermissibles();
} }
/** /**
@ -130,11 +141,21 @@ class PermissionAttachment{
$name = $name instanceof Permission ? $name->getName() : $name; $name = $name instanceof Permission ? $name->getName() : $name;
if(isset($this->permissions[$name])){ if(isset($this->permissions[$name])){
unset($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)]);
} }
} }

View File

@ -25,5 +25,5 @@ namespace pocketmine\permission;
interface PermissionRemovedExecutor{ interface PermissionRemovedExecutor{
public function attachmentRemoved(PermissionAttachment $attachment) : void; public function attachmentRemoved(Permissible $permissible, PermissionAttachment $attachment) : void;
} }