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
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
|
# Instance Management
## Overview
Instance management is central to MeshMC's design. An "instance" is a self-contained Minecraft environment with its own game version, mods, settings, saves, resource packs, and configuration. MeshMC stores multiple instances in parallel, allowing users to maintain entirely separate Minecraft setups.
## Instance Storage Layout
### Instance Root Directory
All instances live under a single parent directory, configurable in settings (default: `instances/` within the MeshMC data directory). Each instance occupies its own subdirectory:
```
instances/
├── MyVanilla1.20/
│ ├── instance.cfg # Instance-level settings (INI format)
│ ├── mmc-pack.json # Component list (PackProfile)
│ ├── patches/ # Custom component overrides (JSON)
│ ├── .minecraft/ # Game directory
│ │ ├── mods/ # Loader mods
│ │ ├── resourcepacks/ # Resource packs
│ │ ├── shaderpacks/ # Shader packs
│ │ ├── saves/ # World saves
│ │ ├── config/ # Mod configuration
│ │ ├── options.txt # Game options
│ │ ├── screenshots/ # Screenshots
│ │ └── logs/ # Game logs
│ └── libraries/ # Instance-local libraries
├── ForgeModded/
│ ├── instance.cfg
│ ├── mmc-pack.json
│ ├── patches/
│ └── .minecraft/
└── ...
```
### Instance Configuration File (`instance.cfg`)
Each instance has an `instance.cfg` file (INI format) managed by `INISettingsObject`. This stores per-instance metadata and setting overrides:
```ini
InstanceType=OneSix
name=My Modded Instance
iconKey=flame
notes=Testing Forge 1.20.4 with performance mods
lastLaunchTime=1712345678000
totalTimePlayed=3600
lastTimePlayed=1800
JoinServerOnLaunch=false
OverrideJavaPath=true
JavaPath=/usr/lib/jvm/java-21/bin/java
OverrideMemory=true
MinMemAlloc=2048
MaxMemAlloc=8192
```
## BaseInstance Class
`BaseInstance` is the abstract base class for all instance types, defined in `launcher/BaseInstance.h`:
```cpp
class BaseInstance : public QObject,
public std::enable_shared_from_this<BaseInstance>
{
Q_OBJECT
protected:
BaseInstance(SettingsObjectPtr globalSettings,
SettingsObjectPtr settings,
const QString& rootDir);
public:
enum class Status { Present, Gone };
virtual void saveNow() = 0;
void invalidate();
virtual QString id() const;
void setRunning(bool running);
bool isRunning() const;
int64_t totalTimePlayed() const;
int64_t lastTimePlayed() const;
void resetTimePlayed();
QString instanceType() const;
QString instanceRoot() const;
virtual QString gameRoot() const { return instanceRoot(); }
virtual QString modsRoot() const = 0;
QString name() const;
void setName(QString val);
QString windowTitle() const;
QString iconKey() const;
void setIconKey(QString val);
QString notes() const;
void setNotes(QString val);
QString getPreLaunchCommand();
QString getPostExitCommand();
QString getWrapperCommand();
virtual QSet<QString> traits() const = 0;
qint64 lastLaunch() const;
void setLastLaunch(qint64 val);
virtual SettingsObjectPtr settings() const;
virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
virtual shared_qobject_ptr<LaunchTask>
createLaunchTask(AuthSessionPtr account,
MinecraftServerTargetPtr serverToJoin) = 0;
shared_qobject_ptr<LaunchTask> getLaunchTask();
virtual QProcessEnvironment createEnvironment() = 0;
virtual IPathMatcher::Ptr getLogFileMatcher() = 0;
virtual QString getLogFileRoot() = 0;
};
typedef std::shared_ptr<BaseInstance> InstancePtr;
```
Key characteristics:
- Uses `std::enable_shared_from_this` for safe self-reference in callbacks
- Instance ID is determined internally by MeshMC (typically the directory name)
- Tracks play time (total and last session) in milliseconds
- Supports custom pre-launch, post-exit, and wrapper commands
- `traits()` returns feature flags from the version profile (e.g., `"XR:Initial"`, `"FirstThreadOnMacOS"`)
## MinecraftInstance
`MinecraftInstance` is the concrete implementation of `BaseInstance` for modern Minecraft versions, defined in `launcher/minecraft/MinecraftInstance.h`:
```cpp
class MinecraftInstance : public BaseInstance
{
Q_OBJECT
public:
MinecraftInstance(SettingsObjectPtr globalSettings,
SettingsObjectPtr settings,
const QString& rootDir);
// Directory accessors
QString jarModsDir() const;
QString resourcePacksDir() const;
QString texturePacksDir() const;
QString shaderPacksDir() const;
QString modsRoot() const override;
QString coreModsDir() const;
QString modsCacheLocation() const;
QString libDir() const;
QString worldDir() const;
QString resourcesDir() const;
QDir jarmodsPath() const;
QDir librariesPath() const;
QDir versionsPath() const;
QString instanceConfigFolder() const override;
QString gameRoot() const override;
QString binRoot() const;
QString getNativePath() const;
QString getLocalLibraryPath() const;
// Component system
std::shared_ptr<PackProfile> getPackProfile() const;
// Mod folder models
std::shared_ptr<ModFolderModel> loaderModList() const;
std::shared_ptr<ModFolderModel> coreModList() const;
std::shared_ptr<ModFolderModel> resourcePackList() const;
std::shared_ptr<ModFolderModel> texturePackList() const;
std::shared_ptr<ModFolderModel> shaderPackList() const;
std::shared_ptr<WorldList> worldList() const;
std::shared_ptr<GameOptions> gameOptionsModel() const;
// Launch
Task::Ptr createUpdateTask(Net::Mode mode) override;
shared_qobject_ptr<LaunchTask>
createLaunchTask(AuthSessionPtr account,
MinecraftServerTargetPtr serverToJoin) override;
QStringList javaArguments() const;
QStringList getClassPath() const;
QStringList getNativeJars() const;
QString getMainClass() const;
QStringList processMinecraftArgs(AuthSessionPtr account,
MinecraftServerTargetPtr serverToJoin) const;
JavaVersion getJavaVersion() const;
};
```
`MinecraftInstance` provides:
- All directory path resolution for game assets
- Lazy-initialized folder models (`ModFolderModel`, `WorldList`, etc.)
- Launch task construction with the full step pipeline
- Java argument assembly including classpath, library paths, and game arguments
- Version-specific behaviors via traits
## InstanceList
`InstanceList` manages the collection of all instances, defined in `launcher/InstanceList.h`:
```cpp
class InstanceList : public QAbstractListModel
{
Q_OBJECT
public:
explicit InstanceList(SettingsObjectPtr settings,
const QString& instDir, QObject* parent = 0);
// Model interface
QModelIndex index(int row, int column = 0,
const QModelIndex& parent = QModelIndex()) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role) const override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
bool setData(const QModelIndex& index, const QVariant& value,
int role) override;
enum AdditionalRoles {
GroupRole = Qt::UserRole,
InstancePointerRole = 0x34B1CB48,
InstanceIDRole = 0x34B1CB49
};
InstancePtr at(int i) const { return m_instances.at(i); }
};
```
### Instance Discovery
On startup, `InstanceList` scans the instances directory:
1. Enumerates subdirectories in the instances folder
2. For each directory, looks for `instance.cfg`
3. Reads `InstanceType` from the config to determine the instance class
4. Creates the appropriate instance object (`MinecraftInstance`)
5. Adds it to the internal list and emits model change signals
### Custom Model Roles
| Role | Value | Returns |
|---|---|---|
| `GroupRole` | `Qt::UserRole` | Group name (QString) |
| `InstancePointerRole` | `0x34B1CB48` | `InstancePtr` (shared pointer) |
| `InstanceIDRole` | `0x34B1CB49` | Instance ID (QString) |
## Instance Groups
Instances can be organized into named groups. Group assignments are stored in `instgroups.json` in the data directory:
```json
{
"formatVersion": 1,
"groups": {
"Modded": {
"hidden": false,
"instances": [
"ForgeModded",
"FabricServer"
]
},
"Vanilla": {
"hidden": false,
"instances": [
"MyVanilla1.20"
]
}
}
}
```
Group state tracking uses a tri-state enum:
```cpp
enum class GroupsState { NotLoaded, Steady, Dirty };
```
Groups are loaded lazily and saved when dirty. The `GroupRole` in the model provides group information for UI display.
## Instance Creation
### New Instance Creation
New instances are created via `NewInstanceDialog`, which collects:
- Instance name and icon
- Minecraft version selection
- Optional mod loader (Forge, Fabric, Quilt, NeoForge)
- Optional modpack import
The actual creation is handled by `InstanceCreationTask`:
1. Creates the instance directory
2. Writes initial `instance.cfg`
3. Creates a `PackProfile` with the selected components
4. Saves the component list to `mmc-pack.json`
5. Runs `ComponentUpdateTask` to resolve dependencies and download metadata
### Instance Import
`InstanceImportTask` handles importing instances from external sources:
```cpp
class InstanceImportTask : public InstanceTask
{
Q_OBJECT
public:
explicit InstanceImportTask(const QUrl& url);
protected:
virtual void executeTask() override;
};
```
Supported import formats:
- **ZIP archives** — exported MeshMC/MultiMC instance packages
- **URLs** — downloads and extracts (supports CurseForge, Modrinth, and Technic pack URLs)
- **Modpack manifests** — platform-specific manifests trigger specialized import logic
### Instance Copying
`InstanceCopyTask` clones an existing instance:
```cpp
class InstanceCopyTask : public InstanceTask
{
Q_OBJECT
public:
explicit InstanceCopyTask(InstancePtr origInstance,
bool copySaves, bool keepPlaytime);
protected:
virtual void executeTask() override;
private:
InstancePtr m_origInstance;
QFuture<bool> m_copyFuture;
QFutureWatcher<bool> m_copyFutureWatcher;
std::unique_ptr<IPathMatcher> m_matcher;
bool m_keepPlaytime;
};
```
Key options:
- `copySaves` — whether to include world save data
- `keepPlaytime` — whether to copy playtime statistics
- Uses `QtConcurrent` for background file copying with progress tracking
- An `IPathMatcher` can exclude specific files/directories from the copy
The copy dialog is `CopyInstanceDialog`:
```cpp
class CopyInstanceDialog : public QDialog
// UI file: CopyInstanceDialog.ui
```
## Instance Lifecycle States
An instance progresses through several states during its lifetime:
```
Created → Present → [Running] → Present → [Gone]
```
The `BaseInstance::Status` enum tracks the primary state:
```cpp
enum class Status {
Present, // Instance exists and is tracked
Gone // Instance was removed or invalidated
};
```
Running state is tracked separately:
```cpp
void BaseInstance::setRunning(bool running);
bool BaseInstance::isRunning() const;
```
When running:
- Play time counters are updated
- The instance icon shows a running indicator in the UI
- Certain operations are disabled (delete, move, etc.)
## Instance Invalidation
```cpp
void BaseInstance::invalidate();
```
An instance is invalidated when:
- Its directory is externally deleted or moved
- A `RecursiveFileSystemWatcher` detects the directory change
- The `InstanceList` removes it from its model
## Instance Settings Override System
Each instance has its own `SettingsObject` that can override global settings:
```cpp
virtual SettingsObjectPtr settings() const;
```
The override mechanism uses `OverrideSetting`:
- A **gate setting** (boolean) controls whether the override is active
- When the gate is ON, the instance's local value is used
- When the gate is OFF, the global value is passed through
Common overridable settings:
| Setting | Gate Setting | Purpose |
|---|---|---|
| `JavaPath` | `OverrideJavaPath` | Java binary path |
| `MinMemAlloc` | `OverrideMemory` | Minimum memory (MB) |
| `MaxMemAlloc` | `OverrideMemory` | Maximum memory (MB) |
| `JvmArgs` | `OverrideJavaArgs` | Additional JVM arguments |
| `MCLaunchMethod` | `OverrideMCLaunchMethod` | Launch method |
| `PreLaunchCommand` | `OverrideCommands` | Pre-launch command |
| `PostExitCommand` | `OverrideCommands` | Post-exit command |
| `WrapperCommand` | `OverrideCommands` | Wrapper command |
| `WindowWidth` | `OverrideWindow` | Window width |
| `WindowHeight` | `OverrideWindow` | Window height |
| `MaximizeWindow` | `OverrideWindow` | Start maximized |
The `InstanceSettingsPage` UI provides checkboxes for each gate setting, enabling or disabling the corresponding override section.
## Instance UI Integration
### Instance View
The main window displays instances in a custom view (`InstanceView` in `ui/instanceview/`):
- Grid or list layout
- Group headers with collapse/expand
- Drag and drop between groups
- Context menu for instance operations
- Icon display with status overlay (running indicator)
### Instance Pages
When editing an instance, a `PageDialog` opens with these pages:
| Page | File | Purpose |
|---|---|---|
| `VersionPage` | `ui/pages/instance/VersionPage.{h,cpp}` | Component management |
| `ModFolderPage` | `ui/pages/instance/ModFolderPage.{h,cpp}` | Mod list |
| `ResourcePackPage` | `ui/pages/instance/ResourcePackPage.h` | Resource packs |
| `TexturePackPage` | `ui/pages/instance/TexturePackPage.h` | Texture packs |
| `ShaderPackPage` | `ui/pages/instance/ShaderPackPage.h` | Shader packs |
| `NotesPage` | `ui/pages/instance/NotesPage.{h,cpp}` | Instance notes |
| `LogPage` | `ui/pages/instance/LogPage.{h,cpp}` | Game log viewer |
| `ScreenshotsPage` | `ui/pages/instance/ScreenshotsPage.{h,cpp}` | Screenshots |
| `WorldListPage` | `ui/pages/instance/WorldListPage.{h,cpp}` | World management |
| `GameOptionsPage` | `ui/pages/instance/GameOptionsPage.{h,cpp}` | Game options editor |
| `ServersPage` | `ui/pages/instance/ServersPage.{h,cpp}` | Server list editor |
| `InstanceSettingsPage` | `ui/pages/instance/InstanceSettingsPage.{h,cpp}` | Settings overrides |
| `OtherLogsPage` | `ui/pages/instance/OtherLogsPage.{h,cpp}` | Additional log files |
### Instance Window
`InstanceWindow` provides a dedicated window for a running instance:
```cpp
class InstanceWindow : public QMainWindow
{
Q_OBJECT
};
```
It displays:
- Real-time game log output via `LogModel`
- Launch/kill controls
- Instance page navigation
## Instance Export
`ExportInstanceDialog` allows exporting an instance to a ZIP archive:
- Select which files/directories to include
- Exclude sensitive data, caches, and temporary files
- The exported archive can be imported by MeshMC on another machine
## Play Time Tracking
Each instance tracks cumulative play time:
```cpp
int64_t BaseInstance::totalTimePlayed() const;
int64_t BaseInstance::lastTimePlayed() const;
void BaseInstance::resetTimePlayed();
```
- `totalTimePlayed` — cumulative milliseconds across all sessions
- `lastTimePlayed` — duration of the most recent session
- Time is recorded when `setRunning(false)` is called after a session
- Stored in `instance.cfg` as `totalTimePlayed` and `lastTimePlayed`
|