Working Instance Sync

This commit is contained in:
Kr4ight
2026-04-06 21:13:02 +02:00
parent 950d7f0a1d
commit fba51d78b8
3 changed files with 90 additions and 6 deletions
+69 -4
View File
@@ -1,9 +1,9 @@
use std::collections::HashMap;
use std::{collections::HashMap, fs, path::PathBuf};
use lyceris::auth::microsoft::MinecraftAccount;
use tauri::State;
use crate::{features::Feature, GameVersion, SharedState};
use crate::{features::Feature, launcher::launcher_dir, GameVersion, SharedState};
pub struct InstanceSync {}
@@ -20,7 +20,7 @@ impl Feature for InstanceSync {
version: &GameVersion,
account: &MinecraftAccount,
) -> super::FeatureResult {
println!("Launching {} for {}", version.id, account.username);
sync_to_instance(version).map_err(|e| e.to_string())?;
Ok(())
}
@@ -31,12 +31,70 @@ impl Feature for InstanceSync {
version: &GameVersion,
account: &MinecraftAccount,
) -> super::FeatureResult {
println!("Game launched!");
sync_back_from_instance(version).map_err(|e| e.to_string())?;
Ok(())
}
}
fn sync_to_instance(version: &GameVersion) -> std::io::Result<()> {
let global_path = options_path_global();
let instance_path = options_path_instance(version);
if !global_path.exists() {
if let Ok(instance_content) = fs::read_to_string(instance_path) {
fs::write(global_path, instance_content)?;
}
return Ok(());
}
let global_content = fs::read_to_string(global_path)?;
// Ensure instance dir exists
if let Some(parent) = instance_path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(instance_path, global_content)?;
Ok(())
}
fn sync_back_from_instance(version: &GameVersion) -> std::io::Result<()> {
let global_path = options_path_global();
let instance_path = options_path_instance(version);
let global_content = fs::read_to_string(&global_path)?;
let instance_content = fs::read_to_string(&instance_path)?;
let mut global_map = parse_options(&global_content);
let instance_map = parse_options(&instance_content);
// Only apply changes (ignore deletions)
for (key, instance_value) in instance_map {
match global_map.get(&key) {
Some(global_value) if global_value == &instance_value => {}
_ => {
// changed or new → update global
global_map.insert(key, instance_value);
}
}
}
fs::write(global_path, serialize_options(&global_map))?;
Ok(())
}
fn options_path_global() -> PathBuf {
launcher_dir().join("options.txt")
}
fn options_path_instance(version: &GameVersion) -> PathBuf {
launcher_dir().join(&version.id).join("options.txt")
}
fn parse_options(content: &str) -> HashMap<String, String> {
let mut map = HashMap::new();
@@ -52,3 +110,10 @@ fn parse_options(content: &str) -> HashMap<String, String> {
map
}
fn serialize_options(map: &HashMap<String, String>) -> String {
map.iter()
.map(|(k, v)| format!("{k}:{v}"))
.collect::<Vec<_>>()
.join("\n")
}
+15
View File
@@ -1,4 +1,5 @@
use lyceris::auth::microsoft::MinecraftAccount;
use serde::{Deserialize, Serialize};
use tauri::State;
use tokio::sync::Mutex;
@@ -8,6 +9,20 @@ mod instance_sync;
pub type FeatureResult = Result<(), String>;
#[derive(Clone, Serialize, Deserialize)]
pub struct FeatureSettings {
// Instance Sync
sync_options: bool,
}
impl Default for FeatureSettings {
fn default() -> Self {
Self {
sync_options: false,
}
}
}
#[allow(unused_variables)]
pub trait Feature: Send + Sync {
fn launch(
+6 -2
View File
@@ -9,7 +9,7 @@ use std::{
sync::{Arc, Mutex},
};
use crate::launcher::launcher_dir;
use crate::{features::FeatureSettings, launcher::launcher_dir};
pub type SharedState = Arc<Mutex<AppState>>;
@@ -36,6 +36,7 @@ pub struct GameVersion {
#[derive(Clone, Serialize, Deserialize)]
pub struct LauncherSettings {
pub max_memory: u32,
pub features: FeatureSettings,
}
// --- App State ---
@@ -48,7 +49,10 @@ pub struct AppState {
impl Default for AppState {
fn default() -> Self {
Self {
settings: LauncherSettings { max_memory: 4096 },
settings: LauncherSettings {
max_memory: 4096,
features: FeatureSettings::default(),
},
version: String::from("1.21.6"),
}
}