GenisysPro  for Minecraft PE/Windows 10 v1.1.x
Feature-rich server software for Minecraft PE and Windows 10 Edition
PluginManager Class Reference

Public Member Functions

 __construct (Server $server, SimpleCommandMap $commandMap)
 
 getPlugin ($name)
 
 registerInterface ($loaderName)
 
 getPlugins ()
 
 loadPlugin ($path, $loaders=null)
 
 loadPlugins ($directory, $newLoaders=null)
 
 getPermission ($name)
 
 addPermission (Permission $permission)
 
 removePermission ($permission)
 
 getDefaultPermissions ($op)
 
 recalculatePermissionDefaults (Permission $permission)
 
 subscribeToPermission ($permission, Permissible $permissible)
 
 unsubscribeFromPermission ($permission, Permissible $permissible)
 
 subscribeToDefaultPerms ($op, Permissible $permissible)
 
 unsubscribeFromDefaultPerms ($op, Permissible $permissible)
 
 getPermissions ()
 
 isPluginEnabled (Plugin $plugin)
 
 enablePlugin (Plugin $plugin)
 
 disablePlugins ()
 
 disablePlugin (Plugin $plugin)
 
 clearPlugins ()
 
 callEvent (Event $event)
 
 registerEvents (Listener $listener, Plugin $plugin)
 
 registerEvent ($event, Listener $listener, $priority, EventExecutor $executor, Plugin $plugin, $ignoreCancelled=false)
 
 useTimings ()
 
 setUseTimings ($use)
 

Static Public Attributes

static $pluginParentTimer
 
static $useTimings = false
 

Protected Member Functions

 parseYamlCommands (Plugin $plugin)
 

Protected Attributes

 $plugins = []
 
 $permissions = []
 
 $defaultPerms = []
 
 $defaultPermsOp = []
 
 $permSubs = []
 
 $defSubs = []
 
 $defSubsOp = []
 
 $fileAssociations = []
 

Detailed Description

Manages all the plugins, Permissions and Permissibles

Constructor & Destructor Documentation

◆ __construct()

__construct ( Server  $server,
SimpleCommandMap  $commandMap 
)
Parameters
Server$server
SimpleCommandMap$commandMap
106  {
107  $this->server = $server;
108  $this->commandMap = $commandMap;
109  }

Member Function Documentation

◆ addPermission()

addPermission ( Permission  $permission)
Parameters
Permission$permission
Returns
bool
406  {
407  if(!isset($this->permissions[$permission->getName()])){
408  $this->permissions[$permission->getName()] = $permission;
409  $this->calculatePermissionDefault($permission);
410 
411  return true;
412  }
413 
414  return false;
415  }

◆ callEvent()

callEvent ( Event  $event)

Calls an event

Parameters
Event$event
711  {
712  foreach($event->getHandlers()->getRegisteredListeners() as $registration){
713  if(!$registration->getPlugin()->isEnabled()){
714  continue;
715  }
716 
717  try{
718  $registration->callEvent($event);
719  }catch(\Throwable $e){
720  $this->server->getLogger()->critical(
721  $this->server->getLanguage()->translateString("pocketmine.plugin.eventError", [
722  $event->getEventName(),
723  $registration->getPlugin()->getDescription()->getFullName(),
724  $e->getMessage(),
725  get_class($registration->getListener())
726  ]));
727  $this->server->getLogger()->logException($e);
728  }
729  }
730  }

◆ clearPlugins()

clearPlugins ( )
697  {
698  $this->disablePlugins();
699  $this->plugins = [];
700  $this->fileAssociations = [];
701  $this->permissions = [];
702  $this->defaultPerms = [];
703  $this->defaultPermsOp = [];
704  }

◆ disablePlugin()

disablePlugin ( Plugin  $plugin)
Parameters
Plugin$plugin
681  {
682  if($plugin->isEnabled()){
683  try{
684  $plugin->getPluginLoader()->disablePlugin($plugin);
685  }catch(\Throwable $e){
686  $this->server->getLogger()->logException($e);
687  }
688 
689  $this->server->getScheduler()->cancelTasks($plugin);
691  foreach($plugin->getDescription()->getPermissions() as $perm){
692  $this->removePermission($perm);
693  }
694  }
695  }

◆ disablePlugins()

disablePlugins ( )
672  {
673  foreach($this->getPlugins() as $plugin){
674  $this->disablePlugin($plugin);
675  }
676  }

◆ enablePlugin()

