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,
|
size: (eti_game.game_size * 1024.0 * 1024.0 * 1024.0) as u64,
|
||||||
thumbnail: None,
|
thumbnail: None,
|
||||||
installed: false,
|
installed: false,
|
||||||
|
eti_game_version: None,
|
||||||
|
local_version: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,31 @@ use std::{collections::HashMap, fmt, path::Path};
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use serde::{Deserialize, Serialize};
|
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
|
/// A game
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
@@ -31,6 +56,10 @@ pub struct Game {
|
|||||||
pub thumbnail: Option<Bytes>,
|
pub thumbnail: Option<Bytes>,
|
||||||
/// only relevant for client (yeah... I know)
|
/// only relevant for client (yeah... I know)
|
||||||
pub installed: bool,
|
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 {
|
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
|
// filter out games that the server does not have in game_dir
|
||||||
games.retain(|game| cli.game_dir.join(&game.id).is_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);
|
let mut game_db = GameDB::from(games);
|
||||||
|
|
||||||
game_db.add_thumbnails(&cli.thumbs_dir);
|
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");
|
log::debug!("Set {game} to uninstalled");
|
||||||
}
|
}
|
||||||
game.installed = installed;
|
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;
|
thumbnail: Uint8Array;
|
||||||
installed: boolean;
|
installed: boolean;
|
||||||
install_status: InstallStatus;
|
install_status: InstallStatus;
|
||||||
|
eti_game_version?: string;
|
||||||
|
local_version?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const App = () => {
|
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 dialogGameDir = async () => {
|
||||||
const file = await open({
|
const file = await open({
|
||||||
multiple: false,
|
multiple: false,
|
||||||
@@ -259,14 +302,26 @@ const App = () => {
|
|||||||
<span className="size-text">{(item.size / 1024 / 1024 / 1024).toFixed(1)} GB</span>
|
<span className="size-text">{(item.size / 1024 / 1024 / 1024).toFixed(1)} GB</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="play-button"
|
<div className="play-button"
|
||||||
onClick={() => item.installed
|
onClick={() => {
|
||||||
? runGame(item.id)
|
if (!item.installed) {
|
||||||
: installGame(item.id)}>
|
installGame(item.id);
|
||||||
{item.installed ? 'Play'
|
} else if (needsUpdate(item)) {
|
||||||
: item.install_status === InstallStatus.CheckingServer ? 'Checking server...'
|
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.Downloading ? 'Downloading...'
|
||||||
: item.install_status === InstallStatus.Unpacking ? 'Unpacking...'
|
: 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>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user