the launcher can now update the game

This commit is contained in:
ALEZ-DEV 2024-05-07 20:13:28 +02:00
parent 3f0086287a
commit 5e59aef0f9
8 changed files with 95 additions and 4129 deletions

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,12 @@ async fn main() {
let mut proton: Option<Proton> = None; let mut proton: Option<Proton> = None;
loop { loop {
let state = GameState::get_current_state().await; let state_result = GameState::get_current_state().await;
if let Err(error) = state_result {
info!("Something goes wrong : {:?}", error);
break;
}
let state = state_result.unwrap();
if state != GameState::ProtonNotInstalled && proton == None { if state != GameState::ProtonNotInstalled && proton == None {
let proton_component = ProtonComponent::new(GameState::get_config_directory().await); let proton_component = ProtonComponent::new(GameState::get_config_directory().await);
@ -118,6 +123,13 @@ async fn main() {
.await .await
.expect("Failed to install the game"); .expect("Failed to install the game");
} }
GameState::GameNeedUpdate => {
info!("Game need an update, updating it");
info!("This will restart the installation process...");
GameManager::update_game()
.await
.expect("Failed to start the installation process");
}
GameState::GameNotPatched => { GameState::GameNotPatched => {
info!("Patching game..."); info!("Patching game...");
GameManager::patch_game(GameState::get_game_dir().await.unwrap()) GameManager::patch_game(GameState::get_game_dir().await.unwrap())
@ -125,11 +137,9 @@ async fn main() {
.expect("Failed to patch the game"); .expect("Failed to patch the game");
info!("Game patched!"); info!("Game patched!");
} }
_ => {} GameState::GameInstalled => {
} break;
}
if GameState::get_current_state().await == GameState::GameInstalled {
break;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -32,4 +32,3 @@ wincompatlib = { version = "0.7.4", features = [
"wine-fonts", "wine-fonts",
"winetricks", "winetricks",
] } ] }
xz = "0.1.0"

View File

@ -107,7 +107,7 @@ impl ComponentDownloader for GameComponent {
output_dir: &std::path::PathBuf, output_dir: &std::path::PathBuf,
progress: Option<std::sync::Arc<P>>, progress: Option<std::sync::Arc<P>>,
) -> anyhow::Result<std::path::PathBuf> { ) -> anyhow::Result<std::path::PathBuf> {
let game_info = kuro_prod_api::fetch_game_info().await?; let game_info = kuro_prod_api::GameInfo::get_info().await?;
let resources = game_info.fetch_resources().await?; let resources = game_info.fetch_resources().await?;
let mut downloader = Downloader::builder() let mut downloader = Downloader::builder()
.download_folder(output_dir) .download_folder(output_dir)

View File

@ -132,6 +132,17 @@ impl GameManager {
Ok(()) Ok(())
} }
// this function just pass is_game_installed and is_game_patched to false,
// so the launcher on the next iteration download the new file and delete the old one with the check process in the installation process
pub async fn update_game() -> anyhow::Result<()> {
let mut config = GameState::get_config().await;
config.is_game_installed = false;
config.is_game_patched = false;
GameState::save_config(config).await?;
Ok(())
}
pub async fn patch_game(game_dir: PathBuf) -> anyhow::Result<()> { pub async fn patch_game(game_dir: PathBuf) -> anyhow::Result<()> {
game_patcher::patch_game(game_dir).await?; game_patcher::patch_game(game_dir).await?;

View File

@ -6,6 +6,8 @@ use tokio::{
io::AsyncWriteExt, io::AsyncWriteExt,
}; };
use crate::utils::kuro_prod_api::GameInfo;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum GameState { pub enum GameState {
ProtonNotInstalled, ProtonNotInstalled,
@ -13,6 +15,7 @@ pub enum GameState {
FontNotInstalled, FontNotInstalled,
DependecieNotInstalled, DependecieNotInstalled,
GameNotInstalled, GameNotInstalled,
GameNeedUpdate,
GameNotPatched, GameNotPatched,
GameInstalled, GameInstalled,
} }
@ -100,33 +103,37 @@ impl GameState {
} }
} }
pub async fn get_current_state() -> Self { pub async fn get_current_state() -> anyhow::Result<Self> {
let config = GameState::get_config().await; let config = GameState::get_config().await;
if !config.is_wine_installed { if !config.is_wine_installed {
return GameState::ProtonNotInstalled; return Ok(GameState::ProtonNotInstalled);
} }
if !config.is_dxvk_installed { if !config.is_dxvk_installed {
return GameState::DXVKNotInstalled; return Ok(GameState::DXVKNotInstalled);
} }
if !config.is_font_installed { if !config.is_font_installed {
return GameState::FontNotInstalled; return Ok(GameState::FontNotInstalled);
} }
if !config.is_dependecies_installed { if !config.is_dependecies_installed {
return GameState::DependecieNotInstalled; return Ok(GameState::DependecieNotInstalled);
} }
if !config.is_game_installed { if !config.is_game_installed {
return GameState::GameNotInstalled; return Ok(GameState::GameNotInstalled);
}
if GameInfo::get_info().await?.need_update().await? {
return Ok(GameState::GameNeedUpdate);
} }
if !config.is_game_patched { if !config.is_game_patched {
return GameState::GameNotPatched; return Ok(GameState::GameNotPatched);
} }
GameState::GameInstalled Ok(GameState::GameInstalled)
} }
} }