enablePlugin ( Plugin  $plugin)
Parameters
Plugin$plugin
607  {
608  if(!$plugin->isEnabled()){
609  try{
610  foreach($plugin->getDescription()->getPermissions() as $perm){
611  $this->addPermission($perm);
612  }
613  $plugin->getPluginLoader()->enablePlugin($plugin);
614  }catch(\Throwable $e){
615  $this->server->getLogger()->logException($e);
616  $this->disablePlugin($plugin);
617  }
618  }
619  }

◆ getDefaultPermissions()

getDefaultPermissions (   $op)
Parameters
bool$op
Returns
Permission[]
433  {
434  if($op === true){
435  return $this->defaultPermsOp;
436  }else{
437  return $this->defaultPerms;
438  }
439  }

◆ getPermission()

getPermission (   $name)
Parameters
string$name
Returns
null|Permission
393  {
394  if(isset($this->permissions[$name])){
395  return $this->permissions[$name];
396  }
397 
398  return null;
399  }

◆ getPermissions()

getPermissions ( )
Returns
Permission[]
587  {
588  return $this->permissions;
589  }

◆ getPlugin()

getPlugin (   $name)
Parameters
string$name
Returns
null|Plugin
116  {
117  if(isset($this->plugins[$name])){
118  return $this->plugins[$name];
119  }
120 
121  return null;
122  }

◆ getPlugins()

getPlugins ( )
Returns
Plugin[]
144  {
145  return $this->plugins;
146  }

◆ isPluginEnabled()

isPluginEnabled ( Plugin  $plugin)
Parameters
Plugin$plugin
Returns
bool
596  {
597  if($plugin instanceof Plugin and isset($this->plugins[$plugin->getDescription()->getName()])){
598  return $plugin->isEnabled();
599  }else{
600  return false;
601  }
602  }

◆ loadPlugin()

loadPlugin (   $path,
  $loaders = null 
)
Parameters
string$path
PluginLoader[]$loaders
Returns
Plugin
154  {
155  foreach(($loaders === null ? $this->fileAssociations : $loaders) as $loader){
156  if(preg_match($loader->getPluginFilters(), basename($path)) > 0){
157  $description = $loader->getPluginDescription($path);
158  if($description instanceof PluginDescription){
159  if(($plugin = $loader->loadPlugin($path)) instanceof Plugin){
160  $this->plugins[$plugin->getDescription()->getName()] = $plugin;
161 
162  $pluginCommands = $this->parseYamlCommands($plugin);
163 
164  if(count($pluginCommands) > 0){
165  $this->commandMap->registerAll($plugin->getDescription()->getName(), $pluginCommands);
166  }
167 
168  return $plugin;
169  }
170  }
171  }
172  }
173 
174  return null;
175  }

◆ loadPlugins()

