thunderstore-io / Thunderstore

Thunderstore is a mod database and API for downloading mods. Thunderstore Discord: https://discord.thunderstore.io/
https://thunderstore.io/
GNU Affero General Public License v3.0
128 stars 28 forks source link

WIP: Manifest v2 Specification #93

Open MythicManiac opened 5 years ago

MythicManiac commented 5 years ago

Currently, the Risk of Rain 2 mod tooling economy is very unstandardized, which causes confusion among mod developers on how to make mods, users on how to install mods, and tool developers on how to manage mods.

The goal of the Manifest v2 specification is to allow for more flexible yet standardized support for mod packages. The Manifest v2 specification should account for the needs of users, mod developers, and tool developers, while being flexible enough to function for the foreseeable future.

Based on #86, I have now collected the following spec for version 2

v2 specification (subject to change)

Key Content
ManifestVersion The version of this Manifest file. Should be 2 in this case.
AuthorName The author of this package. Will be uploaded under that author identity. If it doesn't exist yet, it will be created and ownership of the author identity assigned to the uploader. If it does exist, proper access rights are required. Same as username in the current system, but a single account can have multiple author identities, which each also can hold multiple users with upload rights.
Name The package's author-unique name. Needs to remain same across versions.
DisplayName The display name of the package, can be changed between versions, and has less strict restrictions.
Version The version number of the package.
License The license this mod is licensed under, e.g. MIT
WebsiteURL The URL to the mod's website, if any. Usually git repository link for example.
Description Short description of the mod, max length 256 characters.
GameVersion The version (or build ID in this case) of the game this mod was built against.
Dependencies A list of dependencies for this mod, version range supported.
OptionalDependencies A list of optional dependencies for this mod, version range supported.
Incompatibilities A list of incompatible packages for this mod, version range supported.
NetworkMode Where is this code required to run for the mod to function? server, client, or both
PackageType What type of a package is this? code, tool, mod, map, or other
InstallMode How should the package be installed (used by managers for example). extract, managed, or none
Loaders What loaders should load this mod? A list of freeform strings, currently likely disunity, bepinex, monomod, or empty
ExtraData Freeform dictionary of keys and values. Can be used by other tools for features that the current spec doesn't cover.

Clarifications

Todo

Next steps after v2

Please do share any concerns and/or suggestions

scottbot95 commented 5 years ago

As far as version range goes, I suggest we just use the semver versioning scheme. It can handle anything you through at it, and is widely used.

0x0ade commented 5 years ago

NetworkMode: Where is this code required to run for the mod to function? serverclient, or both

I'd like to propose a none / nosync mode, similarly to how it already is implemented by the Terraria modding community. This would be important if the network mode ever gets enforced in a strict manner, f.e. clients disabling their server mods automatically and servers syncing their client mods with connecting clients.

MythicManiac commented 5 years ago

@0x0ade I feel like that could be it's own separate field, and good point 👍 The NetworkMode could be used purely to define where the mod functions/is required, and maybe some separate flag for whether or not the mod should be sent to clients. At least in my mind those are different use cases, and could use separate fields due to that.

tristanmcpherson commented 5 years ago

Loader: What loader should load this mod? Freeform input, currently likely disunity, bepinex, monomod, or empty

Will this field be an array? As R2API contains both a monomod patch and a BepInEx plugin.

MythicManiac commented 5 years ago

@tristanmcpherson good point, we'll have to think how to handle that as well. With the current spec it could be workarounded by separating those to two packages, and having a dependency relation, but it would probably be nicer to do that in a single package.

opl- commented 5 years ago
opl- commented 5 years ago

Another thought: characters allowed in Name and possibly AuthorName should be declared in the specification, both because right now it's vague at best and as they're most likely going to end up in URLs. Something to consider here would be names potentially used by Asian users but also just straight up zalgo.

opl- commented 5 years ago

