-
-
Notifications
You must be signed in to change notification settings - Fork 194
Suggestion: Improved JSON format for mod info #637
Description
Introduction
After having spent quite a bit of time working with NodeJS and NPM, I've become quite impressed with the power and simplicity of the package.json file format. I've noticed that FML internally uses a somewhat similar format in the form of the mcmod.info file, but I've found that there are a few drawbacks to the format:
- While most mods embed
mcmod.infoin the JAR, there doesn't seem to be a public repository of these files. As a result, each mod needs to write its own update checking logic (or rely on a shared library). - The "version" field of
mcmod.infois arbitrary. As a result, update checking logic must be unique to the version format used by the mod author. - The "dependencies" and "requiredMods" fields of
mcmod.infodo not specify version information.
The package.json format used by nodejs shares similar characteristics with mcmod.info, but provides some additional capabilities:
- The "version" field requires a canonical format, via semantic versioning.
- The "dependencies" field is a map of required dependencies to their minimal version, using a specialized format for specifying version ranges.
- The "repository" field contains information about where to clone or contribute to the package if it is open source.
- The "bugs" field contains information about where to file bugs against the package.
- The "directories" and "files" fields contain information about the contents of the package.
Proposal
I propose that a new JSON format be introduced for FML mods. This format would use the following structure:
NOTE: The following listing uses TypeScript interfaces to describe the structure of the JSON file.
- The
?token following a field name marks the field as optional.- The
|token between types means the field must be either of the types.- The
[]tokens following a type or parenthesized type indicate an array.NOTE: Not all of the existing fields from
mcmod.infoare listed below, and some have been renamed or moved. This does not mean they should be lost, but rather merged into this format as appropriate.
// The primary structure for the JSON file
interface Mod {
// The name of the mod, used as a key for dependencies (previously "modid")
name: string;
// A descriptive name for the mod (previously "name")
title?: string;
// A long description for the mod
description?: string;
// Additional keywords or tags for the mod
keywords?: string[];
// The semantic version of the mod: http://semver.org
version: string;
// The primary author of the mod (previously "credits"/"authorList").
author?: string | Person;
// Additional contributors to the mod (previously "authorList")
contributors?: (string | Person)[];
// A url to the homepage for the mod
homepage?: string;
// A url to download the binary version of the mod
url?: string | FileResource;
// Urls to download additional resources for the mod
urls?: (string | FileResource)[];
// The source code repository for the mod, if it is open source
repository?: string | Resource;
// The means with which users can file bugs
bugs?: BugTracker
// Required dependencies for the mod (previously "dependencies", "requiredMods", "mcversion")
dependencies?: DependencyMap;
// Optional dependencies for the mod
optionalDependencies?: DependencyMap
// Developer dependencies for the mod
devDependencies?: DependencyMap;
// License information for the mod. See https://spdx.org/licenses/
license?: string;
// Directories in the mod (under the mods/[mod name] folder)
directories?: string[];
// Files in the mod (under the mods/[mod name] folder)
files?: string;
// Extensibility for future updates
[key: string]: any;
}
// Extended information about a Person
interface Person {
// The display name for the person
name: string;
// The email for the person
email?: string;
// A url for the person (homepage, blog, profile, etc.)
url?: string;
}
// Extended information about a url resource
interface Resource {
// What type of resource is this? A file? A feed? A git repository?
type: string;
// The url to the resource
url: string;
}
// Extended information about a file url resource
interface FileResource extends Resource {
// The MD5 hash of the file resource (in hexadecimal)
md5?: string;
// The SHA1 hash of the file resource (in hexadecimal)
sha1?: string;
}
// Extended information about a bug tracker
interface BugTracker {
// A url to a public bug tracker
url?: string;
// An email for bug reports
email?: string;
}
// A key-value map for dependencies to the required version spec:
interface DependencyMap {
[dependency: string]: string;
}Dependencies
A dependency can specify the version range required (useful both for version testing when loading the mod, and to allow loaders or mod management tools to check for updates and version mismatches. For an example of version ranges, see https://docs.npmjs.com/misc/semver.
Example
Here is an example from converting the mcmod.info for Thermal Foundation:
{
"name": "ThermalFoundation",
"title": "Thermal Foundation",
"description": "The foundation of a Thermally enhanced world!",
"version": "1.0.0-RC4+58",
"author": "TeamCoFH",
"contributors": [
"KingLemming",
"skyboy026",
"ZeldoKavira"
],
"homepage": "http://www.curse.com/mc-mods/minecraft/222880-thermal-foundation",
"dependencies": {
"Minecraft": "1.7.10",
"MinecraftForge": "10.13.2",
"CoFHCore": "3.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/CoFH/ThermalFoundation"
},
"bugs": {
"url": "https://github.com/CoFH/Feedback/issues"
},
"files": [
"ThermalFoundation-[1.7.10]1.0.0RC4-58.jar"
]
}And here is an example for Forge:
{
"name": "MinecraftForage",
"title": "Forge",
"version": "10.13.2+1291",
"dependencies": {
"Minecraft": "1.7.10"
},
"homepage": "http://files.minecraftforge.net/",
"author": "LexManos",
"urls": [
{
"type": "Universal",
"url": "http://files.minecraftforge.net/maven/net/minecraftforge/forge/1.7.10-10.13.2.1291/forge-1.7.10-10.13.2.1291-universal.jar",
"md5": "e71e88c744588fdad48d3b3beb4935fc"
},
{
"type": "Installer-win",
"url": "http://files.minecraftforge.net/maven/net/minecraftforge/forge/1.7.10-10.13.2.1291/forge-1.7.10-10.13.2.1291-installer-win.exe",
"md5": "0b8598a75955dedf99a56e39c5c721ce"
},
{
"type": "Changelog",
"url": "http://files.minecraftforge.net/maven/net/minecraftforge/forge/1.7.10-10.13.2.1291/forge-1.7.10-10.13.2.1291-changelog.txt"
}
],
"repository": {
"type": "git",
"url": "https://github.com/MinecraftForge/MinecraftForge"
},
"bugs": {
"url": "https://github.com/MinecraftForge/MinecraftForge/issues"
}
}Benefits
By adopting this format, and assuming a central repository to which mod authors could publish these files, in addition to embedding them in the JAR, there would be a number of benefits:
- Mod authors can easily specify version ranges for dependencies.
- Mod authors have control over how their mods are downloaded (automatic updates, or require the user to navigate to a home page or an adfly link, etc).
- A central repository (like http://modlist.mcf.li, Curse, or something else similar to http://npmjs.org) could manage these dependencies.
- A tool similar to npm could be used to install and update mods on a server or client
- Server operators could easily update their servers and ensure compatible versions of dependent mods are updated all at once.
- Clients could easily download mods by following links in the JSON files stored either in a central repository or from a Minecraft server.