loadPlugins (   $directory,
  $newLoaders = null 
)
Parameters
string$directory
array$newLoaders
Returns
Plugin[]
183  {
184 
185  if(is_dir($directory)){
186  $plugins = [];
187  $loadedPlugins = [];
188  $dependencies = [];
189  $softDependencies = [];
190  if(is_array($newLoaders)){
191  $loaders = [];
192  foreach($newLoaders as $key){
193  if(isset($this->fileAssociations[$key])){
194  $loaders[$key] = $this->fileAssociations[$key];
195  }
196  }
197  }else{
198  $loaders = $this->fileAssociations;
199  }
200  foreach($loaders as $loader){
201  foreach(new \RegexIterator(new \DirectoryIterator($directory), $loader->getPluginFilters()) as $file){
202  if($file === "." or $file === ".."){
203  continue;
204  }
205  $file = $directory . $file;
206  try{
207  $description = $loader->getPluginDescription($file);
208  if($description instanceof PluginDescription){
209  $name = $description->getName();
210  if(stripos($name, "pocketmine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){
211  $this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [$name, "%pocketmine.plugin.restrictedName"]));
212  continue;
213  }elseif(strpos($name, " ") !== false){
214  $this->server->getLogger()->warning($this->server->getLanguage()->translateString("pocketmine.plugin.spacesDiscouraged", [$name]));
215  }
216 
217  if(isset($plugins[$name]) or $this->getPlugin($name) instanceof Plugin){
218  $this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.duplicateError", [$name]));
219  continue;
220  }
221 
222  $compatible = false;
223  //Check multiple dependencies
224  foreach($description->getCompatibleApis() as $version){
225  //Format: majorVersion.minorVersion.patch (3.0.0)
226  // or: majorVersion.minorVersion.patch-devBuild (3.0.0-alpha1)
227  if($version !== $this->server->getApiVersion()){
228  $pluginApi = array_pad(explode("-", $version), 2, ""); //0 = version, 1 = suffix (optional)
229  $serverApi = array_pad(explode("-", $this->server->getApiVersion()), 2, "");
230 
231  if(strtoupper($pluginApi[1]) !== strtoupper($serverApi[1])){ //Different release phase (alpha vs. beta) or phase build (alpha.1 vs alpha.2)
232  continue;
233  }
234 
235  $pluginNumbers = array_map("intval", explode(".", $pluginApi[0]));
236  $serverNumbers = array_map("intval", explode(".", $serverApi[0]));
237 
238  if($pluginNumbers[0] !== $serverNumbers[0]){ //Completely different API version
239  continue;
240  }
241 
242  if($pluginNumbers[1] > $serverNumbers[1]){ //If the plugin requires new API features, being backwards compatible
243  continue;
244  }
245  }
246 
247  $compatible = true;
248  break;
249  }
250 
251  $compatiblegeniapi = false;
252  foreach($description->getCompatibleGeniApis() as $version){
253  //Format: majorVersion.minorVersion.patch
254  $version = array_map("intval", explode(".", $version));
255  $apiVersion = array_map("intval", explode(".", $this->server->getGeniApiVersion()));
256  //Completely different API version
257  if($version[0] > $apiVersion[0]){
258  continue;
259  }
260  //If the plugin uses new API
261  if($version[0] < $apiVersion[0]){
262  $compatiblegeniapi = true;
263  break;
264  }
265  //If the plugin requires new API features, being backwards compatible
266  if($version[1] > $apiVersion[1]){
267  continue;
268  }
269 
270  if($version[1] == $apiVersion[1] and $version[2] > $apiVersion[2]){
271  continue;
272  }
273 
274  $compatiblegeniapi = true;
275  break;
276  }
277 
278  if($compatible === false){
279  if($this->server->loadIncompatibleAPI === true){
280  $this->server->getLogger()->debug("插件{$name}的API与服务器不符,但GenisysPro仍然加载了它");
281  }else{
282  $this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [$name, "%pocketmine.plugin.incompatibleAPI"]));
283  continue;
284  }
285  }
286 
287  if($compatiblegeniapi === false){
288  $this->server->getLogger()->error("Could not load plugin '{$description->getName()}': Incompatible GeniAPI version");
289  continue;
290  }
291 
292  $plugins[$name] = $file;
293 
294  $softDependencies[$name] = (array) $description->getSoftDepend();
295  $dependencies[$name] = (array) $description->getDepend();
296 
297  foreach($description->getLoadBefore() as $before){
298  if(isset($softDependencies[$before])){
299  $softDependencies[$before][] = $name;
300  }else{
301  $softDependencies[$before] = [$name];
302  }
303  }
304  }
305  }catch(\Throwable $e){
306  $this->server->getLogger()->error($this->server->getLanguage()->translateString("pocketmine.plugin.fileError", [$file, $directory, $e->getMessage()]));
307  $this->server->getLogger()->logException($e);
308  }
309  }
310  }
311 
312 
313  while(count($plugins) > 0){
314  $missingDependency = true;
315  foreach($plugins as $name => $file){
316  if(isset($dependencies[$name])){
317  foreach($dependencies[$name] as $key => $dependency){
318  if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){
319  unset($dependencies[$name][$key]);
320  }elseif(!isset($plugins[$dependency])){
321  $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [$name, "%pocketmine.plugin.unknownDependency"]));
322  break;
323  }
324  }
325 
326  if(count($dependencies[$name]) === 0){
327  unset($dependencies[$name]);
328  }
329  }
330 
331  if(isset($softDependencies[$name])){
332  foreach($softDependencies[$name] as $key => $dependency){
333  if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){
334  unset($softDependencies[$name][$key]);
335  }
336  }
337 
338  if(count($softDependencies[$name]) === 0){
339  unset($softDependencies[$name]);
340  }
341  }
342 
343  if(!isset($dependencies[$name]) and !isset($softDependencies[$name])){
344  unset($plugins[$name]);
345  $missingDependency = false;
346  if($plugin = $this->loadPlugin($file, $loaders) and $plugin instanceof Plugin){
347  $loadedPlugins[$name] = $plugin;
348  }else{
349  $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.genericLoadError", [$name]));
350  }
351  }
352  }
353 
354  if($missingDependency === true){
355  foreach($plugins as $name => $file){
356  if(!isset($dependencies[$name])){
357  unset($softDependencies[$name]);
358  unset($plugins[$name]);
359  $missingDependency = false;
360  if($plugin = $this->loadPlugin($file, $loaders) and $plugin instanceof Plugin){
361  $loadedPlugins[$name] = $plugin;
362  }else{
363  $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.genericLoadError", [$name]));
364  }
365  }
366  }
367 
368  //No plugins loaded :(
369  if($missingDependency === true){
370  foreach($plugins as $name => $file){
371  $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [$name, "%pocketmine.plugin.circularDependency"]));
372  }
373  $plugins = [];
374  }
375  }
376  }
377 
378  TimingsCommand::$timingStart = microtime(true);
379 
380  return $loadedPlugins;
381  }else{
382  TimingsCommand::$timingStart = microtime(true);
383 
384  return [];
385  }
386  }

