Merge branch 'master' of github.com:pmmp/PocketMine-MP

This commit is contained in:
Dylan K. Taylor 2021-10-20 21:23:14 +01:00
commit fecc13f362
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
3 changed files with 150 additions and 59 deletions

View File

@ -0,0 +1,42 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\plugin;
final class PluginLoadTriage{
/**
* @var PluginLoadTriageEntry[]
* @phpstan-var array<string, PluginLoadTriageEntry>
*/
public $plugins = [];
/**
* @var string[][]
* @phpstan-var array<string, list<string>>
*/
public $dependencies = [];
/**
* @var string[][]
* @phpstan-var array<string, list<string>>
*/
public $softDependencies = [];
}

View File

@ -44,7 +44,10 @@ use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\Utils;
use pocketmine\utils\VersionString;
use Webmozart\PathUtil\Path;
use function array_diff_assoc;
use function array_intersect;
use function array_key_exists;
use function array_keys;
use function array_merge;
use function class_exists;
use function count;
@ -265,18 +268,12 @@ class PluginManager{
/**
* @param string[]|null $newLoaders
* @phpstan-param list<class-string<PluginLoader>> $newLoaders
*
* @return Plugin[]
*/
public function loadPlugins(string $directory, ?array $newLoaders = null) : array{
private function triagePlugins(string $directory, PluginLoadTriage $triage, ?array $newLoaders = null) : void{
if(!is_dir($directory)){
return [];
return;
}
$plugins = [];
$loadedPlugins = [];
$dependencies = [];
$softDependencies = [];
if(is_array($newLoaders)){
$loaders = [];
foreach($newLoaders as $key){
@ -320,7 +317,7 @@ class PluginManager{
continue;
}
if(isset($plugins[$name]) or $this->getPlugin($name) instanceof Plugin){
if(isset($triage->plugins[$name]) or $this->getPlugin($name) instanceof Plugin){
$this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_duplicateError($name)));
continue;
}
@ -336,77 +333,129 @@ class PluginManager{
)));
continue;
}
$plugins[$name] = new PluginLoadTriageEntry($file, $loader, $description);
$softDependencies[$name] = array_merge($softDependencies[$name] ?? [], $description->getSoftDepend());
$dependencies[$name] = $description->getDepend();
$triage->plugins[$name] = new PluginLoadTriageEntry($file, $loader, $description);
$triage->softDependencies[$name] = array_merge($triage->softDependencies[$name] ?? [], $description->getSoftDepend());
$triage->dependencies[$name] = $description->getDepend();
foreach($description->getLoadBefore() as $before){
if(isset($softDependencies[$before])){
$softDependencies[$before][] = $name;
if(isset($triage->softDependencies[$before])){
$triage->softDependencies[$before][] = $name;
}else{
$softDependencies[$before] = [$name];
$triage->softDependencies[$before] = [$name];
}
}
}
}
}
while(count($plugins) > 0){
/**
* @param string[][] $dependencyLists
* @param Plugin[] $loadedPlugins
*/
private function checkDepsForTriage(string $pluginName, string $dependencyType, array &$dependencyLists, array $loadedPlugins, PluginLoadTriage $triage) : void{
if(isset($dependencyLists[$pluginName])){
foreach($dependencyLists[$pluginName] as $key => $dependency){
if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){
$this->server->getLogger()->debug("Successfully resolved $dependencyType dependency \"$dependency\" for plugin \"$pluginName\"");
unset($dependencyLists[$pluginName][$key]);
}elseif(array_key_exists($dependency, $triage->plugins)){
$this->server->getLogger()->debug("Deferring resolution of $dependencyType dependency \"$dependency\" for plugin \"$pluginName\" (found but not loaded yet)");
}
}
if(count($dependencyLists[$pluginName]) === 0){
unset($dependencyLists[$pluginName]);
}
}
}
/**
* @return Plugin[]
*/
public function loadPlugins(string $directory) : array{
$triage = new PluginLoadTriage();
$this->triagePlugins($directory, $triage);
$loadedPlugins = [];
while(count($triage->plugins) > 0){
$loadedThisLoop = 0;
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){
unset($dependencies[$name][$key]);
}elseif(!isset($plugins[$dependency])){
$this->server->getLogger()->critical($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError(
$name,
KnownTranslationFactory::pocketmine_plugin_unknownDependency($dependency)
)));
unset($plugins[$name]);
continue 2;
}
}
foreach($triage->plugins as $name => $entry){
$this->checkDepsForTriage($name, "hard", $triage->dependencies, $loadedPlugins, $triage);
$this->checkDepsForTriage($name, "soft", $triage->softDependencies, $loadedPlugins, $triage);
if(count($dependencies[$name]) === 0){
unset($dependencies[$name]);
}
}
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)");
}
}
if(count($softDependencies[$name]) === 0){
unset($softDependencies[$name]);
}
}
if(!isset($dependencies[$name]) and !isset($softDependencies[$name])){
unset($plugins[$name]);
if(!isset($triage->dependencies[$name]) and !isset($triage->softDependencies[$name])){
unset($triage->plugins[$name]);
$loadedThisLoop++;
$oldRegisteredLoaders = $this->fileAssociations;
if(($plugin = $this->internalLoadPlugin($entry->getFile(), $entry->getLoader(), $entry->getDescription())) instanceof Plugin){
$loadedPlugins[$name] = $plugin;
$diffLoaders = [];
foreach($this->fileAssociations as $k => $loader){
if(!array_key_exists($k, $oldRegisteredLoaders)){
$diffLoaders[] = $k;
}
}
if(count($diffLoaders) !== 0){
$this->server->getLogger()->debug("Plugin $name registered a new plugin loader during load, scanning for new plugins");
$plugins = $triage->plugins;
$this->triagePlugins($directory, $triage, $diffLoaders);
$diffPlugins = array_diff_assoc($triage->plugins, $plugins);
$this->server->getLogger()->debug("Re-triage found plugins: " . implode(", ", array_keys($diffPlugins)));
}
}
}
}
if($loadedThisLoop === 0){
//No plugins loaded :(
foreach($plugins as $name => $file){
//check for skippable soft dependencies first, in case the dependents could resolve hard dependencies
foreach($triage->plugins as $name => $file){
if(isset($triage->softDependencies[$name]) && !isset($triage->dependencies[$name])){
foreach($triage->softDependencies[$name] as $k => $dependency){
if($this->getPlugin($dependency) === null && !array_key_exists($dependency, $triage->plugins)){
$this->server->getLogger()->debug("Skipping resolution of missing soft dependency \"$dependency\" for plugin \"$name\"");
unset($triage->softDependencies[$name][$k]);
}
}
if(count($triage->softDependencies[$name]) === 0){
unset($triage->softDependencies[$name]);
continue 2; //go back to the top and try again
}
}
}
foreach($triage->plugins as $name => $file){
if(isset($triage->dependencies[$name])){
$unknownDependencies = [];
foreach($triage->dependencies[$name] as $k => $dependency){
if($this->getPlugin($dependency) === null && !array_key_exists($dependency, $triage->plugins)){
//assume that the plugin is never going to be loaded
//by this point all soft dependencies have been ignored if they were able to be, so
//there's no chance of this dependency ever being resolved
$unknownDependencies[$dependency] = $dependency;
}
}
if(count($unknownDependencies) > 0){
$this->server->getLogger()->critical($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError(
$name,
KnownTranslationFactory::pocketmine_plugin_unknownDependency(implode(", ", $unknownDependencies))
)));
unset($triage->plugins[$name]);
}
}
}
foreach($triage->plugins as $name => $file){
$this->server->getLogger()->critical($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError($name, KnownTranslationFactory::pocketmine_plugin_circularDependency())));
}
$plugins = [];
break;
}
}

@ -1 +1 @@
Subproject commit dfbea943e1c64094358acac56013b89065884657
Subproject commit db184c25636b1f984c6539fd4b1729b0b64b35d6