PocketMine-MP 5.15.1 git-be6754494fdbbb9dd57c058ba0e33a4a78c4581f
PermissibleInternal.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\permission;
25
31use function count;
32use function spl_object_id;
33
47 private array $rootPermissions;
48
50 private array $attachments = [];
51
53 private array $permissions = [];
54
59 private ObjectSet $permissionRecalculationCallbacks;
60
65 public function __construct(array $basePermissions){
66 $this->permissionRecalculationCallbacks = new ObjectSet();
67
68 $this->rootPermissions = $basePermissions;
70 }
71
72 public function setBasePermission(Permission|string $name, bool $grant) : void{
73 if($name instanceof Permission){
74 $name = $name->getName();
75 }
76 $this->rootPermissions[$name] = $grant;
78 }
79
80 public function unsetBasePermission(Permission|string $name) : void{
81 unset($this->rootPermissions[$name instanceof Permission ? $name->getName() : $name]);
82 $this->recalculatePermissions();
83 }
84
85 public function isPermissionSet(Permission|string $name) : bool{
86 return isset($this->permissions[$name instanceof Permission ? $name->getName() : $name]);
87 }
88
89 public function hasPermission(Permission|string $name) : bool{
90 if($name instanceof Permission){
91 $name = $name->getName();
92 }
93
94 if($this->isPermissionSet($name)){
95 return $this->permissions[$name]->getValue();
96 }
97
98 return false;
99 }
100
104 public function addAttachment(Plugin $plugin, ?string $name = null, ?bool $value = null) : PermissionAttachment{
105 if(!$plugin->isEnabled()){
106 throw new PluginException("Plugin " . $plugin->getDescription()->getName() . " is disabled");
107 }
108
109 $result = new PermissionAttachment($plugin);
110 $this->attachments[spl_object_id($result)] = $result;
111 if($name !== null && $value !== null){
112 $result->setPermission($name, $value);
113 }
114
115 $result->subscribePermissible($this);
116
117 $this->recalculatePermissions();
118
119 return $result;
120 }
121
122 public function removeAttachment(PermissionAttachment $attachment) : void{
123 if(isset($this->attachments[spl_object_id($attachment)])){
124 unset($this->attachments[spl_object_id($attachment)]);
125 $attachment->unsubscribePermissible($this);
126
127 $this->recalculatePermissions();
128
129 }
130
131 }
132
133 public function recalculatePermissions() : array{
134 Timings::$permissibleCalculation->startTiming();
135
136 $permManager = PermissionManager::getInstance();
137 $permManager->unsubscribeFromAllPermissions($this);
138 $oldPermissions = $this->permissions;
139 $this->permissions = [];
140
141 foreach(Utils::stringifyKeys($this->rootPermissions) as $name => $isGranted){
142 $perm = $permManager->getPermission($name);
143 if($perm === null){
144 throw new \LogicException("Unregistered root permission $name");
145 }
146 $this->permissions[$name] = new PermissionAttachmentInfo($name, null, $isGranted, null);
147 $permManager->subscribeToPermission($name, $this);
148 $this->calculateChildPermissions($perm->getChildren(), !$isGranted, null, $this->permissions[$name]);
149 }
150
151 foreach($this->attachments as $attachment){
152 $this->calculateChildPermissions($attachment->getPermissions(), false, $attachment, null);
153 }
154
155 $diff = [];
156 Timings::$permissibleCalculationDiff->time(function() use ($oldPermissions, &$diff) : void{
157 foreach($this->permissions as $permissionAttachmentInfo){
158 $name = $permissionAttachmentInfo->getPermission();
159 if(!isset($oldPermissions[$name])){
160 $diff[$name] = false;
161 }elseif($oldPermissions[$name]->getValue() !== $permissionAttachmentInfo->getValue()){
162 continue;
163 }
164 unset($oldPermissions[$name]);
165 }
166 //oldPermissions now only contains permissions that changed or are no longer set
167 foreach($oldPermissions as $permissionAttachmentInfo){
168 $diff[$permissionAttachmentInfo->getPermission()] = $permissionAttachmentInfo->getValue();
169 }
170 });
171
172 Timings::$permissibleCalculationCallback->time(function() use ($diff) : void{
173 if(count($diff) > 0){
174 foreach($this->permissionRecalculationCallbacks as $closure){
175 $closure($diff);
176 }
177 }
178 });
179
180 Timings::$permissibleCalculation->stopTiming();
181 return $diff;
182 }
183
188 private function calculateChildPermissions(array $children, bool $invert, ?PermissionAttachment $attachment, ?PermissionAttachmentInfo $parent) : void{
189 $permManager = PermissionManager::getInstance();
190 foreach(Utils::stringifyKeys($children) as $name => $v){
191 $perm = $permManager->getPermission($name);
192 $value = ($v xor $invert);
193 $this->permissions[$name] = new PermissionAttachmentInfo($name, $attachment, $value, $parent);
194 $permManager->subscribeToPermission($name, $this);
195
196 if($perm instanceof Permission){
197 $this->calculateChildPermissions($perm->getChildren(), !$value, $attachment, $this->permissions[$name]);
198 }
199 }
200 }
201
206 public function getPermissionRecalculationCallbacks() : ObjectSet{ return $this->permissionRecalculationCallbacks; }
207
211 public function getEffectivePermissions() : array{
212 return $this->permissions;
213 }
214
215 public function destroyCycles() : void{
216 PermissionManager::getInstance()->unsubscribeFromAllPermissions($this);
217 $this->permissions = []; //PermissionAttachmentInfo doesn't reference Permissible anymore, but it references PermissionAttachment which does
218 foreach($this->attachments as $attachment){
219 $attachment->unsubscribePermissible($this);
220 }
221 $this->attachments = [];
222 $this->permissionRecalculationCallbacks->clear();
223 }
224}
addAttachment(Plugin $plugin, ?string $name=null, ?bool $value=null)
setBasePermission(Permission|string $name, bool $grant)