From 3a373b880db59d3f55ba66c3ad28534988d56a66 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 12 Jul 2018 19:24:46 +0100 Subject: [PATCH 1/3] Listener: Add documentation on functionality (#2292) The Listener interface is one of the most magical parts of PocketMine-MP, and before this pull request it didn't have a single bit of documentation. --- src/pocketmine/event/Listener.php | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/pocketmine/event/Listener.php b/src/pocketmine/event/Listener.php index e19f673c8..0a3f84f50 100644 --- a/src/pocketmine/event/Listener.php +++ b/src/pocketmine/event/Listener.php @@ -23,6 +23,37 @@ declare(strict_types=1); namespace pocketmine\event; +use pocketmine\plugin\PluginManager; + +/** + * Classes implementing this interface can be registered to receive called Events. + * @see PluginManager::registerEvents() + * + * A function in a Listener class must meet the following criteria to be registered as an event handler: + * + * - MUST be public + * - MUST NOT be static + * - MUST accept EXACTLY ONE class parameter which: + * - MUST be a VALID class extending Event + * - MUST NOT be abstract, UNLESS it has an `@allowHandle` annotation + * + * Event handlers do not have to have any particular name - they are detected using reflection. + * They SHOULD NOT return any values (but this is not currently enforced). + * + * Functions which meet the criteria can have the following annotations in their doc comments: + * + * - `@notHandler`: Marks a function as NOT being an event handler. Only needed if the function meets the above criteria. + * - `@softDepend [PluginName]`: Handler WILL NOT be registered if its event doesn't exist. Useful for soft-depending + * on plugin events. Plugin name is optional. + * Example: `@softDepend SimpleAuth` + * - `@ignoreCancelled`: Cancelled events WILL NOT be passed to this handler. + * - `@priority `: Sets the priority at which this event handler will receive events. + * Example: `@priority HIGHEST` + * @see EventPriority for a list of possible options. + * + * Event handlers will receive any instanceof the Event class they have chosen to receive. For example, an + * EntityDamageEvent handler will also receive any subclass of EntityDamageEvent. + */ interface Listener{ } From 1d5c741f28f4e706b168300d5daebb8c34d8a050 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 12 Jul 2018 19:25:48 +0100 Subject: [PATCH 2/3] PluginBase: Automatically save default config if it doesn't exist (#2285) I wasn't sure whether this would be considered a bug fix or a feature. Nonetheless, it's a behavioural change, so it belongs in 3.1 if anywhere. Prior to this, plugins would be required to call saveDefaultConfig() before calling getConfig() or anything else. Calling getConfig() without saveDefaultConfig() first would generate an empty configuration file. Instead, it now saves the default config before loading it. --- src/pocketmine/plugin/PluginBase.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/plugin/PluginBase.php b/src/pocketmine/plugin/PluginBase.php index bba7231e9..e28f75a49 100644 --- a/src/pocketmine/plugin/PluginBase.php +++ b/src/pocketmine/plugin/PluginBase.php @@ -256,7 +256,9 @@ abstract class PluginBase implements Plugin{ } public function reloadConfig(){ - @mkdir($this->dataFolder); + if(!$this->saveDefaultConfig()){ + @mkdir($this->dataFolder); + } $this->config = new Config($this->configFile); if(($configStream = $this->getResource("config.yml")) !== null){ $this->config->setDefaults(yaml_parse(Config::fixYAMLIndexes(stream_get_contents($configStream)))); From af80aefd458f64aa68fc4dcadf8483659264c790 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 12 Jul 2018 19:31:00 +0100 Subject: [PATCH 3/3] Remove async config save (#2298) As discussed in #2297: Honestly I don't see a fit purpose for async saving at all. It should either always be synchronous or always asynchronous, and at the user's own option. However, this isn't currently possible because Config doesn't enable you to get the serialized content without writing it to disk. Consider the following code: ```php for($i = 0, $size = $this->getServer()->getAsyncPool()->getSize(); $i < $size; ++$i){ $this->getServer()->getAsyncPool()->submitTask(new class extends AsyncTask{ public function onRun(){ sleep(5); } }); } $config = $this->getConfig(); $config->set("steve", "hi"); $config->save(true); $config->set("steve", "bye"); $config->save(false); ``` Output: ```yml --- steve: hi ... ``` Expected output: ```yml --- steve: bye ... ``` Additionally, if your configs are causing you performance issues when you're saving, it's a clear sign that a) you're saving too much b) you're abusing configs and should consider using a database. Configs should be used for _simple_ data which does not change much. Configuration is such that the _user_ is expected to be able to modify it. As such, it should never be an issue to save synchronously. In the future, something like ReactPHP may be introduced to allow proper async saving. When this happens, async saving would always be sequential but non blocking. Using threads for this makes no sense. --- src/pocketmine/Server.php | 6 +++--- src/pocketmine/utils/Config.php | 11 ++--------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 94b4305f1..e1fc23261 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1300,7 +1300,7 @@ class Server{ if(($player = $this->getPlayerExact($name)) !== null){ $player->recalculatePermissions(); } - $this->operators->save(true); + $this->operators->save(); } /** @@ -1320,7 +1320,7 @@ class Server{ */ public function addWhitelist(string $name){ $this->whitelist->set(strtolower($name), true); - $this->whitelist->save(true); + $this->whitelist->save(); } /** @@ -1691,7 +1691,7 @@ class Server{ } if($this->properties->hasChanged()){ - $this->properties->save(true); + $this->properties->save(); } if(!($this->getDefaultLevel() instanceof Level)){ diff --git a/src/pocketmine/utils/Config.php b/src/pocketmine/utils/Config.php index c8609afdc..30ab3dadd 100644 --- a/src/pocketmine/utils/Config.php +++ b/src/pocketmine/utils/Config.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace pocketmine\utils; -use pocketmine\scheduler\FileWriteTask; use pocketmine\Server; @@ -187,11 +186,9 @@ class Config{ } /** - * @param bool $async - * * @return bool */ - public function save(bool $async = false) : bool{ + public function save() : bool{ if($this->correct){ try{ $content = null; @@ -216,11 +213,7 @@ class Config{ throw new \InvalidStateException("Config type is unknown, has not been set or not detected"); } - if($async){ - Server::getInstance()->getAsyncPool()->submitTask(new FileWriteTask($this->file, $content)); - }else{ - file_put_contents($this->file, $content); - } + file_put_contents($this->file, $content); }catch(\Throwable $e){ $logger = Server::getInstance()->getLogger(); $logger->critical("Could not save Config " . $this->file . ": " . $e->getMessage());