summaryrefslogtreecommitdiff
path: root/docs/handbook/meshmc/mod-system.md
blob: 14d309e7213d5b8d2fc5da0648f967cf44acafff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# Mod System

## Overview

MeshMC provides comprehensive mod management through a combination of local folder models and mod platform integrations. The mod system handles installation, discovery, metadata extraction, enabling/disabling, and browsing of mods from CurseForge, Modrinth, ATLauncher, FTB, and Technic.

## Local Mod Management

### ModFolderModel (`minecraft/mod/ModFolderModel.h`)

`ModFolderModel` is a `QAbstractListModel` that represents the contents of a mod directory (e.g., `<instance>/.minecraft/mods/`):

```cpp
class ModFolderModel : public QAbstractListModel
{
    Q_OBJECT
public:
    enum Columns {
        ActiveColumn = 0,   // Enabled/disabled toggle
        NameColumn,          // Mod name
        VersionColumn,       // Mod version
        DateColumn,          // File modification date
        NUM_COLUMNS
    };

    enum ModStatusAction { Disable, Enable, Toggle };

    ModFolderModel(const QString& dir);

    // Model interface
    QVariant data(const QModelIndex& index, int role) const override;
    bool setData(const QModelIndex& index, const QVariant& value,
                 int role) override;
    Qt::DropActions supportedDropActions() const override;
    Qt::ItemFlags flags(const QModelIndex& index) const override;
    QStringList mimeTypes() const override;
    bool dropMimeData(const QMimeData* data, Qt::DropAction action,
                      int row, int column, const QModelIndex& parent) override;
    int rowCount(const QModelIndex&) const override;
    QVariant headerData(int section, Qt::Orientation orientation,
                        int role) const override;
    int columnCount(const QModelIndex& parent) const override;

    size_t size() const;
    bool empty() const;
    Mod& operator[](size_t index);
};
```

Key features:
- **Drag and drop** — users can drag mod files into the view to install them
- **Enable/disable** — toggling a mod renames the file (`.jar` ↔ `.jar.disabled`)
- **Automatic refresh** — directory changes are detected via `QFileSystemWatcher`
- **Column sorting** — by name, version, or date

### Mod Class (`minecraft/mod/Mod.h`)

The `Mod` class represents a single mod file:

```cpp
class Mod {
public:
    enum ModType {
        MOD_UNKNOWN,    // Unknown format
        MOD_ZIPFILE,    // ZIP/JAR with metadata
        MOD_SINGLEFILE, // Single file (no metadata)
        MOD_FOLDER,     // Directory mod
        MOD_LITEMOD     // LiteLoader mod (.litemod)
    };

    Mod(const QFileInfo& file);

    QString name() const;
    QString version() const;
    QString homeurl() const;
    QString description() const;
    QStringList authors() const;
    QDateTime dateTimeChanged() const;

    bool enable(bool value);  // Enable or disable
    bool enabled() const;
    ModType type() const;
};
```

### ModDetails (`minecraft/mod/ModDetails.h`)

Extracted metadata from mod files:

```cpp
struct ModDetails {
    QString mod_id;
    QString name;
    QString version;
    QString description;
    QStringList authors;
    QString homeurl;
    QStringList loaders;     // Compatible mod loaders
};
```

### Mod Metadata Extraction (`minecraft/mod/LocalModParseTask.h`)

`LocalModParseTask` runs in a background thread to parse metadata from mod JAR/ZIP files:

```cpp
class LocalModParseTask : public QObject {
    Q_OBJECT
public:
    LocalModParseTask(int token, Mod::ModType type,
                      const QFileInfo& modFile);
signals:
    void metadataReady(int token, ModDetails details);
};
```

Supported metadata formats:
- **Forge** — `mcmod.info` (JSON, legacy) and `mods.toml` (TOML, modern)
- **Fabric** — `fabric.mod.json` (JSON)
- **Quilt** — `quilt.mod.json` (JSON)
- **LiteLoader** — `litemod.json` (JSON)

The parser uses `tomlc99` for TOML parsing and Qt's JSON facilities for JSON.

### ModFolderLoadTask (`minecraft/mod/ModFolderLoadTask.h`)

