Initial Commit

This commit is contained in:
2022-07-17 22:42:42 -07:00
parent aa51ef9db5
commit 94e112ad6b
3 changed files with 379 additions and 0 deletions

364
src/main.rs Normal file
View File

@@ -0,0 +1,364 @@
use std::path::Path;
use std::str;
use std::*;
use fs_extra::{copy_items, dir};
use iui::controls::{Button, Group, Label, VerticalBox};
use iui::prelude::*;
use regex::Regex;
static AMONG_US_APPID: &'static str = "945360";
struct AmongUsVersion {
year: i32,
month: i32,
day: i32,
}
impl fmt::Display for AmongUsVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}.{}", self.year, self.month, self.day)
}
}
impl From<&str> for AmongUsVersion {
fn from(s: &str) -> AmongUsVersion {
let v: Vec<&str> = s.split(".").collect();
AmongUsVersion {
year: i32::from_str_radix(v[0], 10).unwrap(),
month: i32::from_str_radix(v[1], 10).unwrap(),
day: i32::from_str_radix(v[2], 10).unwrap(),
}
}
}
fn attempt_run_among_us(install_path: &path::Path) {
let executable_path: path::PathBuf = [install_path.to_str().unwrap(), "Among Us.exe"]
.iter()
.collect();
std::process::Command::new(executable_path.to_str().unwrap())
.spawn()
.unwrap();
}
fn main() {
// CREATE PROGRAM DIRECTORY
let mut data_path = dirs::data_dir().unwrap();
data_path.push("town-of-us-updater");
fs::create_dir(data_path.clone()).unwrap_or(());
let mut installs_path = data_path.clone();
installs_path.push("installs");
fs::create_dir(installs_path.clone()).unwrap_or(());
let ui = UI::init().expect("UI failed to init");
let mut win = Window::new(&ui, "Town of Us Updater", 600, 400, WindowType::NoMenubar);
let mut vbox = VerticalBox::new(&ui);
vbox.set_padded(&ui, true);
// Find existing installs, make buttons for them
let install_iter = fs::read_dir(installs_path.clone());
match install_iter {
Ok(iter) => {
for i in iter {
let existing_ver_smash = i.unwrap().file_name();
let mut button = Button::new(&ui, existing_ver_smash.clone().to_str().unwrap());
button.on_clicked(&ui, {
let ui = ui.clone();
let installs_path = installs_path.clone();
let existing_ver_smash = existing_ver_smash.clone();
move |btn| {
let mut new_path = installs_path.clone();
new_path.push(existing_ver_smash.clone());
println!("{}", new_path.clone().to_str().unwrap());
attempt_run_among_us(&new_path);
btn.set_text(&ui, "Amogus");
}
});
vbox.append(&ui, button, LayoutStrategy::Compact);
println!("{}", existing_ver_smash.clone().to_str().unwrap());
}
}
_ => (),
}
let mut button = Button::new(&ui, "Button");
button.on_clicked(&ui, {
let ui = ui.clone();
move |btn| {
let folder_opt = detect_among_us_folder();
if folder_opt.is_some() {
btn.set_text(&ui, "Amogus");
ui.quit();
}
}
});
let folder_opt = detect_among_us_folder();
let mut among_us_folder = path::PathBuf::new();
if folder_opt.is_some() {
among_us_folder.push(folder_opt.unwrap());
} else {
win.modal_msg(&ui, "Find Among Us", "On the following Open File dialog, navigate to your Among Us folder and select Among Us.exe");
let open_window = win.open_file(&ui);
// println!("{}", open_window.unwrap().to_str().unwrap());
among_us_folder = open_window.unwrap().clone();
among_us_folder.pop();
// vbox.append(&ui, button, LayoutStrategy::Compact);
// win.set_child(&ui, vbox);
// win.show(&ui);
// ui.main();
}
println!("Among Us Folder: {}", among_us_folder.to_str().unwrap());
let among_us_version =
determine_among_us_version(String::from(among_us_folder.to_str().unwrap())).unwrap();
let ver_url: (String, String) = determine_town_of_us_url(among_us_version.clone()).unwrap();
let version_smash = format!("{}-{}", among_us_version.clone(), ver_url.0.clone());
let new_installed_path: path::PathBuf =
[installs_path.to_str().unwrap(), version_smash.as_str()]
.iter()
.collect();
if !path::Path::exists(&new_installed_path) {
copy_folder_to_target(
among_us_folder.to_str().unwrap(),
installs_path.to_str().unwrap(),
);
let among_us_path: path::PathBuf = [installs_path.to_str().unwrap(), "Among Us\\"]
.iter()
.collect();
println!(
"Rename {} to {}",
among_us_path.to_str().unwrap(),
new_installed_path.to_str().unwrap()
);
let mut perms = fs::metadata(among_us_path.clone()).unwrap().permissions();
perms.set_readonly(false);
fs::set_permissions(among_us_path.clone(), perms).unwrap();
fs::rename(among_us_path, new_installed_path.clone()).unwrap();
let mut download_path = data_path.clone();
let downloaded_filename = ver_url.1.rsplit("/").nth(0).unwrap();
download_path.push(downloaded_filename.clone());
if !path::Path::exists(&download_path) {
println!("{:?}", download_path);
println!("Downloading Town of Us [{}]", ver_url.1.clone());
let zip = reqwest::blocking::get(ver_url.1.clone())
.unwrap()
.bytes()
.unwrap();
fs::write(download_path.clone(), zip).unwrap();
}
let opened_zip = fs::File::open(download_path).unwrap();
println!("Extracting...");
let mut archive = zip::ZipArchive::new(opened_zip).unwrap();
archive.extract(data_path.clone()).unwrap();
let mut root_folder_path = String::new();
for i in archive.file_names() {
root_folder_path = String::from(i.split("/").nth(0).unwrap());
break;
}
let extracted_path: path::PathBuf =
[data_path.to_str().unwrap(), root_folder_path.as_str(), "."]
.iter()
.collect();
println!("{}", extracted_path.to_str().unwrap());
copy_folder_contents_to_target(
extracted_path.to_str().unwrap(),
new_installed_path.to_str().unwrap(),
);
} else {
println!("Modded install already found");
}
// let mut install_folder_path = installs_path.clone();
// install_folder_path.push(version_smash);
// fs::create_dir(install_folder_path.clone()).unwrap_or(());
// Copy Among Us Out
// Create destination path
let executable_path: path::PathBuf = [new_installed_path.to_str().unwrap(), "Among Us.exe"]
.iter()
.collect();
std::process::Command::new(executable_path.to_str().unwrap())
.spawn()
.unwrap();
}
// Returns (Version, URL)
fn determine_town_of_us_url(among_us_version: String) -> Option<(String, String)> {
let markdown = reqwest::blocking::get(
"https://raw.githubusercontent.com/eDonnes124/Town-Of-Us-R/master/README.md",
)
.unwrap()
.text()
.unwrap();
let mut line = markdown.find(&among_us_version);
if line.is_some() {
println!("Found official version!");
} else {
println!("Official version cannot be determined.");
println!("At this point, there are two options:");
println!(" [1] Revert Among Us to public-previous in Steam THEN select this option.");
println!(" [2] Attempt to use the latest version of Town of Us anyway");
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
match input.trim() {
"1" => {
println!("Re-attempting...");
return None;
}
"2" => {
println!("Continuing...");
line = markdown.find("[Download]");
}
_ => return None,
};
}
// 100% scientific "-15" here to get the correct version since we find to [Download] above which is after the version number for that line
let splits = markdown.split_at(line.unwrap() - 15);
// println!("{}", splits.1);
let url_regex = Regex::new(r#"\(([\w\d:/\.\-]+)\)\s|\n"#).unwrap();
let captures = url_regex.captures(splits.1).unwrap();
let capture = captures.get(captures.len() - 1).unwrap();
let url = splits.1.get(capture.start()..capture.end()).unwrap();
println!("Official URL is: {}", url);
let ver_regex = Regex::new(r#"\| (v\d\.\d\.\d) \|"#).unwrap();
let ver_captures = ver_regex.captures(splits.1).unwrap();
let ver_capture = ver_captures.get(ver_captures.len() - 1).unwrap();
let ver = splits
.1
.get(ver_capture.start()..ver_capture.end())
.unwrap();
println!("Matching version is: {}", ver);
Some((String::from(ver), String::from(url)))
}
fn determine_among_us_version(folder_root: String) -> Option<String> {
let asset_file = format!("{}\\Among Us_Data\\globalgamemanagers", folder_root);
const TARGET_BYTES_LEN: usize = 16;
let target_bytes: [u8; TARGET_BYTES_LEN] = [3, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0];
let file_bytes = fs::read(asset_file).unwrap();
//println!("{:?}", file_bytes);
let mut bytes_str = String::new();
let mut target_head = 0;
let mut file_index = 0;
for i in &file_bytes {
if target_head == TARGET_BYTES_LEN {
break;
}
if *i == target_bytes[target_head] {
target_head += 1;
} else {
target_head = 0;
}
file_index += 1;
bytes_str += &format!("{i:x}");
}
let offset: usize = usize::from(file_bytes[file_index]);
file_index += 4;
// let mut offset = 10;
// if file_bytes[file_index + 9] == 0 {
// offset -= 1;
// }
// if file_bytes[file_index + 8] == 0 {
// offset -= 1;
// }
println!(
"|{}|",
str::from_utf8(file_bytes.get(file_index..file_index + offset).unwrap()).unwrap()
);
let ver = AmongUsVersion::from(
str::from_utf8(file_bytes.get(file_index..file_index + offset).unwrap()).unwrap(),
);
println!("AmongUsVersion: {}", ver);
Some(String::from(
str::from_utf8(file_bytes.get(file_index..file_index + offset).unwrap()).unwrap(),
))
//println!("{}", bytes_str);
//None
}
fn copy_folder_to_target<T: AsRef<path::Path>>(source: T, dest: T) {
let mut copy_opts = dir::CopyOptions::new();
copy_opts.overwrite = true;
copy_opts.skip_exist = true;
copy_opts.copy_inside = true;
let mut from_paths = Vec::new();
from_paths.push(source);
copy_items(&from_paths, dest, &copy_opts).unwrap();
}
fn copy_folder_contents_to_target<T: AsRef<path::Path>>(source: T, dest: T) {
let mut copy_opts = dir::CopyOptions::new();
copy_opts.overwrite = true;
copy_opts.skip_exist = true;
copy_opts.copy_inside = true;
copy_opts.content_only = true;
fs_extra::dir::copy(source, dest, &copy_opts).unwrap();
}
fn detect_among_us_folder() -> Option<String> {
let library_folder =
fs::read_to_string("C:\\Program Files (x86)\\Steam\\steamapps\\libraryfolders.vdf");
if library_folder.is_ok() {
println!("Steam is on C:\\ drive!");
let mut library_folder_string: String = library_folder.unwrap();
let appid_index = library_folder_string.find(AMONG_US_APPID);
if appid_index.is_none() {
println!("Among Us not found!");
return None;
} else {
library_folder_string.truncate(appid_index.unwrap());
}
//println!("{}", library_folder_string);
let path_regex = Regex::new(r#"path"\s+"([Z-a\w\d\s\\\(\):]+)""#).unwrap();
let caps: regex::CaptureMatches = path_regex.captures_iter(&library_folder_string);
let last_path = caps.last().unwrap();
let start = last_path.get(last_path.len() - 1).unwrap();
/*
println!(
"{}",
library_folder_string
.get(start.start()..start.end())
.unwrap()
);
*/
return Some(format!(
"{}\\\\steamapps\\\\common\\\\Among Us\\\\",
library_folder_string
.get(start.start()..start.end())
.unwrap()
));
}
None
}