aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src-tauri/src/core/manifest.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src-tauri/src/core/manifest.rs')
-rw-r--r--src-tauri/src/core/manifest.rs154
1 files changed, 153 insertions, 1 deletions
diff --git a/src-tauri/src/core/manifest.rs b/src-tauri/src/core/manifest.rs
index 11ebc5a..2fea811 100644
--- a/src-tauri/src/core/manifest.rs
+++ b/src-tauri/src/core/manifest.rs
@@ -1,5 +1,8 @@
use serde::{Deserialize, Serialize};
use std::error::Error;
+use std::path::PathBuf;
+
+use crate::core::game_version::GameVersion;
#[derive(Debug, Deserialize, Serialize)]
pub struct VersionManifest {
@@ -24,8 +27,157 @@ pub struct Version {
pub release_time: String,
}
-pub async fn fetch_version_manifest() -> Result<VersionManifest, Box<dyn Error>> {
+pub async fn fetch_version_manifest() -> Result<VersionManifest, Box<dyn Error + Send + Sync>> {
let url = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json";
let resp = reqwest::get(url).await?.json::<VersionManifest>().await?;
Ok(resp)
}
+
+/// Load a version JSON from the local versions directory.
+///
+/// This is used for loading both vanilla and modded versions that have been
+/// previously downloaded or installed.
+///
+/// # Arguments
+/// * `game_dir` - The .minecraft directory path
+/// * `version_id` - The version ID to load
+///
+/// # Returns
+/// The parsed `GameVersion` if found, or an error if not found.
+pub async fn load_local_version(
+ game_dir: &PathBuf,
+ version_id: &str,
+) -> Result<GameVersion, Box<dyn Error + Send + Sync>> {
+ let json_path = game_dir
+ .join("versions")
+ .join(version_id)
+ .join(format!("{}.json", version_id));
+
+ if !json_path.exists() {
+ return Err(format!("Version {} not found locally", version_id).into());
+ }
+
+ let content = tokio::fs::read_to_string(&json_path).await?;
+ let version: GameVersion = serde_json::from_str(&content)?;
+ Ok(version)
+}
+
+/// Fetch a version JSON from Mojang's servers.
+///
+/// # Arguments
+/// * `version_id` - The version ID to fetch
+///
+/// # Returns
+/// The parsed `GameVersion` from Mojang's API.
+pub async fn fetch_vanilla_version(
+ version_id: &str,
+) -> Result<GameVersion, Box<dyn Error + Send + Sync>> {
+ // First, get the manifest to find the version URL
+ let manifest = fetch_version_manifest().await?;
+
+ let version_entry = manifest
+ .versions
+ .iter()
+ .find(|v| v.id == version_id)
+ .ok_or_else(|| format!("Version {} not found in manifest", version_id))?;
+
+ // Fetch the actual version JSON
+ let resp = reqwest::get(&version_entry.url)
+ .await?
+ .json::<GameVersion>()
+ .await?;
+
+ Ok(resp)
+}
+
+/// Load a version, checking local first, then fetching from remote if needed.
+///
+/// For modded versions (those with `inheritsFrom`), this will also resolve
+/// the inheritance chain.
+///
+/// # Arguments
+/// * `game_dir` - The .minecraft directory path
+/// * `version_id` - The version ID to load
+///
+/// # Returns
+/// A fully resolved `GameVersion` ready for launching.
+pub async fn load_version(
+ game_dir: &PathBuf,
+ version_id: &str,
+) -> Result<GameVersion, Box<dyn Error + Send + Sync>> {
+ // Try loading from local first
+ let mut version = match load_local_version(game_dir, version_id).await {
+ Ok(v) => v,
+ Err(_) => {
+ // Not found locally, try fetching from Mojang
+ fetch_vanilla_version(version_id).await?
+ }
+ };
+
+ // If this version inherits from another, resolve the inheritance iteratively
+ while let Some(parent_id) = version.inherits_from.clone() {
+ // Load the parent version
+ let parent = match load_local_version(game_dir, &parent_id).await {
+ Ok(v) => v,
+ Err(_) => fetch_vanilla_version(&parent_id).await?,
+ };
+
+ // Merge child into parent
+ version = crate::core::version_merge::merge_versions(version, parent);
+ }
+
+ Ok(version)
+}
+
+/// Save a version JSON to the local versions directory.
+///
+/// # Arguments
+/// * `game_dir` - The .minecraft directory path
+/// * `version` - The version to save
+///
+/// # Returns
+/// The path where the JSON was saved.
+pub async fn save_local_version(
+ game_dir: &PathBuf,
+ version: &GameVersion,
+) -> Result<PathBuf, Box<dyn Error + Send + Sync>> {
+ let version_dir = game_dir.join("versions").join(&version.id);
+ tokio::fs::create_dir_all(&version_dir).await?;
+
+ let json_path = version_dir.join(format!("{}.json", version.id));
+ let content = serde_json::to_string_pretty(version)?;
+ tokio::fs::write(&json_path, content).await?;
+
+ Ok(json_path)
+}
+
+/// List all locally installed versions.
+///
+/// # Arguments
+/// * `game_dir` - The .minecraft directory path
+///
+/// # Returns
+/// A list of version IDs found in the versions directory.
+pub async fn list_local_versions(
+ game_dir: &PathBuf,
+) -> Result<Vec<String>, Box<dyn Error + Send + Sync>> {
+ let versions_dir = game_dir.join("versions");
+ let mut versions = Vec::new();
+
+ if !versions_dir.exists() {
+ return Ok(versions);
+ }
+
+ let mut entries = tokio::fs::read_dir(&versions_dir).await?;
+ while let Some(entry) = entries.next_entry().await? {
+ if entry.file_type().await?.is_dir() {
+ let name = entry.file_name().to_string_lossy().to_string();
+ let json_path = entry.path().join(format!("{}.json", name));
+ if json_path.exists() {
+ versions.push(name);
+ }
+ }
+ }
+
+ Ok(versions)
+}