◆ parseYamlCommands()

parseYamlCommands ( Plugin  $plugin)
protected
Parameters
Plugin$plugin
Returns
PluginCommand[]
626  {
627  $pluginCmds = [];
628 
629  foreach($plugin->getDescription()->getCommands() as $key => $data){
630  if(strpos($key, ":") !== false){
631  $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.commandError", [$key, $plugin->getDescription()->getFullName()]));
632  continue;
633  }
634  if(is_array($data)){
635  $newCmd = new PluginCommand($key, $plugin);
636  if(isset($data["description"])){
637  $newCmd->setDescription($data["description"]);
638  }
639 
640  if(isset($data["usage"])){
641  $newCmd->setUsage($data["usage"]);
642  }
643 
644  if(isset($data["aliases"]) and is_array($data["aliases"])){
645  $aliasList = [];
646  foreach($data["aliases"] as $alias){
647  if(strpos($alias, ":") !== false){
648  $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.aliasError", [$alias, $plugin->getDescription()->getFullName()]));
649  continue;
650  }
651  $aliasList[] = $alias;
652  }
653 
654  $newCmd->setAliases($aliasList);
655  }
656 
657  if(isset($data["permission"])){
658  $newCmd->setPermission($data["permission"]);
659  }
660 
661  if(isset($data["permission-message"])){
662  $newCmd->setPermissionMessage($data["permission-message"]);
663  }
664 
665  $pluginCmds[] = $newCmd;
666  }
667  }
668 
669  return $pluginCmds;
670  }

◆ recalculatePermissionDefaults()

recalculatePermissionDefaults ( Permission  $permission)
Parameters
Permission$permission
444  {
445  if(isset($this->permissions[$permission->getName()])){
446  unset($this->defaultPermsOp[$permission->getName()]);
447  unset($this->defaultPerms[$permission->getName()]);
448  $this->calculatePermissionDefault($permission);
449  }
450  }

◆ registerEvent()

registerEvent (   $event,
Listener  $listener,
  $priority,
EventExecutor  $executor,
Plugin  $plugin,
  $ignoreCancelled = false 
)
Parameters
string$eventClass name that extends Event
Listener$listener
int$priority
EventExecutor$executor
Plugin$plugin
bool$ignoreCancelled
Exceptions
PluginException
792  {
793  if(!is_subclass_of($event, Event::class)){
794  throw new PluginException($event . " is not an Event");
795  }
796  $class = new \ReflectionClass($event);
797  if($class->isAbstract()){
798  throw new PluginException($event . " is an abstract Event");
799  }
800  if($class->getProperty("handlerList")->getDeclaringClass()->getName() !== $event){
801  throw new PluginException($event . " does not have a handler list");
802  }
803 
804  if(!$plugin->isEnabled()){
805  throw new PluginException("Plugin attempted to register " . $event . " while not enabled");
806  }
807 
808  $timings = new TimingsHandler("Plugin: " . $plugin->getDescription()->getFullName() . " Event: " . get_class($listener) . "::" . ($executor instanceof MethodEventExecutor ? $executor->getMethod() : "???") . "(" . (new \ReflectionClass($event))->getShortName() . ")", self::$pluginParentTimer);
809 
810  $this->getEventListeners($event)->register(new RegisteredListener($listener, $executor, $priority, $plugin, $ignoreCancelled, $timings));
811  }

◆ registerEvents()

registerEvents ( Listener  $listener,
Plugin  $plugin 
)

Registers all the events in the given Listener class

