SpongeAPI icon indicating copy to clipboard operation
SpongeAPI copied to clipboard

[API-8] Standardize data directory

Open alexstaeding opened this issue 3 years ago • 3 comments

The concept of the config directory has been standardized for a long time now. However, it is not very clear where plugins should store "user data" (assuming it's not stored on a remote database).

Currently, the main choices are:

  1. In the root server directory SERVER_DIR/<pluginid>
  2. In the config directory SERVER_DIR/config/<pluginid>

Both have disadvantages; saving directly in the server directory can lead to an unorganized mess, whereas saving in the config directory seems weird considering "user data" is not "configuration data".

(As a side note, some users may delete the config directory to reset configuration data but this should not delete user data.)

Potential solution

There should be a standardized way of storing plugin data that is not configuration data. In my opinion, the most sensible convention would be SERVER_DIR/data/<pluginid> or SERVER_DIR/plugindata/<pluginid> as this is similar to the structure of the current config directory.

Deliverables

  • [ ] Recommend a standardized approach in the docs (on https://docs.spongepowered.org/)
  • [ ] Offer a binding annotation for easy integration via guice (similar to @ConfigDir, maybe @DataDir?)

alexstaeding avatar Apr 05 '21 19:04 alexstaeding

How would that work where the game can boot multiple server engines - something like the client? Is there data for client side and server side? Should we make the distinction between game scoped and engine scoped - presumably the latter is more useful for plugin data?

This is nowhere near as simple as config which is assumed to always be game scoped. It's not a simple as slapping an annotation on a Path and being done with it.

dualspiral avatar Apr 05 '21 21:04 dualspiral

It's probably worth having the same sort of discussion about scope on configurations as well, since plugins may want to have per-world or per-universe configurations (drawing from names used in the vanilla server CLI arguments here)

  • global: runtime
  • universe: one single save on the client/integrated server, equivalent to global on dedicated server
  • world: a single dimension, such as overworld or nether

For universe and world, the injected type would have to be some sort of provider mapping engine/world -> a configuration location

The part I've struggled to find a good answer for is how to handle invalidation of a certain scope -- when an integrated server shuts down, how do we indicate to plugins that their configuration has gone out of scope in a minimally error-prone way?

zml2008 avatar Apr 05 '21 21:04 zml2008

@zml2008

Perhaps the desire to continue to do injected configuration loaders/paths are the issue here. You hit on this with your point on how to tell plugin devs that the config is now "stale". I don't really see a clean way to do this with injected loaders without introducing another concept for plugin devs to have to learn.

With this is mind, maybe a better fix for this is (imo) granting configuration is own lifecycle event. This does more tightly couple Configurate to plugin development (well depends how the event looks) but given pseudocode below...

interface LoadConfigurationEvent extends LifecycleEvent {
    Path configDirectory();

    // TODO Need a way for a dev to tell us "I want to be hocon!" and we give them back the appropriate configuration node?

    interface GameScoped extends LoadConfigurationEvent {}
    
    interface EngineScoped<E extends Engine> extends LoadConfigurationEvent {}

    interface WorldScoped<W extends World> extends LoadConfigurationEvent {}
}    

Rough by far but perhaps a talking point. We would essentially mirror this for some "loading data" mechanism...just without configurate-specific bits there.

Zidane avatar Jul 23 '21 03:07 Zidane