Successor to Erisia/cursetool-rs.
While cursetool only supports conversion of a human-writable manifest into the Nix file used by Erisia/builder, this tool aims to be a full-service modpack builder, allowing workflows to be defined which will pull a pack from Curse/Modrinth/etc., edit mod lists, patch config files, output a Nix manifest and static pack files, and more.
While the core functionality of resolving human-readable mod lists into a Erisia/builder readable manifest has been implemented (and expanded to support both Curse and Modrinth), the other capabilities are still in progress.
With Nix Flakes enabled, run
$ nix run github:maxwell-lt/modestly-modular-modpack-modifier/0.6.0 -- ./pack-manifest.yml
Optionally, the paths where output files should be saved can be specified with -o /path/to/output
or --output-dir /path/to/output
.
The directory used for the config file (defaults to the platform-specific user config directory) can be overridden with -c /path/to/config
or --config-dir /path/to/config
.
Mod resolution data is persistently cached for performance, which may cause the tool to pick up old versions of mods that are specified without a file ID.
To clear the cache and ensure the newest versions of unpinned mods are retrieved, run with the flag --clear-cache
.
Workflows are defined as a YAML file.
The top level consists of two keys, config
and nodes
.
config:
...
nodes:
...
The config
key contains key/value pairs, where the values must be strings.
The values set here will be available globally to any nodes that require them.
The documentation for each node will explain which keys are required.
config:
minecraft_version: '1.7.10'
The nodes
key contains an array of three types of nodes: source, intermediate, and output.
These can be defined in any order within the nodes
array, and link to each other by name.
Note
|
Named outputs and implied
default Intermediate nodes can have one or more outputs, where the primary output will be named For brevity, examples in this document will generally omit the output name. |
Source nodes are YAML objects with keys id
and value
. The id
key names the node, and is how other nodes will reference it.
The value
node can be either a string (Text), array of strings (List), or array of mods (Mods).
nodes:
- id: text-node
value: 'Hello World!'
- id: list-node
value:
- 'Hello'
- 'World'
- id: mods-node
value:
- name: 'appleskin'
source: curse
The mod schema further breaks down into three categories: CurseForge, Modrinth, and direct URL.
The name
and source
fields are mandatory for all mod source types, and the URL type additionally requires the URL to be set.
All other fields are optional.
# CurseForge
- name: 'appleskin'
source: curse
# Optional fields:
id: 123456
file_id: 12345678
required: true
default: true
side: client
# Modrinth
- name: 'sodium'
source: modrinth
# Optional fields:
id: AbCdE123
file_id: 1A2b3C4d
required: true
default: true
side: server
# Direct URL
- name: 'botania-gtnh'
source: url
location: 'https://github.com/GTNewHorizons/Botania/releases/download/1.10.0-GTNH/Botania-1.10.0-GTNH.jar'
# Optional fields:
filename: 'Botania-1.10.0-GTNH.jar'
required: true
default: true
side: both
Output nodes are YAML objects with keys source
and filename
.
The source
key links to the node data is received from, and filename
defines the name of the file that should be output.
The referenced channel must have a type of either Text or Files.
Output nodes with a source channel of other types will be ignored.
Output nodes linked to a Text channel will write to a file with exactly the name specified by filename
,
but nodes linked to a Files channel will have their file extension (if present) replaced with .zip
.
nodes:
- id: file-contents
value: |
Hello World!
This is a multiline YAML input that will be put into a file!
# This output node will write the text from the file-contents node to "output.txt"
- source: file-contents
filename: output.txt
Each intermediate node is a YAML object with keys id
, kind
, and input
.
The id
key sets its name, the kind
key sets its type, and the input
key is a map of named inputs to the output channels of other nodes.
Each node type has a different set of named inputs required.
nodes:
- id: source-node-with-url
value: https://example.com/file.zip
- id: download-pack
kind: ArchiveDownloader
input:
url: source-node-with-url
The ArchiveDownloader node downloads a ZIP archive from a provided URL, then unpacks it.
-
url
-
Type: Text
-
-
default
-
Type: Files
-
The DirectoryMerger node takes multiple Files inputs and combines them into a single Files output.
This node is special, in that it accepts any number of inputs, with any name. The names provided for inputs are used to resolve conflicts between files with the same name; inputs with names with an earlier alphabetical ordering take precedence.
For example, two Files channels have a file named "config/modconfig.cfg".
If one of those channels is provided to an input named input-a
, and the other input-b
, the version of the file from input-a
will be retained.
-
Multiple channels with any name will be accepted
-
Type: Files
-
-
default
-
Type: Files
-
The ModMerger node takes multiple ResolvedMods inputs and combines them into a single ResolvedMods output.
This node is special, in that it accepts any number of inputs, with any name. The names provided for inputs are used to resolve conflicts between mods with the same name; inputs with names with an earlier alphabetical ordering take precedence.
For example, two ResolvedMods channels have a mod named "appleskin".
If one of those channels is provided to an input named input-a
, and the other input-b
, the version of the mod from input-a
will be retained.
-
Multiple channels with any name will be accepted
-
Type: ResolvedMods
-
-
default
-
Type: ResolvedMods
-
The FileFilter node takes a Files input along with a List input containing a series of glob patterns, and outputs all files that match any specified glob pattern.
Files that match none of the specified glob patterns are sent to the named output inverse
.
Inverted glob patterns are not supported, so the inverse
channel should be used in use cases where a specific set of files is to be excluded.
-
files
-
Type: Files
-
-
pattern
-
Type: List
-
-
default
-
Type: Files
-
-
inverse
-
Type: Files
-
The ModResolver node takes a Mods input and outputs a ResolvedMods list that includes all the required metadata.
Important
|
Curse API
If any mods processed by a ModResolver have a CurseForge source, the config file |
-
minecraft_version
-
Version of Minecraft for which mods should be resolved, in cases where the exact file is not specified.
-
-
modloader
-
Modloader for which mods should be resolved, in cases where the exact file is not specified.
-
-
mods
-
Type: Mods
-
-
default
-
Type: ResolvedMods
-
The ModWriter node takes a ResolvedMods input and outputs two Text channels with those mods in a Nix manifest and JSON manifest as supported by Erisia/builder.
-
minecraft_version
-
Version of Minecraft to include in the manifest.
-
-
resolved
-
Type: ResolvedMods
-
-
default
-
Type: Text
-
-
json
-
Type: Text
-
The CurseResolver node takes a Text input, parses it as a CurseForge pack manifest, and outputs ResolvedMods.
Important
|
Curse API
The config file |
-
manifest
-
Type: Text
-
-
default
-
Type: ResolvedMods
-
The FilePicker node takes a Files input along with a path from a Text input, and outputs the file at that path as a Text channel. This node will fail if a UTF-8 encoded file is not present at the provided path.
-
files
-
Type: Files
-
-
path
-
Type: Text
-
-
default
-
Type: Text
-
The ModOverrider node takes a ResolvedMods input and a Mods input, and applies the values from the side, required, and default fields from the latter to the former, by mod name. The overridden mod list is then returned as a ResolvedMods channel.
Note
|
Overridden fields
When declaring the Mods used as an override, keep a few things in mind. The defined mod type has no effect. If the required or default fields are not set, the original value will be used. If the side field is not set, the mod will be set to use side Both. |
-
mods
-
Type: ResolvedMods
-
-
overrides
-
Type: Mods
-
-
default
-
Type: ResolvedMods
-
The ModFilter node takes a ResolvedMods input and a List of mod names, and outputs the mods which match any of those names. Mods that match none of those names are sent to the named output inverse
-
mods
-
Type: ResolvedMods
-
-
filters
-
Type: List
-
-
default
-
Type: ResolvedMods
-
-
inverse
-
Type: ResolvedMods
-