View File

@ -1,5 +1,11 @@
use std::path::PathBuf;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use tokio::fs::read_to_string;
use tokio::io::AsyncWriteExt;
use crate::game_state::GameState;
// start data --------------------------------------------------------------------- // start data ---------------------------------------------------------------------
@ -101,13 +107,25 @@ static URL: &str = concat!(
"e.com/pcstarter/prod/game/G143/4/index.json" "e.com/pcstarter/prod/game/G143/4/index.json"
); );
pub async fn fetch_game_info() -> anyhow::Result<GameInfo> {
let response = reqwest::get(URL).await?;
let body = response.text().await?;
Ok(serde_json::from_str(&body)?)
}
impl GameInfo { impl GameInfo {
pub async fn get_info() -> anyhow::Result<GameInfo> {
let info = match GameInfo::try_load_from_cache().await {
Ok(i) => i,
Err(_) => {
let i = GameInfo::fetch_game_info().await?;
i.save_in_cache().await?;
i
}
};
Ok(info)
}
pub async fn need_update(&self) -> anyhow::Result<bool> {
let info = GameInfo::fetch_game_info().await?;
Ok(self.default.version != info.default.version)
}
pub fn get_first_cdn(&self) -> String { pub fn get_first_cdn(&self) -> String {
self.default.cdn_list.first().unwrap().url.clone() self.default.cdn_list.first().unwrap().url.clone()
} }
@ -125,6 +143,34 @@ impl GameInfo {
let body = response.text().await?; let body = response.text().await?;
Ok(serde_json::from_str::<Resources>(&body)?) Ok(serde_json::from_str::<Resources>(&body)?)
} }
async fn fetch_game_info() -> anyhow::Result<GameInfo> {
let response = reqwest::get(URL).await?;
let body = response.text().await?;
Ok(serde_json::from_str(&body)?)
}
async fn get_cache_file_path() -> PathBuf {
GameState::get_config_directory()
.await
.join("version-cache")
}
async fn save_in_cache(&self) -> anyhow::Result<()> {
let _ = tokio::fs::create_dir(GameState::get_config_directory().await).await;
let mut file = tokio::fs::File::create(GameInfo::get_cache_file_path().await).await?;
let content = serde_json::to_string(self)?;
file.write_all(content.as_bytes()).await?;
Ok(())
}
async fn try_load_from_cache() -> anyhow::Result<Self> {
let content = read_to_string(GameInfo::get_cache_file_path().await).await?;
Ok(serde_json::from_str::<GameInfo>(&content)?)
}
} }
impl Resources { impl Resources {