PocketMine-MP icon indicating copy to clipboard operation
PocketMine-MP copied to clipboard

Added ApiMap

Open SOF3 opened this issue 5 years ago • 8 comments
trafficstars

Introduction

This provides a type-based approach for plugins to expose APIs to each other.

For example, PocketMine can provide a BanList interface with a default implementation (using the current banned-players.txt etc), then plugins can set it to their own implementation.

This class also handles conflict conditions.

For details, please check the documentation in the code.

Relevant issues

Resolves #3087

Changes

API changes

Added the ApiMap class.

Its methods are directly re-exported in Server.

Behavioural changes

None yet.

Backwards compatibility

This is a pure API addition with no BC issues.

Follow-up

Improve error messages.

Tests

See ApiMapTest.

SOF3 avatar Aug 18 '20 10:08 SOF3

Is there a reason to not just add a getApiMap() method to Server() instead of adding a bunch of proxy methods?

dktapps avatar Sep 29 '20 15:09 dktapps

I also have my doubts that a centralized approach for this is necessary. Some plugins already have their own ways to do this with different behaviour.

dktapps avatar Sep 29 '20 15:09 dktapps

I also have my doubts that a centralized approach for this is necessary. Some plugins already have their own ways to do this with different behaviour.

This is a move away from singleton approach. I am hoping to provide this as the basis for better DI pattern that can replace stuff like EconomyAPI::getInstance() with $server->getApi(EconomyApi::class).

I think centralization is necessary since I plan to implement this with stuff like PlayerGrayList (whitelist + ban list) in the future.

SOF3 avatar Sep 29 '20 16:09 SOF3

Is there a reason to not just add a getApiMap() method to Server() instead of adding a bunch of proxy methods?

Just for convenience. For now I don't see any actual reason to expose the ApiMap object directly.

SOF3 avatar Oct 02 '20 13:10 SOF3

I'm also not sure what the point of "default" APIs is. Allowing there to be a difference just allows plugins to fight with each other, which seems to defeat the objective.

The default API is the implementation provided by the interface declarer, such as by PocketMine itself, explicitly intended for overriding. I don't think there is a problem since there is only one interface declarer.

SOF3 avatar Oct 10 '20 10:10 SOF3

Suggested addition:

public function onFinalize(string $class, Closure $closure) {
    $this->onStartupHook[] = function() {
        $instance = $this->getApi($class);
        if($instance) $closure($instance);
    }
}

This allows decoupling plugin dependencies by only running functions like "register xxx handler" on certain APIs after they are all available. In this case, $class does not have to be loaded at the time of calling onFinalize, and the closure is only executed if the API is available.

Finalization is possible if #2825 is accepted.

SOF3 avatar Dec 14 '20 04:12 SOF3

Side note (previously discussed on discord): I would also like to use ApiMap to replace MetadataStore, so that plugins do not have to handle sessions themselves. E.g. an economy plugin:

public function onLogin(PlayerLoginEvent $event) {
    $event->getPlayer()->getApiMap()->provideApi(EconomyData::class, EconomyData::loadForPlayer($event->getPlayer());
}

It is also worth considering whether we should rename ApiMap to TypeMap or MetadataMap for more generic applications in the future; it's unreasonable to call plugin player sessions an "API" when it's supposed to be internal.

SOF3 avatar Feb 04 '21 09:02 SOF3

I just noticed bukkit has something very similar: https://bukkit.org/threads/services-api-intro.26998/

SOF3 avatar Aug 26 '21 06:08 SOF3