wip
This commit is contained in:
@@ -62,6 +62,8 @@ impl From<EtiGame> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Option<String>> {
|
||||
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<Bytes>,
|
||||
/// only relevant for client (yeah... I know)
|
||||
pub installed: bool,
|
||||
/// ETI game version from version.ini (YYYYMMDD format) (server)
|
||||
pub eti_game_version: Option<String>,
|
||||
/// Local game version from version.ini (YYYYMMDD format)
|
||||
pub local_version: Option<String>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Game {
|
||||
|
||||
@@ -65,6 +65,19 @@ async fn prepare_game_db(cli: &Cli) -> eyre::Result<GameDB> {
|
||||
// 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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = () => {
|
||||
<span className="size-text">{(item.size / 1024 / 1024 / 1024).toFixed(1)} GB</span>
|
||||
</div>
|
||||
<div className="play-button"
|
||||
onClick={() => 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'}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user