I was under the impression that this is a manifest for mod repositories (more specifically Thunderstore, which I've heard is trying to keep it possible to potentially reuse its code for other games, i.e. not RoR2) that would also be used by mod managers to install the mods. That means that while taking the existence of Disunity (and other loaders) into consideration, this manifest isn't actually a Disunity manifest.

Now, based on what I've learned about Disunity, it will be taking into consideration mod repositories and will provide its own solution for those, so we end up with a problem: Thunderstore is trying to stay loader agnostic while Disunity is trying to be, in a way, Thunderstore.

I see several possible outcomes of this situation:

MythicManiac commented 5 years ago

Key capitalization. Generally JSON formatted data uses camel case key names, although technically using pascal case isn't explicitly forbidden. Just throwing it out there since it's somewhat unconventional.

This is what I thought too, and also why they are so in the table above. Another question entirely is should we even use JSON or not? There's been some hopes for alternatives, e.g. TOML, YAML, or even XML. This is an open point for discussion, feel free to contribute your thoughts.

Personally I think that either of the two following criteria should be met:

PackageType values need clarification and are possibly missing a mod value. What's the difference between framework and library? What category do mods fall under? What about a mod that provides a scene hierarchy view?

I thought I had mod in there, but evidently not, good eye. Framework can be removed if it's seen as unnecessary, I was thinking bepinex/disunity/monomod would fall into this category.

Could the Loader field be determined from the dependencies?

  • What happens if the mod has both a monomod prepatcher and wants to be loaded using bepinex?
  • What if the mod can be loaded using more than one mod loader for compatibility?

I believe this is what's currently being done to some extent, but I think we should standardize this more to have a more reliable system.

It does seem we should add support for N amount of mods in a package, targeted at N2 loaders. How should this be in the spec is currently open for discussion at least, but a simple path mapping should suffice I think.

Another alternative is that we only allow one loaded entry per package, meaning if you need more, you'd add dependency relations. I don't think it's as nice of a solution, albeit "cleaner" in a sense.

GameVersion could be merged into Dependencies and the game itself could then be made into a meta package, but honestly I feel like this one isn't really necessary. Still, throwing it out there.

This schemantically doesn't make much sense to me at least, given how dependencies are an entirely different datatype.

GameVersion could also be a version range. Mod managers are likely going to end up using that field for determining mod compatibility with the game and obviously some mods might stay compatible between game versions. Then again, bumping the supported game version could be considered in semver terms a change that would warrant a mod version bump.

Could of course. Would you think that's going to be useful? The need I imagined for this field was simply to know what game version was the mod built for (e.g. after a game update, is the mod targeting the latest version already or not). Allowing for version ranges would at least need to be limited so you can't target a range upwards, as that would make this kind of usability not work (we can't know what happens between game updates, so we can't guarantee it will work on the next version).

Definitely open for more discussion.

Another thought: characters allowed in Name and possibly AuthorName should be declared in the specification, both because right now it's vague at best and as they're most likely going to end up in URLs. Something to consider here would be names potentially used by Asian users but also just straight up zalgo.

Agreed. If we end up using a format that allows schema validation, it's easy to ship that schema on top of any documentation. The biggest limitation is that the names have to be filesystem safe, as defined by Windows (since other platforms are more lax on those anyway).

MythicManiac commented 5 years ago

Tags were mentioned as well in conversations, should think if those are fine to be added here or some other system.

harbingerofme commented 4 years ago

Consider adding an optional Deprecated field. On that note, if you do so, please consider using that field to link alternatives.

MythicManiac commented 4 years ago

Let's add a field for license as well

EDIT: Added to the spec

MythicManiac commented 4 years ago

Loader should probably be an array of Loaders instead, as a single mod can possibly have multiple loaders.

sodiboo commented 3 years ago

Why is ExtraData necessary? Why wouldn't you just have additional root-level keys? Manifest version will ensure these are ignored if a new version uses those same names, and the only benefit of using ExtraData would be that you could then have keys that have the same name as root-level keys in the same manifest version. (which is stupid and confusing, and should be discouraged anyways)

MythicManiac commented 3 years ago

Why is ExtraData necessary? Why wouldn't you just have additional root-level keys? Manifest version will ensure these are ignored if a new version uses those same names, and the only benefit of using ExtraData would be that you could then have keys that have the same name as root-level keys in the same manifest version. (which is stupid and confusing, and should be discouraged anyways)

Two reasons I can think of immediately are:

  1. Forwards compatibility. We can ensure any future manifest version changes won't touch the ExtraData, as it'd be reserved for 3rd party use
  2. Cleaner schema, you know all of the extra data is 3rd party definitions as opposed to having to guess which is what if everything is at the root level

The intention is providing a way for 3rd party metadata to be included in the manifest, though the exact schema is likely to change too. If a 3rd party tool needs complex metadata, it can require it's own files. Whatever we have supported for the manifest is likely going to be something that gets indexed by the site and will be visible in the API as well (e.g. for search purposes). How that'll happen in practice is still not decided, but it's something we want to make happen.

An example scenario where this is useful would be a custom map loader. It could have it's own metadata convention in the manifest, and display available maps (via Thunderstore API) in-game based on metadata filters.