Compare commits

...

11 Commits
0.1.0 ... main

Author SHA1 Message Date
Julian a99e083ce7 Update 'README.md' 2023-02-07 02:03:11 +00:00
Julian e407af4d98
suggest patcher 2023-02-05 16:14:40 -05:00
Julian 98e882eb11
i have infinite time what point does this serve 2023-02-05 12:58:44 -05:00
Julian 4bec7d8198
0.2.1 2023-02-03 14:02:22 -05:00
Julian 9abd399115
Use root folder name from zip 2023-02-03 14:01:57 -05:00
Julian 98dbd192a1
update readme 2023-02-03 11:55:40 -05:00
Julian db9f09a0b2
update error messages 2023-02-02 20:26:48 -05:00
Julian f8cd0c3449
update readme 2023-02-01 16:34:14 -05:00
Julian 6a40968eb7
oh two oh 2023-02-01 16:14:32 -05:00
Julian 7bf28b2657
rename some variable names to be more accurate 2023-01-31 19:24:22 -05:00
Julian 9f48c384c5
add link to releases page in readme 2023-01-31 17:36:43 -05:00
4 changed files with 251 additions and 49 deletions

90
Cargo.lock generated
View File

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
@ -25,6 +34,9 @@ name = "anyhow"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
dependencies = [
"backtrace",
]
[[package]]
name = "async-channel"
@ -43,6 +55,21 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
version = "0.3.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "base64ct"
version = "1.5.3"
@ -464,12 +491,15 @@ dependencies = [
[[package]]
name = "geezshade"
version = "0.1.0"
version = "0.2.1"
dependencies = [
"anyhow",
"copypasta",
"isahc",
"native-dialog",
"semver",
"serde",
"serde_json",
"zip",
]
@ -494,6 +524,12 @@ dependencies = [
"wasi",
]
[[package]]
name = "gimli"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec"
[[package]]
name = "hmac"
version = "0.12.1"
@ -759,6 +795,15 @@ dependencies = [
"objc",
]
[[package]]
name = "object"
version = "0.30.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.17.0"
@ -933,6 +978,18 @@ dependencies = [
"thiserror",
]
[[package]]
name = "rustc-demangle"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "ryu"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "schannel"
version = "0.1.21"
@ -948,11 +1005,42 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]]
name = "semver"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
[[package]]
name = "serde"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha1"

View File

@ -2,12 +2,15 @@
name = "geezshade"
description = "Automated ReShade setup for FFXIV with GShade presets"
authors = ["NotNite <hi@notnite.com>"]
version = "0.1.0"
version = "0.2.1"
edition = "2021"
[dependencies]
anyhow = "1.0.68"
anyhow = { version = "1.0.68", features = ["backtrace"] }
copypasta = "0.8.1"
isahc = "1.7.2"
native-dialog = "0.6.3"
semver = "1.0.16"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.91"
zip = "0.6.3"

View File

