mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-09 03:06:55 +00:00
PluginManager: Improved startup performance when loading many plugins
for some reason we were reading and parsing the plugin.yml at least twice for every plugin loaded. We were repeating work already done by the initial loadPlugins() triage (discovering correct loader, loading plugin.yml from disk, parsing plugin.yml, validating plugin.yml) every time loadPlugin() was called with that plugin.
This commit is contained in:
@ -178,77 +178,7 @@ class PluginManager{
|
||||
if($loader->canLoadPlugin($path)){
|
||||
$description = $loader->getPluginDescription($path);
|
||||
if($description instanceof PluginDescription){
|
||||
$language = $this->server->getLanguage();
|
||||
$this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_load($description->getFullName())));
|
||||
|
||||
$dataFolder = $this->getDataDirectory($path, $description->getName());
|
||||
if(file_exists($dataFolder) and !is_dir($dataFolder)){
|
||||
$this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError(
|
||||
$description->getName(),
|
||||
KnownTranslationFactory::pocketmine_plugin_badDataFolder($dataFolder)
|
||||
)));
|
||||
return null;
|
||||
}
|
||||
if(!file_exists($dataFolder)){
|
||||
mkdir($dataFolder, 0777, true);
|
||||
}
|
||||
|
||||
$prefixed = $loader->getAccessProtocol() . $path;
|
||||
$loader->loadPlugin($prefixed);
|
||||
|
||||
$mainClass = $description->getMain();
|
||||
if(!class_exists($mainClass, true)){
|
||||
$this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError(
|
||||
$description->getName(),
|
||||
KnownTranslationFactory::pocketmine_plugin_mainClassNotFound()
|
||||
)));
|
||||
return null;
|
||||
}
|
||||
if(!is_a($mainClass, Plugin::class, true)){
|
||||
$this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError(
|
||||
$description->getName(),
|
||||
KnownTranslationFactory::pocketmine_plugin_mainClassWrongType(Plugin::class)
|
||||
)));
|
||||
return null;
|
||||
}
|
||||
|
||||
$permManager = PermissionManager::getInstance();
|
||||
$opRoot = $permManager->getPermission(DefaultPermissions::ROOT_OPERATOR);
|
||||
$everyoneRoot = $permManager->getPermission(DefaultPermissions::ROOT_USER);
|
||||
foreach($description->getPermissions() as $default => $perms){
|
||||
foreach($perms as $perm){
|
||||
$permManager->addPermission($perm);
|
||||
switch($default){
|
||||
case PermissionParser::DEFAULT_TRUE:
|
||||
$everyoneRoot->addChild($perm->getName(), true);
|
||||
break;
|
||||
case PermissionParser::DEFAULT_OP:
|
||||
$opRoot->addChild($perm->getName(), true);
|
||||
break;
|
||||
case PermissionParser::DEFAULT_NOT_OP:
|
||||
//TODO: I don't think anyone uses this, and it currently relies on some magic inside PermissibleBase
|
||||
//to ensure that the operator override actually applies.
|
||||
//Explore getting rid of this.
|
||||
//The following grants this permission to anyone who has the "everyone" root permission.
|
||||
//However, if the operator root node (which has higher priority) is present, the
|
||||
//permission will be denied instead.
|
||||
$everyoneRoot->addChild($perm->getName(), true);
|
||||
$opRoot->addChild($perm->getName(), false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Plugin $plugin
|
||||
* @see Plugin::__construct()
|
||||
*/
|
||||
$plugin = new $mainClass($loader, $this->server, $description, $dataFolder, $prefixed, new DiskResourceProvider($prefixed . "/resources/"));
|
||||
$this->plugins[$plugin->getDescription()->getName()] = $plugin;
|
||||
|
||||
return $plugin;
|
||||
$this->internalLoadPlugin($path, $loader, $description);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -256,6 +186,80 @@ class PluginManager{
|
||||
return null;
|
||||
}
|
||||
|
||||
private function internalLoadPlugin(string $path, PluginLoader $loader, PluginDescription $description) : ?Plugin{
|
||||
$language = $this->server->getLanguage();
|
||||
$this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_load($description->getFullName())));
|
||||
|
||||
$dataFolder = $this->getDataDirectory($path, $description->getName());
|
||||
if(file_exists($dataFolder) and !is_dir($dataFolder)){
|
||||
$this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError(
|
||||
$description->getName(),
|
||||
KnownTranslationFactory::pocketmine_plugin_badDataFolder($dataFolder)
|
||||
)));
|
||||
return null;
|
||||
}
|
||||
if(!file_exists($dataFolder)){
|
||||
mkdir($dataFolder, 0777, true);
|
||||
}
|
||||
|
||||
$prefixed = $loader->getAccessProtocol() . $path;
|
||||
$loader->loadPlugin($prefixed);
|
||||
|
||||
$mainClass = $description->getMain();
|
||||
if(!class_exists($mainClass, true)){
|
||||
$this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError(
|
||||
$description->getName(),
|
||||
KnownTranslationFactory::pocketmine_plugin_mainClassNotFound()
|
||||
)));
|
||||
return null;
|
||||
}
|
||||
if(!is_a($mainClass, Plugin::class, true)){
|
||||
$this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError(
|
||||
$description->getName(),
|
||||
KnownTranslationFactory::pocketmine_plugin_mainClassWrongType(Plugin::class)
|
||||
)));
|
||||
return null;
|
||||
}
|
||||
|
||||
$permManager = PermissionManager::getInstance();
|
||||
$opRoot = $permManager->getPermission(DefaultPermissions::ROOT_OPERATOR);
|
||||
$everyoneRoot = $permManager->getPermission(DefaultPermissions::ROOT_USER);
|
||||
foreach($description->getPermissions() as $default => $perms){
|
||||
foreach($perms as $perm){
|
||||
$permManager->addPermission($perm);
|
||||
switch($default){
|
||||
case PermissionParser::DEFAULT_TRUE:
|
||||
$everyoneRoot->addChild($perm->getName(), true);
|
||||
break;
|
||||
case PermissionParser::DEFAULT_OP:
|
||||
$opRoot->addChild($perm->getName(), true);
|
||||
break;
|
||||
case PermissionParser::DEFAULT_NOT_OP:
|
||||
//TODO: I don't think anyone uses this, and it currently relies on some magic inside PermissibleBase
|
||||
//to ensure that the operator override actually applies.
|
||||
//Explore getting rid of this.
|
||||
//The following grants this permission to anyone who has the "everyone" root permission.
|
||||
//However, if the operator root node (which has higher priority) is present, the
|
||||
//permission will be denied instead.
|
||||
$everyoneRoot->addChild($perm->getName(), true);
|
||||
$opRoot->addChild($perm->getName(), false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Plugin $plugin
|
||||
* @see Plugin::__construct()
|
||||
*/
|
||||
$plugin = new $mainClass($loader, $this->server, $description, $dataFolder, $prefixed, new DiskResourceProvider($prefixed . "/resources/"));
|
||||
$this->plugins[$plugin->getDescription()->getName()] = $plugin;
|
||||
|
||||
return $plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[]|null $newLoaders
|
||||
* @phpstan-param list<class-string<PluginLoader>> $newLoaders
|
||||
@ -330,7 +334,7 @@ class PluginManager{
|
||||
)));
|
||||
continue;
|
||||
}
|
||||
$plugins[$name] = $file;
|
||||
$plugins[$name] = new PluginLoadTriageEntry($file, $loader, $description);
|
||||
|
||||
$softDependencies[$name] = array_merge($softDependencies[$name] ?? [], $description->getSoftDepend());
|
||||
$dependencies[$name] = $description->getDepend();
|
||||
@ -347,7 +351,7 @@ class PluginManager{
|
||||
|
||||
while(count($plugins) > 0){
|
||||
$loadedThisLoop = 0;
|
||||
foreach($plugins as $name => $file){
|
||||
foreach($plugins as $name => $entry){
|
||||
if(isset($dependencies[$name])){
|
||||
foreach($dependencies[$name] as $key => $dependency){
|
||||
if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){
|
||||
@ -389,7 +393,7 @@ class PluginManager{
|
||||
if(!isset($dependencies[$name]) and !isset($softDependencies[$name])){
|
||||
unset($plugins[$name]);
|
||||
$loadedThisLoop++;
|
||||
if(($plugin = $this->loadPlugin($file, $loaders)) instanceof Plugin){
|
||||
if(($plugin = $this->internalLoadPlugin($entry->getFile(), $entry->getLoader(), $entry->getDescription())) instanceof Plugin){
|
||||
$loadedPlugins[$name] = $plugin;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user