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