use isahc::{prelude::*, ReadResponseExt, Request}; use std::{io::Cursor, path::PathBuf}; use zip::ZipArchive; const USER_AGENT: &str = "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0"; const RESHADE_URL: &str = "https://reshade.me/downloads/ReShade_Setup_5.6.0_Addon.exe"; const GSHADE_PRESETS_URL: &str = "https://github.com/Mortalitas/GShade/archive/refs/heads/master.zip"; const GSHADE_COMMUNITY_PRESETS_URL: &str = "https://github.com/Mortalitas/GShade-Presets/archive/refs/heads/master.zip"; fn get_file(path: &str) -> anyhow::Result> { let req = Request::get(path) .header("User-Agent", USER_AGENT) .redirect_policy(isahc::config::RedirectPolicy::Follow); let mut resp = req.body(())?.send()?; Ok(resp.bytes()?) } fn get_reshade(xiv_install: PathBuf) -> anyhow::Result<()> { println!("fetching reshade"); let reshade_installer = get_file(RESHADE_URL)?; println!("extracting dll"); let mut zip = zip::ZipArchive::new(Cursor::new(reshade_installer))?; let mut dll = zip.by_name("ReShade64.dll")?; println!("writing dll"); let mut dll_file = std::fs::File::create(xiv_install.join("dxgi.dll"))?; std::io::copy(&mut dll, &mut dll_file)?; Ok(()) } fn get_gshade_presets(xiv_install: PathBuf) -> anyhow::Result<()> { println!("fetching presets"); let gshade_presets = get_file(GSHADE_PRESETS_URL)?; let gshade_community_presets = get_file(GSHADE_COMMUNITY_PRESETS_URL)?; println!("opening presets"); let presets_zip = zip::ZipArchive::new(Cursor::new(gshade_presets))?; let community_presets_zip = zip::ZipArchive::new(Cursor::new(gshade_community_presets))?; let presets_folders = vec![ "GShade-master/Textures", "GShade-master/Shaders", "GShade-master/ComputeShaders", ]; let community_presets_folders = vec!["GShade-Presets-master/FFXIV"]; let dir = xiv_install.join("reshade-shaders"); println!("extracting presets"); extract(dir.clone(), presets_zip, presets_folders.clone())?; extract( dir, community_presets_zip, community_presets_folders.clone(), )?; Ok(()) } fn extract( dir: PathBuf, presets_zip: ZipArchive>>, presets_folders: Vec<&str>, ) -> anyhow::Result<()> { for filename in presets_zip.file_names() { for folder in &presets_folders { if filename.starts_with(folder) { let mut presets_zip = presets_zip.clone(); let mut file = presets_zip.by_name(filename)?; let path = filename.split('/').collect::>(); let path = path[1..].join("/"); let path = dir.join(path); if path.is_dir() || path.display().to_string().ends_with('/') { continue; } let dir = path.parent().unwrap().to_path_buf(); if !dir.exists() { std::fs::create_dir_all(dir)?; } let mut out = std::fs::File::create(path)?; std::io::copy(&mut file, &mut out)?; } } } Ok(()) } fn main() -> anyhow::Result<()> { let game_exe = std::env::args() .nth(1) .expect("supply a path to ffxiv_dx11.exe"); let game_exe = PathBuf::from(game_exe); let xiv_install = game_exe.parent().unwrap(); get_reshade(xiv_install.to_path_buf())?; get_gshade_presets(xiv_install.to_path_buf())?; println!("done lol"); Ok(()) }