use std::{
collections::HashMap,
fs::{self, File},
io::Read,
process::Command,
string::String,
};
use bdgm::{error::BDGMError, game::Game};
use clap::Parser;
use fs_extra::dir::{self, CopyOptions};
use hadris_udf::UdfVolume;
use platform_dirs::AppDirs;
use crate::{args::Args, dump::extract_udf_dir, error::AppError};
#[cfg(windows)]
use crate::dump::dump_disc;
pub(crate) fn run() -> anyhow::Result<()> {
let app_dirs = AppDirs::new(Some("bdgm-play"), true).ok_or(AppError::NoAppDirs)?;
let args = {
let args = Args::parse();
println!("Playing {}", args.location.to_string_lossy());
let mut raw_disc = false;
#[cfg(windows)]
{
raw_disc = args.raw_disc;
}
if args.image || raw_disc {
let file = if args.image {
File::open(&args.location)?
} else {
#[cfg(windows)]
{
let dump_file = app_dirs.data_dir.join("dump.bin");
dump_disc(
&args.location.to_string_lossy(),
&dump_file.to_string_lossy(),
)?;
File::open(&dump_file)?
}
#[cfg(not(windows))]
{
File::open("")?
}
};
let udf = UdfVolume::open(file)?;
let extract_dir = app_dirs.data_dir.join("extract");
if extract_dir.exists() {
fs::remove_dir_all(&extract_dir)?;
}
extract_udf_dir(&udf, &udf.root_dir()?, &extract_dir)?;
#[cfg(windows)]
{
Args {
location: extract_dir,
image: false,
raw_disc: false,
}
}
#[cfg(not(windows))]
{
Args {
location: extract_dir,
image: false,
}
}
} else {
args
}
};
let manifest_path = args.location.join("BDGM").join("DISC.BDGM");
if !manifest_path.try_exists()? {
return Err(BDGMError::DiscFileMissing.into());
}
let mut manifest = File::open(manifest_path)?;
let mut contents = String::new();
println!("Reading manifest...");
manifest.read_to_string(&mut contents)?;
let game = Game::from_str(&contents)?;
let app_dir_path = args.location.join("BDGM").join("APP");
let executable_path = app_dir_path.join(&game.executable);
if !executable_path.try_exists()? {
return Err(BDGMError::ExecutableMissing.into());
}
let game_dir = app_dirs.data_dir.join(&game.id);
let cache_dir = app_dirs.cache_dir.join(&game.id);
let data_dir = game_dir.join("data");
let install_dir = game_dir.join("app").join(game.version);
if !install_dir.try_exists()? {
println!("Copying files...");
dir::create_all(&install_dir, false)?;
dir::copy(
&app_dir_path,
&install_dir,
&CopyOptions::new().overwrite(true).content_only(true),
)?;
println!("Copied!");
}
let mut envvars = HashMap::new();
envvars.insert("BDGM_DATA", data_dir.to_string_lossy().into_owned());
envvars.insert("XDG_DATA_DIRS", data_dir.to_string_lossy().into_owned());
envvars.insert("BDGM_CACHE", cache_dir.to_string_lossy().into_owned());
envvars.insert("BDGM_APP", app_dir_path.to_string_lossy().into_owned());
envvars.insert("BDGM_DISC", args.location.to_string_lossy().into_owned());
envvars.insert("BDGM_VERSION", "1.0".to_string());
match game.runtime {
bdgm::runtime::Runtime::Java => {
Command::new("java")
.args(game.runtime_args)
.arg("--jar")
.arg(install_dir.join(game.executable))
.arg("--")
.args(game.args)
.envs(envvars)
.current_dir(&install_dir)
.status()?;
}
bdgm::runtime::Runtime::Dotnet => {
Command::new("dotnet")
.args(game.runtime_args)
.arg(install_dir.join(game.executable))
.arg("--")
.args(game.args)
.envs(envvars)
.current_dir(&install_dir)
.status()?;
}
bdgm::runtime::Runtime::Python => {
Command::new("python")
.args(game.runtime_args)
.arg(install_dir.join(game.executable))
.arg("--")
.args(game.args)
.envs(envvars)
.current_dir(&install_dir)
.status()?;
}
bdgm::runtime::Runtime::Windows => {
if cfg!(target_os = "windows") {
Command::new(install_dir.join(game.executable))
.args(game.args)
.envs(envvars)
.current_dir(&install_dir)
.status()?;
} else {
Command::new("wine")
.args(game.runtime_args)
.arg(install_dir.join(game.executable))
.args(game.args)
.envs(envvars)
.env("WINEPREFIX", game_dir.join("wineprefix"))
.current_dir(&install_dir)
.status()?;
}
}
};
Ok(())
}