@ -1,7 +1,36 @@
# GeezShade
Automated ReShade setup for FFXIV with GShade presets.
Automated ReShade setup for FFXIV with GShade presets. Make backups before using this - no stability guarantees.
**Note: This is broken, and likely will remain broken. Use [this](https://git.n2.pm/NotNite/DeezShade) instead.**
[CLICK ME TO INSTALL IT](https://git.n2.pm/NotNite/geezshade/releases/latest).
## Why?
I felt like it.
## How?
ReShade's installer is just a weird .zip file and GShade is just reskinned ReShade with barely any new features. Almost every single shader I've tested works fine on ReShade.
Specifically, it goes through the following steps:
- Fetch information about the latest release of ReShade and GShade from [a metadata file](https://notnite.com/geezshade.json)
- Download [ReShade](https://reshade.me/#download) with full add-on support and extract it
- Download [GShade shaders](https://github.com/Mortalitas/GShade) and extract them
- Download [GShade presets](https://github.com/Mortalitas/GShade-Presets) and extract them
I am not rehosting any of the shaders or presets. The download process uses the GitHub API and the ReShade CDN. These are open to the Internet for anyone to download in two clicks - it's just been automated here.
Note that for a short period of time after releasing this, ReShade's CDN went offline and I switched to a rehost for a few hours.
## Help, something's broken
If it's with the installer - email me! `geezshade@(my username).com`
If it's with ReShade or the shaders - don't waste your time. GShade provides no guarantees their shaders will work on ReShade.
## I want to contribute
This Forgejo instance doesn't have signups enabled. Email me a patch file (see above).

View File

@ -1,20 +1,36 @@
use copypasta::{ClipboardContext, ClipboardProvider};
use isahc::{prelude::*, ReadResponseExt, Request};
use native_dialog::{FileDialog, MessageDialog, MessageType};
use serde::Deserialize;
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";
#[derive(Deserialize, Debug, Clone)]
struct GeezShadeConfig {
reshade_url: String,
gshade_shaders_url: String,
gshade_presets_url: String,
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";
geezshade_version: String,
geezshade_user_agent: String,
}
fn get_file(path: &str) -> anyhow::Result<Vec<u8>> {
fn get_geezshade_config() -> anyhow::Result<GeezShadeConfig> {
let req = Request::get("https://notnite.com/geezshade.json").header(
"User-Agent",
format!("GeezShade/{}", env!("CARGO_PKG_VERSION")),
);
let mut resp = req.body(())?.send()?;
let text = resp.text()?;
let config: GeezShadeConfig = serde_json::from_str(&text)?;
Ok(config)
}
fn get_file(path: &str, user_agent: String) -> anyhow::Result<Vec<u8>> {
let req = Request::get(path)
.header("User-Agent", USER_AGENT)
.header("User-Agent", user_agent)
.redirect_policy(isahc::config::RedirectPolicy::Follow);
let mut resp = req.body(())?.send()?;
@ -22,9 +38,9 @@ fn get_file(path: &str) -> anyhow::Result<Vec<u8>> {
Ok(resp.bytes()?)
}
fn get_reshade(xiv_install: PathBuf) -> anyhow::Result<()> {
fn get_reshade(xiv_install: PathBuf, config: GeezShadeConfig) -> anyhow::Result<()> {
println!("fetching reshade");
let reshade_installer = get_file(RESHADE_URL)?;
let reshade_installer = get_file(&config.reshade_url, config.geezshade_user_agent)?;
println!("extracting dll");
let mut zip = zip::ZipArchive::new(Cursor::new(reshade_installer))?;
@ -37,31 +53,47 @@ fn get_reshade(xiv_install: PathBuf) -> anyhow::Result<()> {
Ok(())
}
fn get_gshade_presets(xiv_install: PathBuf) -> anyhow::Result<()> {
fn get_gshade_presets(xiv_install: PathBuf, config: GeezShadeConfig) -> anyhow::Result<()> {
println!("fetching presets");
let gshade_presets = get_file(GSHADE_PRESETS_URL)?;
let gshade_community_presets = get_file(GSHADE_COMMUNITY_PRESETS_URL)?;
let gshade_shaders = get_file(
&config.gshade_shaders_url,
config.geezshade_user_agent.clone(),
)?;
let gshade_presets = get_file(&config.gshade_presets_url, config.geezshade_user_agent)?;
println!("opening presets");
let shaders_zip = zip::ZipArchive::new(Cursor::new(gshade_shaders))?;
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 shaders_folder_name = shaders_zip
.file_names()
.next()
.unwrap()
.split('/')
.next()
.unwrap()
.to_string();
let presets_folder_name = presets_zip
.file_names()
.next()
.unwrap()
.split('/')
.next()
.unwrap()
.to_string();
let shaders_folders = vec!["Textures", "Shaders", "ComputeShaders"]
.iter()
.map(|x| format!("{}/{}", shaders_folder_name, x))
.collect::<Vec<String>>();
let presets_folders = vec![format!("{}/FFXIV", presets_folder_name)];
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(),
)?;
extract(dir.clone(), shaders_zip, shaders_folders)?;
extract(dir, presets_zip, presets_folders)?;
Ok(())
}
@ -69,7 +101,7 @@ fn get_gshade_presets(xiv_install: PathBuf) -> anyhow::Result<()> {
fn extract(
dir: PathBuf,
presets_zip: ZipArchive<Cursor<Vec<u8>>>,
presets_folders: Vec<&str>,
presets_folders: Vec<String>,
) -> anyhow::Result<()> {
for filename in presets_zip.file_names() {
for folder in &presets_folders {
@ -142,9 +174,33 @@ fn get_game_exe() -> anyhow::Result<PathBuf> {
}
}
fn do_the_thing(xiv_install: PathBuf) -> anyhow::Result<()> {
get_reshade(xiv_install.clone())?;
get_gshade_presets(xiv_install.clone())?;
fn show_error(message: &str, error: String) {
MessageDialog::new()
.set_title("GeezShade")
.set_text(&format!("{}\n\nAn error message will be copied to your clipboard. Please report this to geezshade@notnite.com.", message))
.set_type(MessageType::Error)
.show_alert().unwrap();
let mut clipboard = ClipboardContext::new().unwrap();
clipboard.set_contents(error).unwrap();
}
fn do_the_thing(xiv_install: PathBuf, config: GeezShadeConfig) -> anyhow::Result<()> {
if let Err(e) = get_reshade(xiv_install.clone(), config.clone()) {
show_error(
"Failed to download ReShade. You will have to manually install ReShade yourself.",
format!("{:?}", e),
);
return Ok(());
}
if let Err(e) = get_gshade_presets(xiv_install.clone(), config) {
show_error(
"Failed to download GShade shaders & presets. Please try again later.",
format!("{:?}", e),
);
return Ok(());
}
println!("making screenshot folders");
std::fs::create_dir_all(xiv_install.join("reshade-screenshots"))?;
@ -160,35 +216,61 @@ SavePath=.\reshade-screenshots
"#
.trim();
println!("writing config");
std::fs::write(xiv_install.join("ReShade.ini"), config)?;
if !xiv_install.join("ReShade.ini").exists() {
println!("writing config");
std::fs::write(xiv_install.join("ReShade.ini"), config)?;
} else {
println!("config already exists");
}
Ok(())
}
fn main() -> anyhow::Result<()> {
let config = get_geezshade_config();
let config = match config {
Ok(config) => config,
Err(e) => {
show_error(
"An error occured trying to fetch information required for GeezShade. This may be because you are offline, the server is down, or the installer is critically out of date.\nTry downloading the latest version at https://notnite.com/geezshade or try again later.",
format!("{:?}", e),
);
std::process::exit(1);
}
};
let semver_current = semver::Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
let semver_latest = semver::Version::parse(&config.geezshade_version).unwrap();
if semver_latest > semver_current {
let choice = MessageDialog::new()
.set_title("GeezShade")
.set_text("A new version of GeezShade is available to download.\nPlease go to https://notnite.com/geezshade for the latest version.\nNot updating may break the installation process, but it is not required.\n\nContinue anyways?")
.set_type(MessageType::Warning)
.show_confirm()?;
if !choice {
return Ok(());
}
}
let game_exe = get_game_exe()?;
let xiv_install = game_exe.parent().unwrap();
let choice = MessageDialog::new()
.set_title("GeezShade")
.set_text("GeezShade will now download ReShade and the GShade presets.\nMake a backup before of your presets and settings before continuing.\n\nContinue?")
.set_type(MessageType::Info)
.show_confirm()?;
.set_title("GeezShade")
.set_text("GeezShade will now download ReShade and the GShade presets.\nMake a backup before of your presets and settings before continuing.\n\nContinue?")
.set_type(MessageType::Info)
.show_confirm()?;
if !choice {
return Ok(());
}
if let Err(e) = do_the_thing(xiv_install.to_path_buf()) {
MessageDialog::new()
.set_title("GeezShade")
.set_text("An error occurred installing ReShade.\nThis error will be copied to your clipboard.\nPlease report this error to geezshade@notnite.com.")
.set_type(MessageType::Error)
.show_alert()?;
let mut clipboard = ClipboardContext::new().unwrap();
clipboard.set_contents(e.to_string()).unwrap();
if let Err(e) = do_the_thing(xiv_install.to_path_buf(), config) {
show_error("An error occured setting up ReShade.", format!("{:?}", e));
return Err(e);
}