Parameters
Listener$listener
Plugin$plugin
Exceptions
PluginException
740  {
741  if(!$plugin->isEnabled()){
742  throw new PluginException("Plugin attempted to register " . get_class($listener) . " while not enabled");
743  }
744 
745  $reflection = new \ReflectionClass(get_class($listener));
746  foreach($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method){
747  if(!$method->isStatic()){
748  $priority = EventPriority::NORMAL;
749  $ignoreCancelled = false;
750  if(preg_match("/^[\t ]*\\* @priority[\t ]{1,}([a-zA-Z]{1,})/m", (string) $method->getDocComment(), $matches) > 0){
751  $matches[1] = strtoupper($matches[1]);
752  if(defined(EventPriority::class . "::" . $matches[1])){
753  $priority = constant(EventPriority::class . "::" . $matches[1]);
754  }
755  }
756  if(preg_match("/^[\t ]*\\* @ignoreCancelled[\t ]{1,}([a-zA-Z]{1,})/m", (string) $method->getDocComment(), $matches) > 0){
757  $matches[1] = strtolower($matches[1]);
758  if($matches[1] === "false"){
759  $ignoreCancelled = false;
760  }elseif($matches[1] === "true"){
761  $ignoreCancelled = true;
762  }
763  }
764 
765  $parameters = $method->getParameters();
766  if(count($parameters) === 1 and $parameters[0]->getClass() instanceof \ReflectionClass and is_subclass_of($parameters[0]->getClass()->getName(), Event::class)){
767  $class = $parameters[0]->getClass()->getName();
768  $reflection = new \ReflectionClass($class);
769  if(strpos((string) $reflection->getDocComment(), "@deprecated") !== false and $this->server->getProperty("settings.deprecated-verbose", true)){
770  $this->server->getLogger()->warning($this->server->getLanguage()->translateString("pocketmine.plugin.deprecatedEvent", [
771  $plugin->getName(),
772  $class,
773  get_class($listener) . "->" . $method->getName() . "()"
774  ]));
775  }
776  $this->registerEvent($class, $listener, $priority, new MethodEventExecutor($method->getName()), $plugin, $ignoreCancelled);
777  }
778  }
779  }
780  }

◆ registerInterface()

registerInterface (   $loaderName)
Parameters
string$loaderNameA PluginLoader class name
Returns
bool
129  {
130  if(is_subclass_of($loaderName, PluginLoader::class)){
131  $loader = new $loaderName($this->server);
132  }else{
133  return false;
134  }
135 
136  $this->fileAssociations[$loaderName] = $loader;
137 
138  return true;
139  }

◆ removePermission()

removePermission (   $permission)
Parameters
string | Permission$permission
420  {
421  if($permission instanceof Permission){
422  unset($this->permissions[$permission->getName()]);
423  }else{
424  unset($this->permissions[$permission]);
425  }
426  }

◆ setUseTimings()

setUseTimings (   $use)
Parameters
bool$use
836  {
837  self::$useTimings = (bool) $use;
838  }

◆ subscribeToDefaultPerms()

subscribeToDefaultPerms (   $op,
Permissible  $permissible 
)
Parameters
bool$op
Permissible$permissible
531  {
532  if($op === true){
533  $this->defSubsOp[spl_object_hash($permissible)] = $permissible;
534  }else{
535  $this->defSubs[spl_object_hash($permissible)] = $permissible;
536  }
537  }

◆ subscribeToPermission()

subscribeToPermission (   $permission,
Permissible  $permissible 
)
Parameters
string$permission
Permissible$permissible
482  {
483  if(!isset($this->permSubs[$permission])){
484  $this->permSubs[$permission] = [];
485  }
486  $this->permSubs[$permission][spl_object_hash($permissible)] = $permissible;
487  }

◆ unsubscribeFromDefaultPerms()

unsubscribeFromDefaultPerms (   $op,
Permissible  $permissible 
)
Parameters
bool$op
Permissible$permissible
543  {
544  if($op === true){
545  unset($this->defSubsOp[spl_object_hash($permissible)]);
546  }else{
547  unset($this->defSubs[spl_object_hash($permissible)]);
548  }
549  }

◆ unsubscribeFromPermission()

unsubscribeFromPermission (   $permission,
Permissible  $permissible 
)
Parameters
string$permission
Permissible$permissible
493  {
494  if(isset($this->permSubs[$permission])){
495  unset($this->permSubs[$permission][spl_object_hash($permissible)]);
496  if(count($this->permSubs[$permission]) === 0){
497  unset($this->permSubs[$permission]);
498  }
499  }
500  }

◆ useTimings()

useTimings ( )
Returns
bool
829  {
830  return self::$useTimings;
831  }

Field Documentation

◆ $defaultPerms

$defaultPerms = []
protected

◆ $defaultPermsOp

$defaultPermsOp = []
protected

◆ $defSubs

$defSubs = []
protected

◆ $defSubsOp

$defSubsOp = []
protected

◆ $fileAssociations

$fileAssociations = []
protected

◆ $permissions

$permissions = []
protected

◆ $permSubs

$permSubs = []
protected

◆ $pluginParentTimer

$pluginParentTimer
static

◆ $plugins

$plugins = []
protected

◆ $useTimings

$useTimings = false
static

The documentation for this class was generated from the following file: