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    /// Old-format Forge only: `false` means this library is server-only.
48    #[serde(default)]
49    pub clientreq: Option<bool>,
50}
51
52#[derive(Debug, Deserialize, Serialize)]
53pub struct LoaderLibraryDownloads {
54    pub artifact: Option<LoaderArtifact>,
55}
56
57#[derive(Debug, Deserialize, Serialize)]
58pub struct LoaderArtifact {
59    pub sha1: Option<String>,
60    pub size: Option<u64>,
61    pub path: Option<String>,
62    pub url: String,
63}
64
65// ── Fabric / LegacyFabric / Quilt ────────────────────────────────────────────
66
67/// Response from `meta.fabricmc.net/v2/versions` (and equivalents for Quilt/LegacyFabric).
68#[derive(Debug, Deserialize)]
69pub struct FabricMeta {
70    pub game: Vec<FabricGameVersion>,
71    pub loader: Vec<FabricLoaderBuild>,
72}
73
74#[derive(Debug, Deserialize)]
75pub struct FabricGameVersion {
76    pub version: String,
77    pub stable: bool,
78}
79
80#[derive(Debug, Deserialize)]
81pub struct FabricLoaderBuild {
82    pub version: String,
83    pub stable: bool,
84}
85
86/// Quilt's loader build has extra fields and no `stable` flag.
87#[derive(Debug, Deserialize)]
88pub struct QuiltLoaderBuild {
89    pub version: String,
90    #[serde(default)]
91    pub stable: bool,
92}
93
94#[derive(Debug, Deserialize)]
95pub struct QuiltMeta {
96    pub game: Vec<FabricGameVersion>,
97    pub loader: Vec<QuiltLoaderBuild>,
98}
99
100/// Profile JSON fetched from the Fabric/Quilt meta API
101/// (e.g. `meta.fabricmc.net/v2/versions/loader/{mc}/{build}/profile/json`).
102#[derive(Debug, Deserialize, Serialize)]
103#[serde(rename_all = "camelCase")]
104pub struct FabricJson {
105    pub id: String,
106    #[serde(default)]
107    pub libraries: Vec<LoaderLibrary>,
108    pub main_class: Option<String>,
109    pub minecraft_arguments: Option<String>,
110    #[serde(flatten)]
111    pub extra: HashMap<String, Value>,
112}
113
114// ── Forge / NeoForge ─────────────────────────────────────────────────────────
115// `install_profile.json` is highly dynamic. Critical fields are typed;
116// the rest is captured in `extra` to round-trip without data loss.
117
118/// Variable entry in the Forge profile `data` map.
119/// Each variable has a `client` value (and sometimes `server`).
120#[derive(Debug, Clone, Deserialize, Serialize, Default)]
121pub struct ProfileDataEntry {
122    pub client: String,
123    #[serde(default)]
124    pub server: Option<String>,
125}
126
127/// `arguments` block inside a Forge/NeoForge version JSON (1.13+ format).
128#[derive(Debug, Deserialize, Serialize, Default)]
129pub struct ForgeArguments {
130    #[serde(default)]
131    pub game: Vec<serde_json::Value>,
132    #[serde(default)]
133    pub jvm: Vec<serde_json::Value>,
134}
135
136/// Top-level `install_profile.json`. Dual format:
137/// - **Old format** (pre-1.13): has a top-level `install` key → the profile IS `install`.
138/// - **New format** (1.13+): `install` and `version` are separate sections.
139#[derive(Debug, Deserialize, Serialize, Default)]
140#[serde(default)]
141pub struct ForgeProfile {
142    pub install: Option<ForgeInstallSection>,
143    pub version: Option<ForgeVersionSection>,
144    /// Variable map used by processors (`{BINPATCH}`, `{MAPPINGS}`, etc.).
145    /// Present in new-format (1.13+) profiles.
146    pub data: Option<HashMap<String, ProfileDataEntry>>,
147    /// Path within the installer ZIP to the primary artifact (old format).
148    pub file_path: Option<String>,
149    /// Maven coordinate of the primary Forge artifact (old format).
150    pub path: Option<String>,
151    pub processors: Option<Vec<ForgeProcessor>>,
152    pub libraries: Option<Vec<LoaderLibrary>>,
153    /// Old-format (pre-1.13) Forge: the full version JSON embedded inline.
154    #[serde(rename = "versionInfo", default)]
155    pub version_info: Option<ForgeVersionSection>,
156}
157
158#[derive(Debug, Deserialize, Serialize, Default)]
159#[serde(rename_all = "camelCase", default)]
160pub struct ForgeInstallSection {
161    pub libraries: Option<Vec<LoaderLibrary>>,
162    /// Name of the version JSON file inside the installer JAR.
163    pub json: Option<String>,
164    pub path: Option<String>,
165    pub file_path: Option<String>,
166    pub minecraft: Option<String>,
167    pub processors: Option<Vec<ForgeProcessor>>,
168    #[serde(flatten)]
169    pub extra: HashMap<String, Value>,
170}
171
172#[derive(Debug, Deserialize, Serialize, Default)]
173#[serde(rename_all = "camelCase", default)]
174pub struct ForgeVersionSection {
175    pub id: Option<String>,
176    pub libraries: Option<Vec<LoaderLibrary>>,
177    pub main_class: Option<String>,
178    pub minecraft_arguments: Option<String>,
179    /// Modern 1.13+ argument block (game/jvm arrays).
180    pub arguments: Option<ForgeArguments>,
181    #[serde(flatten)]
182    pub extra: HashMap<String, Value>,
183}
184
185/// A Forge installer processor: a Java tool that patches/transforms Minecraft files.
186#[derive(Debug, Deserialize, Serialize)]
187pub struct ForgeProcessor {
188    pub jar: String,
189    pub classpath: Vec<String>,
190    pub args: Vec<String>,
191    #[serde(default)]
192    pub sides: Option<Vec<String>>,
193}
194
195// ── Internal result types (not from JSON) ────────────────────────────────────
196
197/// Result of a successful installer JAR download.
198#[derive(Debug)]
199pub struct InstallerInfo {
200    pub file_path: String,
201    pub meta_data: String,
202    pub ext: String,
203    pub id: String,
204    /// NeoForge only: whether to use the legacy (1.20.1-era) API path.
205    pub old_api: bool,
206}