From 25ff90b2c6880f1179210b8da073d89aadc44d5e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 16 Aug 2019 16:46:59 +0100 Subject: [PATCH] PluginManager: fix chained softdepend plugins load order Test case: - plugin2 depends on nonexistent plugin1 - plugin3 depends on plugin2 At random occasions, plugin3 would be loaded before plugin2, because plugin2 load would be deferred in the expectation of plugin1 being loaded. This would result in the assumption that plugin3's softdepend plugins would not be loaded, so they were ignored. We fix this problem by removing missing plugins from softdepend if they were not present on a scan of the directory. This way, we don't ignore any unresolved deferred dependency resolutions. --- src/pocketmine/plugin/PluginManager.php | 34 ++++++++++--------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/pocketmine/plugin/PluginManager.php b/src/pocketmine/plugin/PluginManager.php index 7936542fd..ee92644b3 100644 --- a/src/pocketmine/plugin/PluginManager.php +++ b/src/pocketmine/plugin/PluginManager.php @@ -305,7 +305,7 @@ class PluginManager{ while(count($plugins) > 0){ - $missingDependency = true; + $loadedThisLoop = 0; foreach($plugins as $name => $file){ if(isset($dependencies[$name])){ foreach($dependencies[$name] as $key => $dependency){ @@ -329,7 +329,14 @@ class PluginManager{ if(isset($softDependencies[$name])){ foreach($softDependencies[$name] as $key => $dependency){ if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){ + $this->server->getLogger()->debug("Successfully resolved soft dependency \"$dependency\" for plugin \"$name\""); unset($softDependencies[$name][$key]); + }elseif(!isset($plugins[$dependency])){ + //this dependency is never going to be resolved, so don't bother trying + $this->server->getLogger()->debug("Skipping resolution of missing soft dependency \"$dependency\" for plugin \"$name\""); + unset($softDependencies[$name][$key]); + }else{ + $this->server->getLogger()->debug("Deferring resolution of soft dependency \"$dependency\" for plugin \"$name\" (found but not loaded yet)"); } } @@ -340,7 +347,7 @@ class PluginManager{ if(!isset($dependencies[$name]) and !isset($softDependencies[$name])){ unset($plugins[$name]); - $missingDependency = false; + $loadedThisLoop++; if($plugin = $this->loadPlugin($file, $loaders) and $plugin instanceof Plugin){ $loadedPlugins[$name] = $plugin; }else{ @@ -349,27 +356,12 @@ class PluginManager{ } } - if($missingDependency){ - foreach($plugins as $name => $file){ - if(!isset($dependencies[$name])){ - unset($softDependencies[$name]); - unset($plugins[$name]); - $missingDependency = false; - if($plugin = $this->loadPlugin($file, $loaders) and $plugin instanceof Plugin){ - $loadedPlugins[$name] = $plugin; - }else{ - $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.genericLoadError", [$name])); - } - } - } - + if($loadedThisLoop === 0){ //No plugins loaded :( - if($missingDependency){ - foreach($plugins as $name => $file){ - $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [$name, "%pocketmine.plugin.circularDependency"])); - } - $plugins = []; + foreach($plugins as $name => $file){ + $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [$name, "%pocketmine.plugin.circularDependency"])); } + $plugins = []; } }