Background task that scans a mod directory and creates `Mod` objects:

```cpp
class ModFolderLoadTask : public QObject {
    Q_OBJECT
public:
    ModFolderLoadTask(const QString& dir);
    void run();
signals:
    void succeeded();
};
```

This task:
1. Enumerates all files in the mod directory
2. Creates `Mod` objects for each `.jar`, `.zip`, `.litemod`, `.disabled`, and directory entry
3. Emits `succeeded()` when scanning is complete
4. The `ModFolderModel` then triggers `LocalModParseTask` for each mod to extract metadata

### Resource Pack and Texture Pack Models

Similar models exist for resource packs and texture packs:

```cpp
class ResourcePackFolderModel : public ModFolderModel {
    // Manages <instance>/.minecraft/resourcepacks/
};

class TexturePackFolderModel : public ModFolderModel {
    // Manages <instance>/.minecraft/texturepacks/
};
```

These inherit from `ModFolderModel` but specialize for their respective content types.

## Mod Platform Integrations

### Directory Structure

```
launcher/modplatform/
├── atlauncher/     # ATLauncher API client
├── flame/          # CurseForge (Flame) API client
├── legacy_ftb/     # Legacy FTB modpack support
├── modpacksch/     # FTB/modpacksch API (modern)
├── modrinth/       # Modrinth API client
└── technic/        # Technic Platform API client
```

### CurseForge Integration (`modplatform/flame/`)

CurseForge (internally called "Flame") integration provides:

- **Mod search** — query CurseForge's API for mods compatible with the instance's game version and loader
- **Modpack installation** — download and install complete CurseForge modpacks
- **Mod installation** — download individual mods and place them in the mods folder
- **Version resolution** — select the correct mod version for the instance's configuration

API authentication uses the `MeshMC_CURSEFORGE_API_KEY` set at build time:

```cmake
set(MeshMC_CURSEFORGE_API_KEY "$2a$10$..." CACHE STRING
    "API key for the CurseForge API")
```

### Modrinth Integration (`modplatform/modrinth/`)

Modrinth integration provides:

- **Mod search** — query Modrinth's API for mods
- **Modpack installation** — download and install Modrinth modpacks (`.mrpack` format)
- **Mod installation** — download and install individual mods
- **Version filtering** — filter by game version, loader, and project type

Modrinth uses a public API and does not require an API key for basic operations.

### ATLauncher Integration (`modplatform/atlauncher/`)

ATLauncher support enables importing ATLauncher modpack definitions:

- Parse ATLauncher pack JSON manifests
- Download required mods and configurations
- Create a new instance with the correct components

### FTB/modpacksch Integration (`modplatform/modpacksch/`)

Modern FTB modpack support via the modpacksch API:

- Browse available FTB modpacks
- Download and install modpacks
- Handle FTB-specific pack format

### Legacy FTB Integration (`modplatform/legacy_ftb/`)

Support for the older FTB modpack format:

- Parse legacy FTB pack definitions
- Import packs from FTB launcher directories

### Technic Integration (`modplatform/technic/`)

Technic Platform support:

- Browse Technic modpacks
- Download and install Technic packs
- Handle Technic's ZIP-based pack format

## Mod Installation Flow

### From Platform Browse Page

1. User opens a mod platform page (CurseForge/Modrinth) from the instance settings
2. Searches or browses for a mod
3. Selects a version compatible with their instance
4. MeshMC creates a `Download` via `NetJob` to fetch the mod file
5. The mod file is placed in `<instance>/.minecraft/mods/`
6. `ModFolderModel` detects the new file and updates the listing
7. `LocalModParseTask` extracts metadata for display

### From Drag and Drop

1. User drags a `.jar` file onto the mod list in `ModFolderPage`
2. Qt's drag-and-drop system fires `ModFolderModel::dropMimeData()`
3. The file is copied to the mods directory
4. The model updates automatically

### From File Dialog

1. User clicks "Add" in `ModFolderPage`
2. A `QFileDialog` opens for file selection
3. Selected files are copied to the mods directory
4. The model refreshes

## Modpack Import

### Overview

Modpack import is handled through `InstanceImportTask` and platform-specific import logic:

