minecraft_java_rs_core/launcher/
game_data.rs1use std::path::Path;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 error::LaunchError,
7 models::{java::JavaFileItem, loader::LoaderType, minecraft::{AssetItem, MinecraftVersionJson}},
8};
9
10#[derive(Debug, Clone, Deserialize, Serialize)]
13#[serde(rename_all = "camelCase")]
14pub struct GameData {
15 pub minecraft_json: MinecraftVersionJson,
16 #[serde(default)]
19 pub minecraft_loader: Option<serde_json::Value>,
20 pub minecraft_version: String,
21 pub minecraft_java: JavaInfo,
22 #[serde(default)]
24 pub loader_libraries: Vec<AssetItem>,
25 #[serde(default)]
27 pub loader_main_class: Option<String>,
28 #[serde(default)]
30 pub loader_version_id: Option<String>,
31 #[serde(default)]
33 pub loader_type: Option<LoaderType>,
34 #[serde(default)]
37 pub loader_extra_game_args: Vec<String>,
38 #[serde(default)]
40 pub loader_extra_jvm_args: Vec<String>,
41}
42
43#[derive(Debug, Clone, Deserialize, Serialize)]
44pub struct JavaInfo {
45 pub files: Vec<JavaFileItem>,
46 pub path: String,
47}
48
49const GAME_DATA_FILE: &str = "gameData.json";
52
53pub async fn load_game_data(dir: &Path) -> Result<GameData, LaunchError> {
54 let path = dir.join(GAME_DATA_FILE);
55 let raw = tokio::fs::read_to_string(&path).await?;
56 let data = serde_json::from_str(&raw)?;
57 Ok(data)
58}
59
60pub async fn save_game_data(dir: &Path, data: &GameData) -> Result<(), LaunchError> {
61 tokio::fs::create_dir_all(dir).await?;
62 let json = serde_json::to_string_pretty(data)?;
63 tokio::fs::write(dir.join(GAME_DATA_FILE), json).await?;
64 Ok(())
65}
66
67#[cfg(test)]
70mod tests {
71 use super::*;
72 use tempfile::TempDir;
73
74 fn make_game_data() -> GameData {
75 use crate::models::minecraft::{
76 AssetIndexRef, DownloadArtifact, MinecraftVersionJson, VersionDownloads,
77 };
78 GameData {
79 minecraft_version: "1.20.4".into(),
80 minecraft_loader: None,
81 minecraft_java: JavaInfo { files: vec![], path: "/usr/bin/java".into() },
82 loader_libraries: vec![],
83 loader_main_class: None,
84 loader_version_id: None,
85 loader_type: None,
86 loader_extra_game_args: vec![],
87 loader_extra_jvm_args: vec![],
88 minecraft_json: MinecraftVersionJson {
89 id: "1.20.4".into(),
90 version_type: "release".into(),
91 assets: Some("16".into()),
92 asset_index: Some(AssetIndexRef {
93 id: "16".into(),
94 url: "https://example.com/16.json".into(),
95 sha1: "abc123".into(),
96 size: 0,
97 total_size: None,
98 }),
99 downloads: Some(VersionDownloads {
100 client: DownloadArtifact {
101 url: "https://example.com/client.jar".into(),
102 sha1: "def456".into(),
103 size: 0,
104 },
105 server: None,
106 client_mappings: None,
107 server_mappings: None,
108 }),
109 libraries: vec![],
110 arguments: None,
111 minecraft_arguments: None,
112 java_version: None,
113 main_class: Some("net.minecraft.client.main.Main".into()),
114 has_natives: false,
115 },
116 }
117 }
118
119 #[tokio::test]
120 async fn round_trip_game_data() {
121 let dir = TempDir::new().unwrap();
122 let original = make_game_data();
123 save_game_data(dir.path(), &original).await.unwrap();
124 let loaded = load_game_data(dir.path()).await.unwrap();
125 assert_eq!(loaded.minecraft_version, "1.20.4");
126 assert_eq!(loaded.minecraft_java.path, "/usr/bin/java");
127 assert!(loaded.minecraft_loader.is_none());
128 }
129
130 #[tokio::test]
131 async fn load_missing_file_returns_error() {
132 let dir = TempDir::new().unwrap();
133 let result = load_game_data(dir.path()).await;
134 assert!(result.is_err());
135 }
136
137 #[tokio::test]
138 async fn save_creates_missing_dir() {
139 let dir = TempDir::new().unwrap();
140 let nested = dir.path().join("a").join("b").join("c");
141 let data = make_game_data();
142 save_game_data(&nested, &data).await.unwrap();
143 assert!(nested.join("gameData.json").exists());
144 }
145}