mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-11 04:17:48 +00:00
Nuke plugin loaders from orbit
This features a near-total rewrite of PluginLoaders and some code associated with them. Highlights: - PluginManager->registerInterface() does not return anything, and now accepts a PluginLoader instance instead of a string. - PluginLoader itself is drastically simplified. getPluginFilters(), enablePlugin() and disablePlugin() are now removed. loadPlugin() responsibilities are now solely confined to doing whatever is necessary to make the plugin's classes visible by the server, and does not emit log messages or check for data directories. - PluginBase->init() and PluginBase->isInitialized() have been removed. - Plugin interface now declares a signature for the constructor which implementations must comply with. - Plugin interface now declares setEnabled().
This commit is contained in:
parent
19d2d6b91c
commit
5a55d434ab
@ -1639,8 +1639,8 @@ class Server{
|
|||||||
$this->pluginManager = new PluginManager($this, $this->commandMap);
|
$this->pluginManager = new PluginManager($this, $this->commandMap);
|
||||||
$this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender);
|
$this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender);
|
||||||
$this->profilingTickRate = (float) $this->getProperty("settings.profile-report-trigger", 20);
|
$this->profilingTickRate = (float) $this->getProperty("settings.profile-report-trigger", 20);
|
||||||
$this->pluginManager->registerInterface(PharPluginLoader::class);
|
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
|
||||||
$this->pluginManager->registerInterface(ScriptPluginLoader::class);
|
$this->pluginManager->registerInterface(new ScriptPluginLoader());
|
||||||
|
|
||||||
register_shutdown_function([$this, "crashDump"]);
|
register_shutdown_function([$this, "crashDump"]);
|
||||||
|
|
||||||
@ -1994,8 +1994,8 @@ class Server{
|
|||||||
$this->getNetwork()->blockAddress($entry->getName(), -1);
|
$this->getNetwork()->blockAddress($entry->getName(), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->pluginManager->registerInterface(PharPluginLoader::class);
|
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
|
||||||
$this->pluginManager->registerInterface(ScriptPluginLoader::class);
|
$this->pluginManager->registerInterface(new ScriptPluginLoader());
|
||||||
$this->pluginManager->loadPlugins($this->pluginPath);
|
$this->pluginManager->loadPlugins($this->pluginPath);
|
||||||
$this->enablePlugins(PluginLoadOrder::STARTUP);
|
$this->enablePlugins(PluginLoadOrder::STARTUP);
|
||||||
$this->enablePlugins(PluginLoadOrder::POSTWORLD);
|
$this->enablePlugins(PluginLoadOrder::POSTWORLD);
|
||||||
|
@ -32,45 +32,25 @@ use pocketmine\Server;
|
|||||||
*/
|
*/
|
||||||
class PharPluginLoader implements PluginLoader{
|
class PharPluginLoader implements PluginLoader{
|
||||||
|
|
||||||
/** @var Server */
|
/** @var \ClassLoader */
|
||||||
private $server;
|
private $loader;
|
||||||
|
|
||||||
/**
|
public function __construct(\ClassLoader $loader){
|
||||||
* @param Server $server
|
$this->loader = $loader;
|
||||||
*/
|
}
|
||||||
public function __construct(Server $server){
|
|
||||||
$this->server = $server;
|
public function canLoadPlugin(string $path) : bool{
|
||||||
|
$ext = ".phar";
|
||||||
|
return is_file($path) and substr($path, -strlen($ext)) === $ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the plugin contained in $file
|
* Loads the plugin contained in $file
|
||||||
*
|
*
|
||||||
* @param string $file
|
* @param string $file
|
||||||
*
|
|
||||||
* @return Plugin|null
|
|
||||||
*/
|
*/
|
||||||
public function loadPlugin(string $file){
|
public function loadPlugin(string $file) : void{
|
||||||
if(($description = $this->getPluginDescription($file)) instanceof PluginDescription){
|
$this->loader->addPath("phar://$file/src");
|
||||||
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.plugin.load", [$description->getFullName()]));
|
|
||||||
$dataFolder = dirname($file) . DIRECTORY_SEPARATOR . $description->getName();
|
|
||||||
if(file_exists($dataFolder) and !is_dir($dataFolder)){
|
|
||||||
throw new \InvalidStateException("Projected dataFolder '" . $dataFolder . "' for " . $description->getName() . " exists and is not a directory");
|
|
||||||
}
|
|
||||||
$file = "phar://$file";
|
|
||||||
$className = $description->getMain();
|
|
||||||
$this->server->getLoader()->addPath("$file/src");
|
|
||||||
|
|
||||||
if(class_exists($className, true)){
|
|
||||||
$plugin = new $className();
|
|
||||||
$this->initPlugin($plugin, $description, $dataFolder, $file);
|
|
||||||
|
|
||||||
return $plugin;
|
|
||||||
}else{
|
|
||||||
throw new PluginException("Couldn't load plugin " . $description->getName() . ": main class not found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,7 +60,7 @@ class PharPluginLoader implements PluginLoader{
|
|||||||
*
|
*
|
||||||
* @return null|PluginDescription
|
* @return null|PluginDescription
|
||||||
*/
|
*/
|
||||||
public function getPluginDescription(string $file){
|
public function getPluginDescription(string $file) : ?PluginDescription{
|
||||||
$phar = new \Phar($file);
|
$phar = new \Phar($file);
|
||||||
if(isset($phar["plugin.yml"])){
|
if(isset($phar["plugin.yml"])){
|
||||||
$pluginYml = $phar["plugin.yml"];
|
$pluginYml = $phar["plugin.yml"];
|
||||||
@ -91,55 +71,4 @@ class PharPluginLoader implements PluginLoader{
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the filename patterns that this loader accepts
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getPluginFilters() : string{
|
|
||||||
return "/\\.phar$/i";
|
|
||||||
}
|
|
||||||
|
|
||||||
public function canLoadPlugin(string $path) : bool{
|
|
||||||
$ext = ".phar";
|
|
||||||
return is_file($path) and substr($path, -strlen($ext)) === $ext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param PluginBase $plugin
|
|
||||||
* @param PluginDescription $description
|
|
||||||
* @param string $dataFolder
|
|
||||||
* @param string $file
|
|
||||||
*/
|
|
||||||
private function initPlugin(PluginBase $plugin, PluginDescription $description, string $dataFolder, string $file){
|
|
||||||
$plugin->init($this, $this->server, $description, $dataFolder, $file);
|
|
||||||
$plugin->onLoad();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Plugin $plugin
|
|
||||||
*/
|
|
||||||
public function enablePlugin(Plugin $plugin){
|
|
||||||
if($plugin instanceof PluginBase and !$plugin->isEnabled()){
|
|
||||||
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.plugin.enable", [$plugin->getDescription()->getFullName()]));
|
|
||||||
|
|
||||||
$plugin->setEnabled(true);
|
|
||||||
|
|
||||||
$this->server->getPluginManager()->callEvent(new PluginEnableEvent($plugin));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Plugin $plugin
|
|
||||||
*/
|
|
||||||
public function disablePlugin(Plugin $plugin){
|
|
||||||
if($plugin instanceof PluginBase and $plugin->isEnabled()){
|
|
||||||
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.plugin.disable", [$plugin->getDescription()->getFullName()]));
|
|
||||||
|
|
||||||
$this->server->getPluginManager()->callEvent(new PluginDisableEvent($plugin));
|
|
||||||
|
|
||||||
$plugin->setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -34,10 +34,11 @@ use pocketmine\utils\Config;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* It is recommended to use PluginBase for the actual plugin
|
* It is recommended to use PluginBase for the actual plugin
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
interface Plugin extends CommandExecutor{
|
interface Plugin extends CommandExecutor{
|
||||||
|
|
||||||
|
public function __construct(PluginLoader $loader, Server $server, PluginDescription $description, string $dataFolder, string $file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the plugin is loaded, before calling onEnable()
|
* Called when the plugin is loaded, before calling onEnable()
|
||||||
*/
|
*/
|
||||||
@ -53,6 +54,11 @@ interface Plugin extends CommandExecutor{
|
|||||||
*/
|
*/
|
||||||
public function isEnabled() : bool;
|
public function isEnabled() : bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $enabled
|
||||||
|
*/
|
||||||
|
public function setEnabled(bool $enabled = true) : void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the plugin is disabled
|
* Called when the plugin is disabled
|
||||||
* Use this to free open things and finish actions
|
* Use this to free open things and finish actions
|
||||||
|
@ -41,9 +41,6 @@ abstract class PluginBase implements Plugin{
|
|||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $isEnabled = false;
|
private $isEnabled = false;
|
||||||
|
|
||||||
/** @var bool */
|
|
||||||
private $initialized = false;
|
|
||||||
|
|
||||||
/** @var PluginDescription */
|
/** @var PluginDescription */
|
||||||
private $description;
|
private $description;
|
||||||
|
|
||||||
@ -62,6 +59,17 @@ abstract class PluginBase implements Plugin{
|
|||||||
/** @var TaskScheduler */
|
/** @var TaskScheduler */
|
||||||
private $scheduler;
|
private $scheduler;
|
||||||
|
|
||||||
|
public function __construct(PluginLoader $loader, Server $server, PluginDescription $description, string $dataFolder, string $file){
|
||||||
|
$this->loader = $loader;
|
||||||
|
$this->server = $server;
|
||||||
|
$this->description = $description;
|
||||||
|
$this->dataFolder = rtrim($dataFolder, "\\/") . "/";
|
||||||
|
$this->file = rtrim($file, "\\/") . "/";
|
||||||
|
$this->configFile = $this->dataFolder . "config.yml";
|
||||||
|
$this->logger = new PluginLogger($this);
|
||||||
|
$this->scheduler = new TaskScheduler($this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the plugin is loaded, before calling onEnable()
|
* Called when the plugin is loaded, before calling onEnable()
|
||||||
*/
|
*/
|
||||||
@ -85,11 +93,11 @@ abstract class PluginBase implements Plugin{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $boolean
|
* @param bool $enabled
|
||||||
*/
|
*/
|
||||||
final public function setEnabled(bool $boolean = true){
|
final public function setEnabled(bool $enabled = true) : void{
|
||||||
if($this->isEnabled !== $boolean){
|
if($this->isEnabled !== $enabled){
|
||||||
$this->isEnabled = $boolean;
|
$this->isEnabled = $enabled;
|
||||||
if($this->isEnabled){
|
if($this->isEnabled){
|
||||||
$this->onEnable();
|
$this->onEnable();
|
||||||
}else{
|
}else{
|
||||||
@ -113,20 +121,6 @@ abstract class PluginBase implements Plugin{
|
|||||||
return $this->description;
|
return $this->description;
|
||||||
}
|
}
|
||||||
|
|
||||||
final public function init(PluginLoader $loader, Server $server, PluginDescription $description, string $dataFolder, string $file){
|
|
||||||
if(!$this->initialized){
|
|
||||||
$this->initialized = true;
|
|
||||||
$this->loader = $loader;
|
|
||||||
$this->server = $server;
|
|
||||||
$this->description = $description;
|
|
||||||
$this->dataFolder = rtrim($dataFolder, "\\/") . "/";
|
|
||||||
$this->file = rtrim($file, "\\/") . "/";
|
|
||||||
$this->configFile = $this->dataFolder . "config.yml";
|
|
||||||
$this->logger = new PluginLogger($this);
|
|
||||||
$this->scheduler = new TaskScheduler($this->logger);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return PluginLogger
|
* @return PluginLogger
|
||||||
*/
|
*/
|
||||||
@ -134,13 +128,6 @@ abstract class PluginBase implements Plugin{
|
|||||||
return $this->logger;
|
return $this->logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
final public function isInitialized() : bool{
|
|
||||||
return $this->initialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
*
|
*
|
||||||
|
@ -28,31 +28,6 @@ namespace pocketmine\plugin;
|
|||||||
*/
|
*/
|
||||||
interface PluginLoader{
|
interface PluginLoader{
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the plugin contained in $file
|
|
||||||
*
|
|
||||||
* @param string $file
|
|
||||||
*
|
|
||||||
* @return Plugin|null
|
|
||||||
*/
|
|
||||||
public function loadPlugin(string $file);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the PluginDescription from the file
|
|
||||||
*
|
|
||||||
* @param string $file
|
|
||||||
*
|
|
||||||
* @return null|PluginDescription
|
|
||||||
*/
|
|
||||||
public function getPluginDescription(string $file);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the filename regex patterns that this loader accepts
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getPluginFilters() : string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this PluginLoader can load the plugin in the given path.
|
* Returns whether this PluginLoader can load the plugin in the given path.
|
||||||
*
|
*
|
||||||
@ -63,18 +38,18 @@ interface PluginLoader{
|
|||||||
public function canLoadPlugin(string $path) : bool;
|
public function canLoadPlugin(string $path) : bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Plugin $plugin
|
* Loads the plugin contained in $file
|
||||||
*
|
*
|
||||||
* @return void
|
* @param string $file
|
||||||
*/
|
*/
|
||||||
public function enablePlugin(Plugin $plugin);
|
public function loadPlugin(string $file) : void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Plugin $plugin
|
* Gets the PluginDescription from the file
|
||||||
*
|
*
|
||||||
* @return void
|
* @param string $file
|
||||||
|
*
|
||||||
|
* @return null|PluginDescription
|
||||||
*/
|
*/
|
||||||
public function disablePlugin(Plugin $plugin);
|
public function getPluginDescription(string $file) : ?PluginDescription;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ use pocketmine\event\Event;
|
|||||||
use pocketmine\event\EventPriority;
|
use pocketmine\event\EventPriority;
|
||||||
use pocketmine\event\HandlerList;
|
use pocketmine\event\HandlerList;
|
||||||
use pocketmine\event\Listener;
|
use pocketmine\event\Listener;
|
||||||
|
use pocketmine\event\plugin\PluginDisableEvent;
|
||||||
|
use pocketmine\event\plugin\PluginEnableEvent;
|
||||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||||
use pocketmine\permission\Permissible;
|
use pocketmine\permission\Permissible;
|
||||||
use pocketmine\permission\Permission;
|
use pocketmine\permission\Permission;
|
||||||
@ -118,20 +120,10 @@ class PluginManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $loaderName A PluginLoader class name
|
* @param PluginLoader $loader
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function registerInterface(string $loaderName) : bool{
|
public function registerInterface(PluginLoader $loader) : void{
|
||||||
if(is_subclass_of($loaderName, PluginLoader::class)){
|
$this->fileAssociations[get_class($loader)] = $loader;
|
||||||
$loader = new $loaderName($this->server);
|
|
||||||
}else{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->fileAssociations[$loaderName] = $loader;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -147,11 +139,12 @@ class PluginManager{
|
|||||||
*
|
*
|
||||||
* @return Plugin|null
|
* @return Plugin|null
|
||||||
*/
|
*/
|
||||||
public function loadPlugin(string $path, array $loaders = null){
|
public function loadPlugin(string $path, array $loaders = null) : ?Plugin{
|
||||||
foreach($loaders ?? $this->fileAssociations as $loader){
|
foreach($loaders ?? $this->fileAssociations as $loader){
|
||||||
if(preg_match($loader->getPluginFilters(), basename($path)) > 0){
|
if($loader->canLoadPlugin($path)){
|
||||||
$description = $loader->getPluginDescription($path);
|
$description = $loader->getPluginDescription($path);
|
||||||
if($description instanceof PluginDescription){
|
if($description instanceof PluginDescription){
|
||||||
|
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.plugin.load", [$description->getFullName()]));
|
||||||
try{
|
try{
|
||||||
$description->checkRequiredExtensions();
|
$description->checkRequiredExtensions();
|
||||||
}catch(PluginException $ex){
|
}catch(PluginException $ex){
|
||||||
@ -159,8 +152,31 @@ class PluginManager{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dataFolder = dirname($path) . DIRECTORY_SEPARATOR . $description->getName();
|
||||||
|
if(file_exists($dataFolder) and !is_dir($dataFolder)){
|
||||||
|
$this->server->getLogger()->error("Projected dataFolder '" . $dataFolder . "' for " . $description->getName() . " exists and is not a directory");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$loader->loadPlugin($path);
|
||||||
|
|
||||||
|
$mainClass = $description->getMain();
|
||||||
|
if(!class_exists($mainClass, true)){
|
||||||
|
$this->server->getLogger()->error("Main class for plugin " . $description->getName() . " not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if(!is_a($mainClass, Plugin::class, true)){
|
||||||
|
$this->server->getLogger()->error("Main class for plugin " . $description->getName() . " is not an instance of " . Plugin::class);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
if(($plugin = $loader->loadPlugin($path)) instanceof Plugin){
|
/**
|
||||||
|
* @var Plugin $plugin
|
||||||
|
* @see Plugin::__construct()
|
||||||
|
*/
|
||||||
|
$plugin = new $mainClass($loader, $this->server, $description, $dataFolder, $path);
|
||||||
|
$plugin->onLoad();
|
||||||
$this->plugins[$plugin->getDescription()->getName()] = $plugin;
|
$this->plugins[$plugin->getDescription()->getName()] = $plugin;
|
||||||
|
|
||||||
$pluginCommands = $this->parseYamlCommands($plugin);
|
$pluginCommands = $this->parseYamlCommands($plugin);
|
||||||
@ -170,7 +186,6 @@ class PluginManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $plugin;
|
return $plugin;
|
||||||
}
|
|
||||||
}catch(\Throwable $e){
|
}catch(\Throwable $e){
|
||||||
$this->server->getLogger()->logException($e);
|
$this->server->getLogger()->logException($e);
|
||||||
return null;
|
return null;
|
||||||
@ -206,7 +221,7 @@ class PluginManager{
|
|||||||
$loaders = $this->fileAssociations;
|
$loaders = $this->fileAssociations;
|
||||||
}
|
}
|
||||||
foreach($loaders as $loader){
|
foreach($loaders as $loader){
|
||||||
foreach(new \RegexIterator(new \DirectoryIterator($directory), $loader->getPluginFilters()) as $file){
|
foreach(new \DirectoryIterator($directory) as $file){
|
||||||
if($file === "." or $file === ".."){
|
if($file === "." or $file === ".."){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -567,11 +582,15 @@ class PluginManager{
|
|||||||
public function enablePlugin(Plugin $plugin){
|
public function enablePlugin(Plugin $plugin){
|
||||||
if(!$plugin->isEnabled()){
|
if(!$plugin->isEnabled()){
|
||||||
try{
|
try{
|
||||||
|
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.plugin.enable", [$plugin->getDescription()->getFullName()]));
|
||||||
|
|
||||||
foreach($plugin->getDescription()->getPermissions() as $perm){
|
foreach($plugin->getDescription()->getPermissions() as $perm){
|
||||||
$this->addPermission($perm);
|
$this->addPermission($perm);
|
||||||
}
|
}
|
||||||
$plugin->getScheduler()->setEnabled(true);
|
$plugin->getScheduler()->setEnabled(true);
|
||||||
$plugin->getPluginLoader()->enablePlugin($plugin);
|
$plugin->setEnabled(true);
|
||||||
|
|
||||||
|
$this->server->getPluginManager()->callEvent(new PluginEnableEvent($plugin));
|
||||||
}catch(\Throwable $e){
|
}catch(\Throwable $e){
|
||||||
$this->server->getLogger()->logException($e);
|
$this->server->getLogger()->logException($e);
|
||||||
$this->disablePlugin($plugin);
|
$this->disablePlugin($plugin);
|
||||||
@ -647,12 +666,14 @@ class PluginManager{
|
|||||||
*/
|
*/
|
||||||
public function disablePlugin(Plugin $plugin){
|
public function disablePlugin(Plugin $plugin){
|
||||||
if($plugin->isEnabled()){
|
if($plugin->isEnabled()){
|
||||||
|
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.plugin.disable", [$plugin->getDescription()->getFullName()]));
|
||||||
|
$this->callEvent(new PluginDisableEvent($plugin));
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$plugin->getPluginLoader()->disablePlugin($plugin);
|
$plugin->setEnabled(false);
|
||||||
}catch(\Throwable $e){
|
}catch(\Throwable $e){
|
||||||
$this->server->getLogger()->logException($e);
|
$this->server->getLogger()->logException($e);
|
||||||
}
|
}
|
||||||
|
|
||||||
$plugin->getScheduler()->shutdown();
|
$plugin->getScheduler()->shutdown();
|
||||||
HandlerList::unregisterAll($plugin);
|
HandlerList::unregisterAll($plugin);
|
||||||
foreach($plugin->getDescription()->getPermissions() as $perm){
|
foreach($plugin->getDescription()->getPermissions() as $perm){
|
||||||
|
@ -33,46 +33,18 @@ use pocketmine\Server;
|
|||||||
*/
|
*/
|
||||||
class ScriptPluginLoader implements PluginLoader{
|
class ScriptPluginLoader implements PluginLoader{
|
||||||
|
|
||||||
/** @var Server */
|
public function canLoadPlugin(string $path) : bool{
|
||||||
private $server;
|
$ext = ".php";
|
||||||
|
return is_file($path) and substr($path, -strlen($ext)) === $ext;
|
||||||
/**
|
|
||||||
* @param Server $server
|
|
||||||
*/
|
|
||||||
public function __construct(Server $server){
|
|
||||||
$this->server = $server;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the plugin contained in $file
|
* Loads the plugin contained in $file
|
||||||
*
|
*
|
||||||
* @param string $file
|
* @param string $file
|
||||||
*
|
|
||||||
* @return Plugin|null
|
|
||||||
*/
|
*/
|
||||||
public function loadPlugin(string $file){
|
public function loadPlugin(string $file) : void{
|
||||||
if(($description = $this->getPluginDescription($file)) instanceof PluginDescription){
|
include_once $file;
|
||||||
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.plugin.load", [$description->getFullName()]));
|
|
||||||
$dataFolder = dirname($file) . DIRECTORY_SEPARATOR . $description->getName();
|
|
||||||
if(file_exists($dataFolder) and !is_dir($dataFolder)){
|
|
||||||
throw new \InvalidStateException("Projected dataFolder '" . $dataFolder . "' for " . $description->getName() . " exists and is not a directory");
|
|
||||||
}
|
|
||||||
|
|
||||||
include_once($file);
|
|
||||||
|
|
||||||
$className = $description->getMain();
|
|
||||||
|
|
||||||
if(class_exists($className, true)){
|
|
||||||
$plugin = new $className();
|
|
||||||
$this->initPlugin($plugin, $description, $dataFolder, $file);
|
|
||||||
|
|
||||||
return $plugin;
|
|
||||||
}else{
|
|
||||||
throw new PluginException("Couldn't load plugin " . $description->getName() . ": main class not found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,7 +54,7 @@ class ScriptPluginLoader implements PluginLoader{
|
|||||||
*
|
*
|
||||||
* @return null|PluginDescription
|
* @return null|PluginDescription
|
||||||
*/
|
*/
|
||||||
public function getPluginDescription(string $file){
|
public function getPluginDescription(string $file) : ?PluginDescription{
|
||||||
$content = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
$content = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
|
|
||||||
$data = [];
|
$data = [];
|
||||||
@ -114,55 +86,4 @@ class ScriptPluginLoader implements PluginLoader{
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the filename patterns that this loader accepts
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getPluginFilters() : string{
|
|
||||||
return "/\\.php$/i";
|
|
||||||
}
|
|
||||||
|
|
||||||
public function canLoadPlugin(string $path) : bool{
|
|
||||||
$ext = ".php";
|
|
||||||
return is_file($path) and substr($path, -strlen($ext)) === $ext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param PluginBase $plugin
|
|
||||||
* @param PluginDescription $description
|
|
||||||
* @param string $dataFolder
|
|
||||||
* @param string $file
|
|
||||||
*/
|
|
||||||
private function initPlugin(PluginBase $plugin, PluginDescription $description, string $dataFolder, string $file){
|
|
||||||
$plugin->init($this, $this->server, $description, $dataFolder, $file);
|
|
||||||
$plugin->onLoad();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Plugin $plugin
|
|
||||||
*/
|
|
||||||
public function enablePlugin(Plugin $plugin){
|
|
||||||
if($plugin instanceof PluginBase and !$plugin->isEnabled()){
|
|
||||||
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.plugin.enable", [$plugin->getDescription()->getFullName()]));
|
|
||||||
|
|
||||||
$plugin->setEnabled(true);
|
|
||||||
|
|
||||||
$this->server->getPluginManager()->callEvent(new PluginEnableEvent($plugin));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Plugin $plugin
|
|
||||||
*/
|
|
||||||
public function disablePlugin(Plugin $plugin){
|
|
||||||
if($plugin instanceof PluginBase and $plugin->isEnabled()){
|
|
||||||
$this->server->getLogger()->info($this->server->getLanguage()->translateString("pocketmine.plugin.disable", [$plugin->getDescription()->getFullName()]));
|
|
||||||
|
|
||||||
$this->server->getPluginManager()->callEvent(new PluginDisableEvent($plugin));
|
|
||||||
|
|
||||||
$plugin->setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit f4d7fc001e942e97048c5775cc2fd259637c8b66
|
Subproject commit eb1af563827fc748bbad8286c6c5796b7501848f
|
Loading…
x
Reference in New Issue
Block a user