mirror of
https://github.com/ALEZ-DEV/Babylonia-terminal.git
synced 2025-12-15 00:48:52 +00:00
initial commit
This commit is contained in:
commit
f7b2755343
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
set_github_env.sh
|
||||
1
babylonia-terminal-cli/.gitignore
vendored
Normal file
1
babylonia-terminal-cli/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
||||
1960
babylonia-terminal-cli/Cargo.lock
generated
Normal file
1960
babylonia-terminal-cli/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
15
babylonia-terminal-cli/Cargo.toml
Normal file
15
babylonia-terminal-cli/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "babylonia-terminal-cli"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
babylonia-terminal-sdk = { path = "./../babylonia-terminal-sdk" }
|
||||
downloader = { git = "https://github.com/ALEZ-DEV/downloader" } # version = "0.2.7",
|
||||
indicatif = "0.17.8"
|
||||
log = "0.4.21"
|
||||
simple_logger = "4.3.3"
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
wincompatlib = "0.7.4"
|
||||
BIN
babylonia-terminal-cli/TDData-data.db
Normal file
BIN
babylonia-terminal-cli/TDData-data.db
Normal file
Binary file not shown.
76
babylonia-terminal-cli/src/main.rs
Normal file
76
babylonia-terminal-cli/src/main.rs
Normal file
@ -0,0 +1,76 @@
|
||||
use babylonia_terminal_sdk::{game_manager::GameManager, game_state::GameState};
|
||||
use log::{info, LevelFilter};
|
||||
use simple_logger::SimpleLogger;
|
||||
use wincompatlib::prelude::*;
|
||||
|
||||
pub mod reporter;
|
||||
|
||||
use crate::reporter::DownloadReporter;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
SimpleLogger::new()
|
||||
.with_module_level("hyper", LevelFilter::Off)
|
||||
.with_module_level("hyper_util", LevelFilter::Off)
|
||||
.with_module_level("tracing", LevelFilter::Off)
|
||||
.with_module_level("rustls", LevelFilter::Off)
|
||||
.with_module_level("minreq", LevelFilter::Off)
|
||||
.init()
|
||||
.unwrap();
|
||||
|
||||
let mut wine: Option<Wine> = None;
|
||||
|
||||
loop {
|
||||
let state = GameState::get_current_state().await;
|
||||
|
||||
if state != GameState::WineNotInstalled && wine.is_none() {
|
||||
wine = Some(GameManager::init_wine());
|
||||
}
|
||||
|
||||
match state {
|
||||
GameState::WineNotInstalled => {
|
||||
info!("Wine not installed, installing it...");
|
||||
GameManager::install_wine(
|
||||
GameState::get_config_directory(),
|
||||
Some(DownloadReporter::create()),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to install Wine");
|
||||
info!("Wine installed");
|
||||
}
|
||||
GameState::DXVKNotInstalled => {
|
||||
info!("DXVK not installed, installing it...");
|
||||
GameManager::install_dxvk(
|
||||
&wine.clone().unwrap(),
|
||||
GameState::get_config_directory(),
|
||||
Some(DownloadReporter::create()),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to installed DXVK");
|
||||
info!("DXVK installed");
|
||||
}
|
||||
GameState::FontNotInstalled => {
|
||||
info!("Fonts not installed, installing it...");
|
||||
GameManager::install_font(&wine.clone().unwrap(), DownloadReporter::create())
|
||||
.await
|
||||
.expect("Failed to install fonts");
|
||||
info!("Fonts installed");
|
||||
}
|
||||
GameState::DependecieNotInstalled => {
|
||||
info!("Dependecies not installed, installing it...");
|
||||
GameManager::install_dependecies(&wine.clone().unwrap())
|
||||
.await
|
||||
.expect("Failed to install dependecies");
|
||||
info!("Dependecies installed");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if GameState::get_current_state().await == GameState::GameInstalled {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
info!("Starting game...");
|
||||
GameManager::start_game(&wine.unwrap()).await;
|
||||
}
|
||||
63
babylonia-terminal-cli/src/reporter.rs
Normal file
63
babylonia-terminal-cli/src/reporter.rs
Normal file
@ -0,0 +1,63 @@
|
||||
use indicatif::{ProgressBar, ProgressState, ProgressStyle};
|
||||
use std::fmt::Write;
|
||||
|
||||
struct DownloadReporterPrivate {
|
||||
last_update: std::time::Instant,
|
||||
max_progress: Option<u64>,
|
||||
message: String,
|
||||
pb: ProgressBar,
|
||||
}
|
||||
|
||||
pub struct DownloadReporter {
|
||||
private: std::sync::Mutex<Option<DownloadReporterPrivate>>,
|
||||
}
|
||||
|
||||
impl DownloadReporter {
|
||||
pub fn create() -> std::sync::Arc<Self> {
|
||||
std::sync::Arc::new(Self {
|
||||
private: std::sync::Mutex::new(None),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl downloader::progress::Reporter for DownloadReporter {
|
||||
fn setup(&self, max_progress: Option<u64>, message: &str) {
|
||||
let pb = ProgressBar::new(max_progress.unwrap());
|
||||
pb.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.white}] {bytes}/{total_bytes} ({eta})")
|
||||
.unwrap()
|
||||
.with_key("eta", |state: &ProgressState, w: &mut dyn Write| write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap())
|
||||
.progress_chars("=>-"));
|
||||
|
||||
let private = DownloadReporterPrivate {
|
||||
last_update: std::time::Instant::now(),
|
||||
max_progress,
|
||||
message: message.to_owned(),
|
||||
pb: pb,
|
||||
};
|
||||
|
||||
println!("{}", private.message);
|
||||
let mut guard = self.private.lock().unwrap();
|
||||
*guard = Some(private);
|
||||
}
|
||||
|
||||
fn progress(&self, current: u64) {
|
||||
if let Some(p) = self.private.lock().unwrap().as_mut() {
|
||||
if p.last_update.elapsed().as_millis() >= 1000 {
|
||||
p.pb.set_position(current);
|
||||
p.last_update = std::time::Instant::now();
|
||||
} else if current == p.max_progress.unwrap() {
|
||||
p.pb.set_position(current);
|
||||
p.last_update = std::time::Instant::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_message(&self, message: &str) {
|
||||
println!("File state: {}", message);
|
||||
}
|
||||
|
||||
fn done(&self) {
|
||||
let mut guard = self.private.lock().unwrap();
|
||||
*guard = None;
|
||||
}
|
||||
}
|
||||
1
babylonia-terminal-sdk/.gitignore
vendored
Normal file
1
babylonia-terminal-sdk/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
||||
1741
babylonia-terminal-sdk/Cargo.lock
generated
Normal file
1741
babylonia-terminal-sdk/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
babylonia-terminal-sdk/Cargo.toml
Normal file
27
babylonia-terminal-sdk/Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "babylonia-terminal-sdk"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.81"
|
||||
dirs = "5.0.1"
|
||||
dotenv = "0.15.0"
|
||||
downloader = { git = "https://github.com/ALEZ-DEV/downloader" } # version = "0.2.7",
|
||||
flate2 = "1.0.28"
|
||||
log = "0.4.21"
|
||||
reqwest = "0.12.2"
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
serde_json = "1.0.115"
|
||||
tar = "0.4.40"
|
||||
tokio = { version = "1.37.0", features = ["fs"] }
|
||||
wincompatlib = { version = "0.7.4", features = [
|
||||
"dxvk",
|
||||
"wine-bundles",
|
||||
"wine-proton",
|
||||
"wine-fonts",
|
||||
"winetricks",
|
||||
] }
|
||||
xz = "0.1.0"
|
||||
@ -0,0 +1,15 @@
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use downloader::progress::Reporter;
|
||||
|
||||
pub trait ComponentDownloader {
|
||||
async fn install<P: Reporter + 'static>(&self, progress: Option<Arc<P>>) -> anyhow::Result<()>;
|
||||
|
||||
//the 'static is something to change, I don't very like it, but it's for testing purpose
|
||||
async fn download<P: Reporter + 'static>(
|
||||
output_dir: &PathBuf,
|
||||
progress: Option<Arc<P>>,
|
||||
) -> anyhow::Result<PathBuf>;
|
||||
|
||||
async fn uncompress(file: PathBuf, new_filename: PathBuf) -> anyhow::Result<()>;
|
||||
}
|
||||
2
babylonia-terminal-sdk/src/components/mod.rs
Normal file
2
babylonia-terminal-sdk/src/components/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub(crate) mod component_downloader;
|
||||
pub(crate) mod wine_component;
|
||||
107
babylonia-terminal-sdk/src/components/wine_component.rs
Normal file
107
babylonia-terminal-sdk/src/components/wine_component.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use std::{
|
||||
fs::{create_dir, remove_file, rename, File},
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use downloader::{progress::Reporter, Downloader};
|
||||
use tar::Archive;
|
||||
use wincompatlib::wine::ext::WineBootExt;
|
||||
use xz::read::XzDecoder;
|
||||
|
||||
use super::component_downloader::ComponentDownloader;
|
||||
use crate::{game_state::GameState, utils::github_requester::GithubRequester};
|
||||
|
||||
pub struct WineComponent {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl GithubRequester for WineComponent {}
|
||||
|
||||
impl ComponentDownloader for WineComponent {
|
||||
async fn install<P: Reporter + 'static>(&self, progress: Option<Arc<P>>) -> anyhow::Result<()> {
|
||||
let file_output = Self::download(
|
||||
&self
|
||||
.path
|
||||
.parent()
|
||||
.expect("Failed to get the parent directory of Wine")
|
||||
.to_path_buf(),
|
||||
progress,
|
||||
)
|
||||
.await?;
|
||||
Self::uncompress(file_output.clone(), self.path.clone()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn download<P: Reporter + 'static>(
|
||||
output_dir: &PathBuf,
|
||||
progress: Option<Arc<P>>,
|
||||
) -> anyhow::Result<PathBuf> {
|
||||
let release = Self::get_latest_github_release("GloriousEggroll", "wine-ge-custom").await?;
|
||||
|
||||
let asset = release[0]
|
||||
.assets
|
||||
.get(1)
|
||||
.expect("Asset not found in the github release");
|
||||
|
||||
let mut downloader = Downloader::builder()
|
||||
.download_folder(output_dir)
|
||||
.parallel_requests(1)
|
||||
.build()?;
|
||||
|
||||
let mut dl = downloader::Download::new(&asset.browser_download_url);
|
||||
if let Some(p) = progress {
|
||||
dl = dl.progress(p);
|
||||
}
|
||||
|
||||
let _result = downloader.async_download(&[dl]).await?;
|
||||
let file_location = output_dir.join(asset.name.clone());
|
||||
|
||||
Ok(file_location)
|
||||
}
|
||||
|
||||
async fn uncompress(file: PathBuf, new_directory_name: PathBuf) -> anyhow::Result<()> {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let tar_xz = File::open(file.clone()).unwrap();
|
||||
let tar = XzDecoder::new(tar_xz);
|
||||
let mut archive = Archive::new(tar);
|
||||
archive
|
||||
.unpack(new_directory_name.parent().unwrap())
|
||||
.unwrap();
|
||||
remove_file(file.clone()).unwrap();
|
||||
rename(
|
||||
file.to_str()
|
||||
.unwrap()
|
||||
.replace("wine-", "")
|
||||
.strip_suffix(".tar.xz")
|
||||
.unwrap(),
|
||||
new_directory_name,
|
||||
)
|
||||
.unwrap();
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl WineComponent {
|
||||
pub fn new(path: PathBuf) -> Self {
|
||||
WineComponent { path }
|
||||
}
|
||||
|
||||
pub fn init_wine(&self) -> wincompatlib::prelude::Wine {
|
||||
let wine_path = self.path.parent().unwrap().join("bin/wine");
|
||||
let wine_prefix = self.path.parent().unwrap().join("data");
|
||||
if !wine_prefix.exists() {
|
||||
create_dir(wine_prefix.clone()).unwrap()
|
||||
}
|
||||
|
||||
let wine = wincompatlib::prelude::Wine::from_binary(wine_path);
|
||||
wine.update_prefix(Some(wine_prefix)).unwrap();
|
||||
|
||||
wine
|
||||
}
|
||||
}
|
||||
142
babylonia-terminal-sdk/src/components_downloader.rs
Normal file
142
babylonia-terminal-sdk/src/components_downloader.rs
Normal file
@ -0,0 +1,142 @@
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use downloader::progress::Reporter;
|
||||
use downloader::Downloader as FileDownloader;
|
||||
use reqwest::header::{self, USER_AGENT};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tar::Header;
|
||||
//use tokio::{fs::File, io};
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GithubRelease {
|
||||
pub url: String,
|
||||
#[serde(rename = "assets_url")]
|
||||
pub assets_url: String,
|
||||
#[serde(rename = "tag_name")]
|
||||
pub tag_name: String,
|
||||
#[serde(rename = "target_commitish")]
|
||||
pub target_commitish: String,
|
||||
pub name: String,
|
||||
pub assets: Vec<Asset>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Asset {
|
||||
pub url: String,
|
||||
pub id: i64,
|
||||
#[serde(rename = "node_id")]
|
||||
pub node_id: String,
|
||||
pub name: String,
|
||||
#[serde(rename = "content_type")]
|
||||
pub content_type: String,
|
||||
pub state: String,
|
||||
pub size: i64,
|
||||
#[serde(rename = "download_count")]
|
||||
pub download_count: i64,
|
||||
#[serde(rename = "created_at")]
|
||||
pub created_at: String,
|
||||
#[serde(rename = "updated_at")]
|
||||
pub updated_at: String,
|
||||
#[serde(rename = "browser_download_url")]
|
||||
pub browser_download_url: String,
|
||||
}
|
||||
|
||||
pub struct ComponentsDownloader;
|
||||
|
||||
static GITHUB_TOKEN: &'static str = "Bearer <GITHUB_TOKEN>"; //this token can only read public repo
|
||||
|
||||
impl ComponentsDownloader {
|
||||
fn get_client() -> reqwest::Client {
|
||||
let mut headers = header::HeaderMap::new();
|
||||
headers.insert(
|
||||
"Authorization",
|
||||
header::HeaderValue::from_static(GITHUB_TOKEN),
|
||||
);
|
||||
|
||||
reqwest::Client::builder()
|
||||
.user_agent(USER_AGENT)
|
||||
.default_headers(headers)
|
||||
.build()
|
||||
.expect("Failed to build https client")
|
||||
}
|
||||
|
||||
async fn get_latest_github_release(
|
||||
user: &str,
|
||||
repo_name: &str,
|
||||
) -> anyhow::Result<Vec<GithubRelease>> {
|
||||
let response = ComponentsDownloader::get_client()
|
||||
.get(format!(
|
||||
"https://api.github.com/repos/{}/{}/releases",
|
||||
user, repo_name
|
||||
))
|
||||
.send()
|
||||
.await?;
|
||||
let body = response.text().await?;
|
||||
|
||||
let releases: Vec<GithubRelease> = serde_json::from_str(&body)?;
|
||||
Ok(releases)
|
||||
}
|
||||
|
||||
pub async fn download_latest_wine<P>(
|
||||
output_dir: &PathBuf,
|
||||
progress: Option<Arc<P>>,
|
||||
) -> anyhow::Result<PathBuf>
|
||||
where
|
||||
P: Reporter + 'static, //the 'static is something to change, I just made it like this for test prupose
|
||||
{
|
||||
let releases =
|
||||
//ComponentsDownloader::get_latest_github_release("Kron4ek", "Wine-Builds").await?;
|
||||
ComponentsDownloader::get_latest_github_release("GloriousEggroll", "wine-ge-custom").await?;
|
||||
|
||||
let asset = releases[0]
|
||||
.assets
|
||||
.get(1)
|
||||
.expect("Asset not found in the github release");
|
||||
|
||||
let mut downloader = FileDownloader::builder()
|
||||
.download_folder(output_dir)
|
||||
.parallel_requests(1)
|
||||
.build()?;
|
||||
|
||||
let mut dl = downloader::Download::new(&asset.browser_download_url);
|
||||
if let Some(p) = progress {
|
||||
dl = dl.progress(p);
|
||||
}
|
||||
|
||||
let _result = downloader.async_download(&[dl]).await?;
|
||||
let file_location = output_dir.join(asset.name.clone());
|
||||
|
||||
Ok(file_location)
|
||||
}
|
||||
|
||||
pub async fn download_latest_dxvk<P>(
|
||||
output_dir: &PathBuf,
|
||||
progress: Option<Arc<P>>,
|
||||
) -> anyhow::Result<PathBuf>
|
||||
where
|
||||
P: Reporter + 'static,
|
||||
{
|
||||
let releases = ComponentsDownloader::get_latest_github_release("doitsujin", "dxvk").await?;
|
||||
|
||||
let asset = releases[0]
|
||||
.assets
|
||||
.first()
|
||||
.expect("Asset not found in the github release");
|
||||
|
||||
let mut downloader = FileDownloader::builder()
|
||||
.download_folder(output_dir)
|
||||
.parallel_requests(1)
|
||||
.build()?;
|
||||
let mut dl = downloader::Download::new(&asset.browser_download_url);
|
||||
if let Some(p) = progress {
|
||||
dl = dl.progress(p);
|
||||
}
|
||||
|
||||
let _result = downloader.async_download(&[dl]).await?;
|
||||
let file_location = output_dir.join(asset.name.clone());
|
||||
|
||||
Ok(file_location)
|
||||
}
|
||||
}
|
||||
168
babylonia-terminal-sdk/src/game_manager.rs
Normal file
168
babylonia-terminal-sdk/src/game_manager.rs
Normal file
@ -0,0 +1,168 @@
|
||||
use std::{
|
||||
fs::{create_dir, remove_file, rename, File},
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use downloader::progress::Reporter;
|
||||
use flate2::read::GzDecoder;
|
||||
use log::info;
|
||||
use tar::Archive;
|
||||
use tokio::{join, time::sleep};
|
||||
use wincompatlib::{prelude::*, wine::bundle::proton};
|
||||
use xz::read::XzDecoder;
|
||||
|
||||
use crate::{
|
||||
components::{component_downloader::ComponentDownloader, wine_component::WineComponent},
|
||||
components_downloader::ComponentsDownloader,
|
||||
game_state::GameState,
|
||||
};
|
||||
|
||||
pub struct GameManager;
|
||||
|
||||
impl GameManager {
|
||||
pub async fn install_wine<P>(
|
||||
config_dir: PathBuf,
|
||||
progress: Option<Arc<P>>,
|
||||
) -> anyhow::Result<WineComponent>
|
||||
where
|
||||
P: Reporter + 'static,
|
||||
{
|
||||
let wine_component = WineComponent::new(config_dir.join("wine"));
|
||||
|
||||
wine_component.install(progress).await?;
|
||||
|
||||
let mut config = GameState::get_config().await?;
|
||||
config.is_wine_installed = true;
|
||||
config.wine_path = Some(
|
||||
GameState::get_config_directory()
|
||||
.join("wine")
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
);
|
||||
GameState::save_config(config).await?;
|
||||
|
||||
Ok(wine_component)
|
||||
}
|
||||
|
||||
pub async fn install_dxvk<P>(
|
||||
wine: &Wine,
|
||||
config_dir: PathBuf,
|
||||
progress: Option<Arc<P>>,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
P: Reporter + 'static,
|
||||
{
|
||||
let file_output = ComponentsDownloader::download_latest_dxvk(&config_dir, progress)
|
||||
.await
|
||||
.expect("failed to download dxvk");
|
||||
|
||||
let file_to_uncompress = file_output.clone();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let tar_gz = File::open(file_to_uncompress.clone()).unwrap();
|
||||
let tar = GzDecoder::new(tar_gz);
|
||||
let mut archive = Archive::new(tar);
|
||||
archive.unpack(config_dir).unwrap();
|
||||
remove_file(file_to_uncompress.clone()).unwrap();
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
wine.install_dxvk(
|
||||
file_output
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.strip_suffix(".tar.gz")
|
||||
.unwrap(),
|
||||
InstallParams::default(),
|
||||
)
|
||||
.expect("failed to installed DXVK");
|
||||
|
||||
let mut config = GameState::get_config().await?;
|
||||
config.is_dxvk_installed = true;
|
||||
GameState::save_config(config).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn install_font<P>(wine: &Wine, progress: Arc<P>) -> anyhow::Result<()>
|
||||
where
|
||||
P: Reporter + 'static,
|
||||
{
|
||||
progress.setup(Some(10), "");
|
||||
progress.progress(0);
|
||||
|
||||
wine.install_font(Font::Arial)?;
|
||||
progress.progress(1);
|
||||
|
||||
wine.install_font(Font::Andale)?;
|
||||
progress.progress(2);
|
||||
|
||||
wine.install_font(Font::Courier)?;
|
||||
progress.progress(3);
|
||||
|
||||
wine.install_font(Font::ComicSans)?;
|
||||
progress.progress(4);
|
||||
|
||||
wine.install_font(Font::Georgia)?;
|
||||
progress.progress(5);
|
||||
|
||||
wine.install_font(Font::Impact)?;
|
||||
progress.progress(6);
|
||||
|
||||
wine.install_font(Font::Times)?;
|
||||
progress.progress(7);
|
||||
|
||||
wine.install_font(Font::Trebuchet)?;
|
||||
progress.progress(8);
|
||||
|
||||
wine.install_font(Font::Verdana)?;
|
||||
progress.progress(9);
|
||||
|
||||
wine.install_font(Font::Webdings)?;
|
||||
progress.progress(10);
|
||||
|
||||
let mut config = GameState::get_config().await?;
|
||||
config.is_font_installed = true;
|
||||
GameState::save_config(config).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn install_dependecies(wine: &Wine) -> anyhow::Result<()> {
|
||||
let winetricks = Winetricks::from_wine("winetricks", wine);
|
||||
winetricks.install("corefonts")?;
|
||||
winetricks.install("vcrun2022")?;
|
||||
|
||||
let mut config = GameState::get_config().await?;
|
||||
config.is_dependecies_installed = true;
|
||||
GameState::save_config(config).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn init_wine() -> Wine {
|
||||
let wine_path = GameState::get_config_directory().join("wine/bin/wine");
|
||||
let wine_prefix = GameState::get_config_directory().join("data");
|
||||
if !wine_prefix.exists() {
|
||||
create_dir(wine_prefix.clone()).unwrap()
|
||||
}
|
||||
|
||||
let wine = Wine::from_binary(wine_path);
|
||||
wine.update_prefix(Some(wine_prefix)).unwrap();
|
||||
|
||||
wine
|
||||
}
|
||||
|
||||
pub fn download_game() {}
|
||||
|
||||
pub async fn start_game(wine: &Wine) {
|
||||
wine.run("/home/alez/.steam/steam/steamapps/compatdata/3841903579/pfx/drive_c/Punishing Gray Raven/launcher.exe").unwrap();
|
||||
|
||||
loop {
|
||||
sleep(Duration::from_millis(10000)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
103
babylonia-terminal-sdk/src/game_state.rs
Normal file
103
babylonia-terminal-sdk/src/game_state.rs
Normal file
@ -0,0 +1,103 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
io::{Read, Write},
|
||||
path::PathBuf,
|
||||
};
|
||||
use tokio::{
|
||||
fs::{read_to_string, File},
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
};
|
||||
//use wincompatlib::prelude::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum GameState {
|
||||
WineNotInstalled,
|
||||
DXVKNotInstalled,
|
||||
FontNotInstalled,
|
||||
DependecieNotInstalled, // that's just the missing dll to install
|
||||
LauncherNotInstalled,
|
||||
GameNotInstalled,
|
||||
InstallingGame,
|
||||
GameInstalled,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GameConfig {
|
||||
pub dedicated_wine: bool,
|
||||
pub is_wine_installed: bool,
|
||||
pub wine_path: Option<String>,
|
||||
pub is_dxvk_installed: bool,
|
||||
pub is_font_installed: bool,
|
||||
pub is_dependecies_installed: bool,
|
||||
}
|
||||
|
||||
impl Default for GameConfig {
|
||||
fn default() -> Self {
|
||||
GameConfig {
|
||||
dedicated_wine: true,
|
||||
is_wine_installed: false,
|
||||
wine_path: None,
|
||||
is_dxvk_installed: false,
|
||||
is_font_installed: false,
|
||||
is_dependecies_installed: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GameState {
|
||||
pub fn get_config_directory() -> PathBuf {
|
||||
dirs::home_dir().unwrap().join(".babylonia-terminal")
|
||||
}
|
||||
|
||||
fn get_config_file_path() -> PathBuf {
|
||||
GameState::get_config_directory().join("babylonia-terminal-config")
|
||||
}
|
||||
|
||||
async fn try_get_config_file() -> anyhow::Result<File> {
|
||||
let _ = tokio::fs::create_dir(GameState::get_config_directory()).await;
|
||||
|
||||
Ok(tokio::fs::File::create(GameState::get_config_file_path()).await?)
|
||||
}
|
||||
|
||||
pub async fn save_config(config: GameConfig) -> anyhow::Result<()> {
|
||||
let mut file = GameState::try_get_config_file().await?;
|
||||
let content = serde_json::to_string(&config)?;
|
||||
file.write_all(content.as_bytes()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_config() -> anyhow::Result<GameConfig> {
|
||||
let content = match read_to_string(GameState::get_config_file_path()).await {
|
||||
Err(_) => return Ok(GameConfig::default()),
|
||||
Ok(c) => c,
|
||||
};
|
||||
if let Ok(config) = serde_json::from_str::<GameConfig>(&content) {
|
||||
Ok(config)
|
||||
} else {
|
||||
Ok(GameConfig::default())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_current_state() -> Self {
|
||||
let config = GameState::get_config().await.unwrap();
|
||||
|
||||
if !config.is_wine_installed {
|
||||
return GameState::WineNotInstalled;
|
||||
}
|
||||
|
||||
if !config.is_dxvk_installed {
|
||||
return GameState::DXVKNotInstalled;
|
||||
}
|
||||
|
||||
if !config.is_font_installed {
|
||||
return GameState::FontNotInstalled;
|
||||
}
|
||||
|
||||
if !config.is_dependecies_installed {
|
||||
return GameState::DependecieNotInstalled;
|
||||
}
|
||||
|
||||
GameState::GameInstalled
|
||||
}
|
||||
}
|
||||
5
babylonia-terminal-sdk/src/lib.rs
Normal file
5
babylonia-terminal-sdk/src/lib.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub mod components;
|
||||
pub mod components_downloader;
|
||||
pub mod game_manager;
|
||||
pub mod game_state;
|
||||
pub mod utils;
|
||||
84
babylonia-terminal-sdk/src/utils/github_requester.rs
Normal file
84
babylonia-terminal-sdk/src/utils/github_requester.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use std::borrow::{Borrow, BorrowMut};
|
||||
|
||||
use reqwest::header::{self, USER_AGENT};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GithubRelease {
|
||||
pub url: String,
|
||||
#[serde(rename = "assets_url")]
|
||||
pub assets_url: String,
|
||||
#[serde(rename = "tag_name")]
|
||||
pub tag_name: String,
|
||||
#[serde(rename = "target_commitish")]
|
||||
pub target_commitish: String,
|
||||
pub name: String,
|
||||
pub assets: Vec<Asset>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Asset {
|
||||
pub url: String,
|
||||
pub id: i64,
|
||||
#[serde(rename = "node_id")]
|
||||
pub node_id: String,
|
||||
pub name: String,
|
||||
#[serde(rename = "content_type")]
|
||||
pub content_type: String,
|
||||
pub state: String,
|
||||
pub size: i64,
|
||||
#[serde(rename = "download_count")]
|
||||
pub download_count: i64,
|
||||
#[serde(rename = "created_at")]
|
||||
pub created_at: String,
|
||||
#[serde(rename = "updated_at")]
|
||||
pub updated_at: String,
|
||||
#[serde(rename = "browser_download_url")]
|
||||
pub browser_download_url: String,
|
||||
}
|
||||
|
||||
pub struct ComponentsDownloader;
|
||||
|
||||
pub trait GithubRequester {
|
||||
fn get_client() -> reqwest::Client {
|
||||
let mut headers = None;
|
||||
|
||||
if let Ok(github_token) = std::env::var("BT_GITHUB_TOKEN") {
|
||||
headers = Some(header::HeaderMap::new());
|
||||
headers.as_mut().unwrap().insert(
|
||||
"Authorization",
|
||||
header::HeaderValue::from_str(&format!("Bearer {}", github_token)).unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
let mut client = reqwest::Client::builder();
|
||||
|
||||
if let Some(h) = headers {
|
||||
client = client.default_headers(h);
|
||||
}
|
||||
|
||||
client
|
||||
.user_agent(USER_AGENT)
|
||||
.build()
|
||||
.expect("Failed to build https client")
|
||||
}
|
||||
|
||||
async fn get_latest_github_release(
|
||||
user: &str,
|
||||
repo_name: &str,
|
||||
) -> anyhow::Result<Vec<GithubRelease>> {
|
||||
let response = Self::get_client()
|
||||
.get(format!(
|
||||
"https://api.github.com/repos/{}/{}/releases",
|
||||
user, repo_name
|
||||
))
|
||||
.send()
|
||||
.await?;
|
||||
let body = response.text().await?;
|
||||
|
||||
let releases: Vec<GithubRelease> = serde_json::from_str(&body)?;
|
||||
Ok(releases)
|
||||
}
|
||||
}
|
||||
1
babylonia-terminal-sdk/src/utils/mod.rs
Normal file
1
babylonia-terminal-sdk/src/utils/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod github_requester;
|
||||
Loading…
Reference in New Issue
Block a user