* Added a new PermissionManager, remove ridiculous cyclic dependencies of Permissions on Server
Aside from all the other ridiculous design problems with the permission system, the biggest problems are its API. This is, once again, a result of poor API design copied from Bukkit.
This pull request removes all permission-related functionality from `PluginManager` and moves it to the `pocketmine\permission\PermissionManager` class.
As can be observed from the removed code in the diff, the permissions system was previously entirely dependent on the Server, because it needed to get the PluginManager for registering permissions. This is utterly ridiculous. This refactor isolates _most_ permission-related functionality within the `permission` namespace.
As mentioned above, this stupid API is a direct result of copying from Bukkit. If you look at the API documentation for Bukkit for `PluginManager` you will see that the methods I'm deprecating here are also in there.
## Changes
- Added a new `PermissionManager` class. This can be accessed via its singleton `getInstance()` static method.
- Deprecated the following `PluginManager` methods - these will be removed no later than 4.0.0:
- `getPermission()`
- `addPermission()`
- `removePermission()`
- `getDefaultPermissions()`
- `recalculatePermissionDefaults()`
- `subscribeToPermission()`
- `unsubscribeFromPermission()`
- `getPermissionSubscriptions()`
- `subscribeToDefaultPerms()`
- `unsubscribeFromDefaultPerms()`
- `getDefaultPermSubscriptions()`
- `getPermissions()`
- Added `Internet::getIP()`, `Internet::getURL()`, `Internet::postURL()`, and `Internet::simpleCurl()`.
- Deprecated the corresponding functions in `Utils`. Updating to the new functions is as simple as replacing `Utils` with `Internet`, since this doesn't break backwards compatibility.
The deprecations should be catered for by plugin developers. These deprecated redirects will be removed no later than 4.0.0.
I considered renaming sendDataPacket() to dataPacket() to reduce the BC breaks, but the parameter set has changed, which might cause astonishing behaviour, so it's better to break it in a loud way. Also, this has a clearer name.
- Separated player handling and creation from network interfaces
- Rewire disconnects to make them not be recursive
- Batching now uses sessions instead of players
- Fixed DisconnectPacket getting sent to players who disconnect of their own accord
DataPacketSendEvent and DataPacketReceiveEvent will no longer capture BatchPackets
In most places strings are now used instead of DataPackets, to remove limitations on what data can be sent to a network interface
Removed CraftingManager's cyclic dependency on Server
There is a lot more work to do aside from this, but this commit is intended to clean up what is necessary to fix the handling of BatchPacket.
Under normal circumstances, none of the boxed code will throw exceptions. Under exceptional circumstances, the caller should know about it. Usually the caller is the server. We don't want to catch unexpected exceptions because those should crash the server and generate a crashdump.
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.
PhpStorm can't see these or understand how they are being called, which is very annoying for bug hunting. Additionally, we already have the CodeOptimizer for this.
This has long been a waste of time and creativity, and that's only going to continue to be the case now that we're going to be properly versioning. New codenames every couple of months is not worth the bother.
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 changes how the AsyncPool works so that it does not immediately always start all of the workers in the pool.
Instead, workers will be started only when an idle worker was not found.
This allows for significant memory footprint reductions while idle.
In effect the async-workers setting in pocketmine.yml now dictates a _maximum_ pool size, not a fixed pool size.
- Removed `Server->getScheduler()`. All plugins now have their own scheduler which is accessible using `Plugin->getScheduler()`. Aside from being syntactically more concise and pleasant, this also allows much more effective management of tasks when plugins are disabled.
- Removed `PluginTask` class. Before this PR it was necessary for plugin tasks to descend from `PluginTask` to ensure that the server could clean them up correctly on plugin disable. This is no longer necessary, so the `PluginTask` class has been removed. Plugins may now utilize the `Task` class as a base if they like.
- Added `Server->getAsyncPool()`. Since the global scheduler does not exist any more, it does not manage the server's `AsyncPool` any more. Additionally, `ServerScheduler` was previously bloated by a lot of `AsyncTask` related methods, which are now not necessary because direct access to `AsyncPool` is granted instead.
- `ServerScheduler`:
- `ServerScheduler` has been renamed to `TaskScheduler` since it is now a general-purpose task scheduler which is non-dependent on the user. This allows much greater flexibility and also makes it possible to unit-test.
- All `AsyncTask`/`AsyncPool` related methods have been removed - the task scheduler does not manage the async pool anymore.
- Calls to `Server->getScheduler()->scheduleAsyncTask()` should be replaced with `Server->getAsyncPool()->submitTask()`.
- Calls to `Server->getScheduler()->scheduleAsyncTaskToWorker()` should be replaced with and `Server->getAsyncPool()->submitTaskToWorker()`.
## Backwards compatibility
This poses significant backwards compatibility breaks for any plugins utilizing Tasks or AsyncTasks. These breaks are described above, along with basic upgrade steps. The upgrade process is quite straightforward.
## Follow-up
A large part of the goal with this pull request is to modularize these parts of the code so that they can be reused and also unit-tested. I would like to remove the existing test set from TesterPlugin at some stage when the AsyncPool can operate without a Server.
Because of the above, I am considering making further backwards incompatible changes directly to `AsyncTask` to remove the `Server` parameters from `onCompletion()` and `onProgressUpdate()`. These shouldn't be too difficult to upgrade from and can be prepared for in advance.
This change breaks pretty much all API pertaining to synchronous task scheduling.
Significant changes:
- Server->getScheduler() has been removed
- Plugin->getScheduler() has been added - every plugin now has its own scheduler
- Because schedulers are now per-plugin, it is now unnecessary for PluginTask to exist because stopping plugin tasks on plugin disable is as simple as destroying the plugin's scheduler. Therefore PluginTask has now been removed and it is expected for things to now use the base Task class instead.
For the most part, plugins will simply need to change Plugin->getServer()->getScheduler()->... to Plugin->getScheduler()->...
Another highlight is that plugin tasks now no longer have global IDs - they are unique to each scheduler.
This commit contains quite a few breaking changes with respect to how AsyncTasks are handled. This is necessary to allow separation of the ServerScheduler and the AsyncPool, because in the future the ServerScheduler may be removed and instead there will be isolated per-plugin sync-task schedulers - but we cannot have every plugin with its own worker pool for memory usage reasons if nothing else.
The following things have changed:
- ServerScheduler: scheduleAsyncTask(), scheduleAsyncTaskToWorker(), getAsyncTaskPoolSize(), increaseAsyncTaskPoolSize() and similar methods have all been removed. Additionally the static \$WORKERS field has been removed.
- Server: added API method getAsyncPool(). This grants you direct access to the server's AsyncPool. Calls to getScheduler()->scheduleAsyncTask() and scheduleAsyncTaskToWorker() should be replaced with getAsyncPool()->submitTask() and submitTaskToWorker() respectively.