From 6845a7d6feff54446b7a1c8fd7a07b22b8f624c9 Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sat, 8 Nov 2025 17:27:01 +0100 Subject: [PATCH] wip --- crates/lanspread-compat/src/eti.rs | 2 + crates/lanspread-db/src/db.rs | 29 ++++++++ crates/lanspread-server/src/main.rs | 13 ++++ .../src-tauri/src/lib.rs | 15 +++++ crates/lanspread-tauri-deno-ts/src/App.tsx | 67 +++++++++++++++++-- 5 files changed, 120 insertions(+), 6 deletions(-) diff --git a/crates/lanspread-compat/src/eti.rs b/crates/lanspread-compat/src/eti.rs index 65103ac..18d1f7a 100644 --- a/crates/lanspread-compat/src/eti.rs +++ b/crates/lanspread-compat/src/eti.rs @@ -62,6 +62,8 @@ impl From for Game { size: (eti_game.game_size * 1024.0 * 1024.0 * 1024.0) as u64, thumbnail: None, installed: false, + eti_game_version: None, + local_version: None, } } } diff --git a/crates/lanspread-db/src/db.rs b/crates/lanspread-db/src/db.rs index 0b2bcc3..2094e0f 100644 --- a/crates/lanspread-db/src/db.rs +++ b/crates/lanspread-db/src/db.rs @@ -6,6 +6,31 @@ use std::{collections::HashMap, fmt, path::Path}; use bytes::Bytes; use serde::{Deserialize, Serialize}; +/// Read version from version.ini file +/// # Errors +/// Returns error if file cannot be read or parsed +pub fn read_version_from_ini(game_dir: &Path) -> eyre::Result> { + let version_file = game_dir.join("version.ini"); + if !version_file.exists() { + return Ok(None); + } + + let content = std::fs::read_to_string(&version_file)?; + let version = content.trim().to_string(); + + // Validate format (YYYYMMDD) + if version.len() == 8 && version.chars().all(|c| c.is_ascii_digit()) { + Ok(Some(version)) + } else { + tracing::warn!( + "Invalid version format in {}: {}", + version_file.display(), + version + ); + Ok(None) + } +} + /// A game #[derive(Clone, Serialize, Deserialize)] pub struct Game { @@ -31,6 +56,10 @@ pub struct Game { pub thumbnail: Option, /// only relevant for client (yeah... I know) pub installed: bool, + /// ETI game version from version.ini (YYYYMMDD format) (server) + pub eti_game_version: Option, + /// Local game version from version.ini (YYYYMMDD format) + pub local_version: Option, } impl fmt::Debug for Game { diff --git a/crates/lanspread-server/src/main.rs b/crates/lanspread-server/src/main.rs index 152b9ba..16b78eb 100644 --- a/crates/lanspread-server/src/main.rs +++ b/crates/lanspread-server/src/main.rs @@ -65,6 +65,19 @@ async fn prepare_game_db(cli: &Cli) -> eyre::Result { // filter out games that the server does not have in game_dir games.retain(|game| cli.game_dir.join(&game.id).is_dir()); + // read version.ini files and update eti_game_version + for game in &mut games { + let game_dir = cli.game_dir.join(&game.id); + if let Ok(version) = lanspread_db::db::read_version_from_ini(&game_dir) { + game.eti_game_version = version; + if let Some(ref version) = game.eti_game_version { + tracing::debug!("Read version for game {}: {}", game.id, version); + } + } else { + tracing::warn!("Failed to read version.ini for game: {}", game.id); + } + } + let mut game_db = GameDB::from(games); game_db.add_thumbnails(&cli.thumbs_dir); diff --git a/crates/lanspread-tauri-deno-ts/src-tauri/src/lib.rs b/crates/lanspread-tauri-deno-ts/src-tauri/src/lib.rs index 42ed595..9b2891e 100644 --- a/crates/lanspread-tauri-deno-ts/src-tauri/src/lib.rs +++ b/crates/lanspread-tauri-deno-ts/src-tauri/src/lib.rs @@ -160,6 +160,21 @@ fn set_game_install_state_from_path(game_db: &mut GameDB, path: &Path, installed log::debug!("Set {game} to uninstalled"); } game.installed = installed; + + // Read local version.ini if installed + if installed { + if let Ok(version) = lanspread_db::db::read_version_from_ini(path) { + game.local_version = version; + if let Some(ref version) = game.local_version { + log::debug!("Read local version for game {}: {}", game.id, version); + } + } else { + log::warn!("Failed to read local version.ini for game: {}", game.id); + } + } else { + // Clear local version when uninstalled + game.local_version = None; + } } } diff --git a/crates/lanspread-tauri-deno-ts/src/App.tsx b/crates/lanspread-tauri-deno-ts/src/App.tsx index b12d83f..c2ad511 100644 --- a/crates/lanspread-tauri-deno-ts/src/App.tsx +++ b/crates/lanspread-tauri-deno-ts/src/App.tsx @@ -26,6 +26,8 @@ interface Game { thumbnail: Uint8Array; installed: boolean; install_status: InstallStatus; + eti_game_version?: string; + local_version?: string; } const App = () => { @@ -204,6 +206,47 @@ const App = () => { } }; + const updateGame = async (id: string) => { + console.log(`🎯 Updating game with id=${id}`); + try { + const success = await invoke('install_game', { id }); + if (success) { + console.log(`✅ Game update for id=${id} started...`); + // update install status in gameItems for this game + setGameItems(prev => prev.map(item => item.id === id + ? { ...item, install_status: InstallStatus.CheckingServer } + : item)); + } else { + // game is already being installed + console.warn(`🚧 Game with id=${id} is already being updated`); + } + } catch (error) { + console.error('❌ Error updating game:', error); + } + }; + + const needsUpdate = (game: Game): boolean => { + if (!game.installed) return false; + + // Check if server has a version and we have a local version + const serverVersion = game.eti_game_version; + const localVersion = game.local_version; + + // If we don't have local version but server has one, we need update + if (!localVersion && serverVersion) { + return true; + } + + // If we have both versions, compare them numerically + if (localVersion && serverVersion) { + const localNum = parseInt(localVersion, 10); + const serverNum = parseInt(serverVersion, 10); + return serverNum > localNum; + } + + return false; + }; + const dialogGameDir = async () => { const file = await open({ multiple: false, @@ -259,14 +302,26 @@ const App = () => { {(item.size / 1024 / 1024 / 1024).toFixed(1)} GB
item.installed - ? runGame(item.id) - : installGame(item.id)}> - {item.installed ? 'Play' - : item.install_status === InstallStatus.CheckingServer ? 'Checking server...' + onClick={() => { + if (!item.installed) { + installGame(item.id); + } else if (needsUpdate(item)) { + updateGame(item.id); + } else { + runGame(item.id); + } + }}> + {!item.installed + ? item.install_status === InstallStatus.CheckingServer ? 'Checking server...' : item.install_status === InstallStatus.Downloading ? 'Downloading...' : item.install_status === InstallStatus.Unpacking ? 'Unpacking...' - : 'Install'} + : 'Install' + : needsUpdate(item) + ? item.install_status === InstallStatus.CheckingServer ? 'Checking server...' + : item.install_status === InstallStatus.Downloading ? 'Downloading...' + : item.install_status === InstallStatus.Unpacking ? 'Unpacking...' + : 'Update' + : 'Play'}
);