```
User selects modpack file/URL
    │
    ▼
InstanceImportTask::executeTask()
    │
    ├── Detect format (CurseForge manifest, Modrinth mrpack, etc.)
    │
    ├── CurseForge: parse manifest.json → download mods → set up instance
    ├── Modrinth: parse modrinth.index.json → download mods → set up instance
    ├── ATLauncher: parse ATL config → download mods → set up instance
    ├── Technic: extract ZIP → set up instance
    └── Generic: extract ZIP → copy files → set up instance
```

### CurseForge Modpack Format

CurseForge modpacks contain a `manifest.json`:
```json
{
    "minecraft": {
        "version": "1.20.4",
        "modLoaders": [
            { "id": "forge-49.0.19", "primary": true }
        ]
    },
    "files": [
        { "projectID": 123456, "fileID": 789012, "required": true }
    ]
}
```

MeshMC parses this manifest, creates components for the game version and mod loader, then downloads each mod file by its CurseForge project/file IDs.

### Modrinth Modpack Format (`.mrpack`)

Modrinth packs use the `.mrpack` format (ZIP with `modrinth.index.json`):
```json
{
    "formatVersion": 1,
    "game": "minecraft",
    "versionId": "1.0.0",
    "dependencies": {
        "minecraft": "1.20.4",
        "fabric-loader": "0.15.6"
    },
    "files": [
        {
            "path": "mods/sodium-0.5.5.jar",
            "hashes": { "sha1": "...", "sha512": "..." },
            "downloads": ["https://cdn.modrinth.com/..."]
        }
    ]
}
```

### Blocked Mods Handling

Some mods on CurseForge restrict third-party downloads. `BlockedModsDialog` handles this case:

```cpp
class BlockedModsDialog : public QDialog {
    // Shows a list of mods that couldn't be auto-downloaded
    // Provides manual download links for the user
};
```

## Mod Enable/Disable Mechanism

MeshMC enables and disables mods by renaming files:

```cpp
bool Mod::enable(bool value);
```

- **Disable**: Rename `modname.jar` → `modname.jar.disabled`
- **Enable**: Rename `modname.jar.disabled` → `modname.jar`

This approach ensures disabled mods are not loaded by the game's mod loader while remaining in the directory for easy re-enabling.

## Mod Folder Page (`ui/pages/instance/ModFolderPage.h`)

`ModFolderPage` provides the UI for managing mods within an instance:

```cpp
class ModFolderPage : public QMainWindow, public BasePage {
    Q_OBJECT
};
```

Features:
- List view with columns: Active (checkbox), Name, Version, Date
- Add button — file dialog for selecting mod files
- Remove button — delete selected mods
- Enable/Disable button — toggle selection
- View folder button — open the mods directory in the file manager
- Mod details panel showing name, version, authors, description, homepage URL

## Shader Packs and Resource Packs

MeshMC provides similar management for other content types:

| Content Type | Directory | Page Class | Model |
|---|---|---|---|
| Mods | `.minecraft/mods/` | `ModFolderPage` | `ModFolderModel` |
| Resource Packs | `.minecraft/resourcepacks/` | `ResourcePackPage` | `ResourcePackFolderModel` |
| Texture Packs | `.minecraft/texturepacks/` | `TexturePackPage` | `TexturePackFolderModel` |
| Shader Packs | `.minecraft/shaderpacks/` | `ShaderPackPage` | `ModFolderModel` |

`ResourcePackPage`, `TexturePackPage`, and `ShaderPackPage` are thin wrappers around `ModFolderPage`:

```cpp
// ShaderPackPage.h
class ShaderPackPage : public ModFolderPage {
    // Specializes base path and file filters for shader packs
};
```

## World Management

While not strictly part of the mod system, world management follows a similar pattern:

### WorldList (`minecraft/WorldList.h`)

```cpp
class WorldList : public QAbstractListModel {
    Q_OBJECT
public:
    WorldList(const QString& dir);
    // Provides list of worlds with name, last played, game mode
};
```

### World (`minecraft/World.h`)

```cpp
class World {
public:
    World(const QFileInfo& file);
    QString name() const;
    // Reads level.dat for world metadata
};
```

The `WorldListPage` provides UI for browsing, adding, copying, and deleting worlds.