#!/usr/bin/perl use autodie; use strict; use warnings; use File::Slurp; use Archive::Zip; use LWP::UserAgent; use File::Spec; use File::Path qw(make_path); my $userAgent = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0}); $userAgent->agent("reshade-on-unix/0.1"); $userAgent->show_progress(1); sub reShadeVersion { my $req = HTTP::Request->new(GET => "https://api.github.com/repos/crosire/reshade/tags"); my $response = $userAgent->request($req); $response->is_success or die $response->status_line; my ($version) = $response->decoded_content =~ /v([\d.]+)/ or die "Could not extract version info"; return $version; } sub downloadFile { my $url = $_[0]; my $file = $_[1]; my $req = HTTP::Request->new(GET => $url); my $response = $userAgent->request($req, $file); $response->is_success or die $response->status_line; } sub getGamePath { if (defined $ARGV[0]) { if (-d $ARGV[0]) { return $ARGV[0] } else { print "Supplied argument [${ARGV[0]}] is not a valid directory!\n" } } if ($^O eq "darwin") { my $xomGamePath = `defaults read dezent.XIV-on-Mac GamePath`; chomp $xomGamePath; $xomGamePath = $xomGamePath . "/game/"; if (-d $xomGamePath) { return $xomGamePath; } } print "Please enter the directory ReShade should be installed into: "; my $path = <STDIN>; chomp $path; if (-d $path) { return $path; } die "Provided path [${path}] is not a folder!"; } my $gamePath = getGamePath; my $shaderPath = File::Spec->catdir($gamePath, "reshade-shaders"); make_path($shaderPath) unless -d $shaderPath; print "Installing ReShade into: [${gamePath}]\n"; my $reshadeSetup = $gamePath . "reshade_setup.exe"; downloadFile("https://reshade.me/downloads/ReShade_Setup_" . reShadeVersion() . "_Addon.exe", $reshadeSetup); my $exeContent = read_file $reshadeSetup; unlink $reshadeSetup; my $magicBytes = pack "CC", 0x50, 0x4b, 0x03, 0x04; my $zipOffset = index $exeContent, $magicBytes; my $zipContent = substr $exeContent, $zipOffset; my $reshadeZip = $gamePath . "reshade.zip"; write_file($reshadeZip, $zipContent); my $zip = Archive::Zip->new($reshadeZip); $zip->extractMember("ReShade64.dll", $gamePath . "dxgi.dll"); unlink $reshadeZip; downloadFile("https://lutris.net/files/tools/dll/d3dcompiler_47.dll", $gamePath . "d3dcompiler_47.dll"); # Basic Shader URLs my %shaders = ( "00" => "https://github.com/crosire/reshade-shaders/archive/slim.zip", "01" => "https://github.com/CeeJayDK/SweetFX/archive/master.zip", "02" => "https://github.com/crosire/reshade-shaders/archive/legacy.zip", ); # Function to download and extract shaders into reshade-shaders directory sub download_and_extract_shader { my ($label, $url, $shader_dir) = @_; my $zip_file = File::Spec->catfile($shader_dir, "$label.zip"); print "Downloading shader $label...\n"; downloadFile($url, $zip_file); print "Extracting shader $label...\n"; my $zip = Archive::Zip->new($zip_file); my $extracted_count = 0; foreach my $member ($zip->members) { my $extracted_name = $member->fileName; next if $extracted_name =~ m{/$}; $extracted_name =~ s{^[^/]+/}{}; if ($extracted_name =~ m{^(Shaders|Textures)/(.+)$}) { my $sub_dir = $1; my $file_name = $2; my $dest_dir = File::Spec->catdir($shader_dir, $sub_dir); my $dest_path = File::Spec->catfile($dest_dir, $file_name); make_path($dest_dir) unless -d $dest_dir; $member->extractToFileNamed($dest_path); $extracted_count++; } } unlink $zip_file or warn "Could not delete $zip_file: $!\n"; print "Extracted $extracted_count files for shader $label\n"; } # Loop through each shader and process it foreach my $label (keys %shaders) { download_and_extract_shader($label, $shaders{$label}, $shaderPath); } print "All shaders have been downloaded and extracted into 'reshade-shaders'.\n";