Skip to main content

minecraft_java_rs_core/models/
loader.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6// ── Loader type enum ─────────────────────────────────────────────────────────
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
9#[serde(rename_all = "lowercase")]
10pub enum LoaderType {
11    Forge,
12    NeoForge,
13    Fabric,
14    // serde rename_all = "lowercase" produces "legacyfabric" ✓
15    LegacyFabric,
16    Quilt,
17}
18
19impl std::fmt::Display for LoaderType {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        let s = match self {
22            LoaderType::Forge => "forge",
23            LoaderType::NeoForge => "neoforge",
24            LoaderType::Fabric => "fabric",
25            LoaderType::LegacyFabric => "legacyfabric",
26            LoaderType::Quilt => "quilt",
27        };
28        f.write_str(s)
29    }
30}
31
32// ── Common loader library ────────────────────────────────────────────────────
33// Used by Fabric, Quilt, Forge, and NeoForge installer JSONs.
34// Simpler than the Mojang `Library` type: no native classifiers, and `rules`
35// is treated as opaque (we only check presence, not content).
36
37#[derive(Debug, Deserialize, Serialize)]
38pub struct LoaderLibrary {
39    pub name: String,
40    /// Base Maven repository URL (Fabric: `"https://maven.fabricmc.net"`).
41    #[serde(default)]
42    pub url: Option<String>,
43    pub downloads: Option<LoaderLibraryDownloads>,
44    /// When present (any value), this library should be skipped.
45    #[serde(default)]
46    pub rules: Option<Vec<Value>>,
47}
48
49#[derive(Debug, Deserialize, Serialize)]
50pub struct LoaderLibraryDownloads {
51    pub artifact: Option<LoaderArtifact>,
52}
53
54#[derive(Debug, Deserialize, Serialize)]
55pub struct LoaderArtifact {
56    pub sha1: Option<String>,
57    pub size: Option<u64>,
58    pub path: Option<String>,
59    pub url: String,
60}
61
62// ── Fabric / LegacyFabric / Quilt ────────────────────────────────────────────
63
64/// Response from `meta.fabricmc.net/v2/versions` (and equivalents for Quilt/LegacyFabric).
65#[derive(Debug, Deserialize)]
66pub struct FabricMeta {
67    pub game: Vec<FabricGameVersion>,
68    pub loader: Vec<FabricLoaderBuild>,
69}
70
71#[derive(Debug, Deserialize)]
72pub struct FabricGameVersion {
73    pub version: String,
74    pub stable: bool,
75}
76
77#[derive(Debug, Deserialize)]
78pub struct FabricLoaderBuild {
79    pub version: String,
80    pub stable: bool,
81}
82
83/// Quilt's loader build has extra fields and no `stable` flag.
84#[derive(Debug, Deserialize)]
85pub struct QuiltLoaderBuild {
86    pub version: String,
87    #[serde(default)]
88    pub stable: bool,
89}
90
91#[derive(Debug, Deserialize)]
92pub struct QuiltMeta {
93    pub game: Vec<FabricGameVersion>,
94    pub loader: Vec<QuiltLoaderBuild>,
95}
96
97/// Profile JSON fetched from the Fabric/Quilt meta API
98/// (e.g. `meta.fabricmc.net/v2/versions/loader/{mc}/{build}/profile/json`).
99#[derive(Debug, Deserialize, Serialize)]
100#[serde(rename_all = "camelCase")]
101pub struct FabricJson {
102    pub id: String,
103    #[serde(default)]
104    pub libraries: Vec<LoaderLibrary>,
105    pub main_class: Option<String>,
106    pub minecraft_arguments: Option<String>,
107    #[serde(flatten)]
108    pub extra: HashMap<String, Value>,
109}
110
111// ── Forge / NeoForge ─────────────────────────────────────────────────────────
112// `install_profile.json` is highly dynamic. Critical fields are typed;
113// the rest is captured in `extra` to round-trip without data loss.
114
115/// Variable entry in the Forge profile `data` map.
116/// Each variable has a `client` value (and sometimes `server`).
117#[derive(Debug, Clone, Deserialize, Serialize, Default)]
118pub struct ProfileDataEntry {
119    pub client: String,
120    #[serde(default)]
121    pub server: Option<String>,
122}
123
124/// `arguments` block inside a Forge/NeoForge version JSON (1.13+ format).
125#[derive(Debug, Deserialize, Serialize, Default)]
126pub struct ForgeArguments {
127    #[serde(default)]
128    pub game: Vec<serde_json::Value>,
129    #[serde(default)]
130    pub jvm: Vec<serde_json::Value>,
131}
132
133/// Top-level `install_profile.json`. Dual format:
134/// - **Old format** (pre-1.13): has a top-level `install` key → the profile IS `install`.
135/// - **New format** (1.13+): `install` and `version` are separate sections.
136#[derive(Debug, Deserialize, Serialize, Default)]
137#[serde(default)]
138pub struct ForgeProfile {
139    pub install: Option<ForgeInstallSection>,
140    pub version: Option<ForgeVersionSection>,
141    /// Variable map used by processors (`{BINPATCH}`, `{MAPPINGS}`, etc.).
142    /// Present in new-format (1.13+) profiles.
143    pub data: Option<HashMap<String, ProfileDataEntry>>,
144    /// Path within the installer ZIP to the primary artifact (old format).
145    pub file_path: Option<String>,
146    /// Maven coordinate of the primary Forge artifact (old format).
147    pub path: Option<String>,
148    pub processors: Option<Vec<ForgeProcessor>>,
149    pub libraries: Option<Vec<LoaderLibrary>>,
150}
151
152#[derive(Debug, Deserialize, Serialize, Default)]
153#[serde(rename_all = "camelCase", default)]
154pub struct ForgeInstallSection {
155    pub libraries: Option<Vec<LoaderLibrary>>,
156    /// Name of the version JSON file inside the installer JAR.
157    pub json: Option<String>,
158    pub path: Option<String>,
159    pub file_path: Option<String>,
160    pub minecraft: Option<String>,
161    pub processors: Option<Vec<ForgeProcessor>>,
162    #[serde(flatten)]
163    pub extra: HashMap<String, Value>,
164}
165
166#[derive(Debug, Deserialize, Serialize, Default)]
167#[serde(rename_all = "camelCase", default)]
168pub struct ForgeVersionSection {
169    pub id: Option<String>,
170    pub libraries: Option<Vec<LoaderLibrary>>,
171    pub main_class: Option<String>,
172    pub minecraft_arguments: Option<String>,
173    /// Modern 1.13+ argument block (game/jvm arrays).
174    pub arguments: Option<ForgeArguments>,
175    #[serde(flatten)]
176    pub extra: HashMap<String, Value>,
177}
178
179/// A Forge installer processor: a Java tool that patches/transforms Minecraft files.
180#[derive(Debug, Deserialize, Serialize)]
181pub struct ForgeProcessor {
182    pub jar: String,
183    pub classpath: Vec<String>,
184    pub args: Vec<String>,
185    #[serde(default)]
186    pub sides: Option<Vec<String>>,
187}
188
189// ── Internal result types (not from JSON) ────────────────────────────────────
190
191/// Result of a successful installer JAR download.
192#[derive(Debug)]
193pub struct InstallerInfo {
194    pub file_path: String,
195    pub meta_data: String,
196    pub ext: String,
197    pub id: String,
198    /// NeoForge only: whether to use the legacy (1.20.1-era) API path.
199    pub old_api: bool,
200}