diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index bbe1fed29..cb53dedd6 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -92,6 +92,7 @@ use pocketmine\plugin\PharPluginLoader; use pocketmine\plugin\Plugin; use pocketmine\plugin\PluginLoadOrder; use pocketmine\plugin\PluginManager; +use pocketmine\plugin\ScriptPluginLoader; use pocketmine\scheduler\FileWriteTask; use pocketmine\scheduler\SendUsageTask; use pocketmine\scheduler\ServerScheduler; @@ -1695,6 +1696,7 @@ class Server{ $this->pluginManager->setUseTimings($this->getProperty("settings.enable-profiling", false)); $this->profilingTickRate = (float) $this->getProperty("settings.profile-report-trigger", 20); $this->pluginManager->registerInterface(PharPluginLoader::class); + $this->pluginManager->registerInterface(ScriptPluginLoader::class); set_exception_handler([$this, "exceptionHandler"]); register_shutdown_function([$this, "crashDump"]); @@ -2047,6 +2049,7 @@ class Server{ } $this->pluginManager->registerInterface(PharPluginLoader::class); + $this->pluginManager->registerInterface(ScriptPluginLoader::class); $this->pluginManager->loadPlugins($this->pluginPath); $this->enablePlugins(PluginLoadOrder::STARTUP); $this->enablePlugins(PluginLoadOrder::POSTWORLD); diff --git a/src/pocketmine/plugin/PluginDescription.php b/src/pocketmine/plugin/PluginDescription.php index 738669b5e..04c25224a 100644 --- a/src/pocketmine/plugin/PluginDescription.php +++ b/src/pocketmine/plugin/PluginDescription.php @@ -45,10 +45,10 @@ class PluginDescription{ private $permissions = []; /** - * @param string $yamlString + * @param string|array $yamlString */ public function __construct($yamlString){ - $this->loadMap(\yaml_parse($yamlString)); + $this->loadMap(!is_array($yamlString) ? \yaml_parse($yamlString) : $yamlString); } /** diff --git a/src/pocketmine/plugin/ScriptPluginLoader.php b/src/pocketmine/plugin/ScriptPluginLoader.php new file mode 100644 index 000000000..95a2e2f97 --- /dev/null +++ b/src/pocketmine/plugin/ScriptPluginLoader.php @@ -0,0 +1,160 @@ +server = $server; + } + + /** + * Loads the plugin contained in $file + * + * @param string $file + * + * @return Plugin + * + * @throws \Exception + */ + public function loadPlugin($file){ + if(($description = $this->getPluginDescription($file)) instanceof PluginDescription){ + $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; + } + + /** + * Gets the PluginDescription from the file + * + * @param string $file + * + * @return PluginDescription + */ + public function getPluginDescription($file){ + $content = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + + $data = []; + + $insideHeader = false; + foreach($content as $line){ + if(!$insideHeader and strpos($line, "/**") !== false){ + $insideHeader = true; + } + + if(preg_match("/^[ \t]+\\*[ \t]+@([a-zA-Z]+)[ \t]+(.*)$/", $line, $matches) > 0){ + $key = $matches[1]; + $content = trim($matches[2]); + + $data[$key] = $content; + } + + if($insideHeader and strpos($line, "**/") !== false){ + break; + } + } + if($insideHeader){ + return new PluginDescription($data); + } + + return null; + } + + /** + * Returns the filename patterns that this loader accepts + * + * @return array + */ + public function getPluginFilters(){ + return "/\\.php$/i"; + } + + /** + * @param PluginBase $plugin + * @param PluginDescription $description + * @param string $dataFolder + * @param string $file + */ + private function initPlugin(PluginBase $plugin, PluginDescription $description, $dataFolder, $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); + } + } +} \ No newline at end of file