Skip to content

Commit

Permalink
Merge pull request #151 from Grasscutters/more_cli
Browse files Browse the repository at this point in the history
Passable amount of CLI options
  • Loading branch information
SpikeHD authored Apr 22, 2023
2 parents 5480af7 + c88e3ce commit c735b89
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 14 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"rust-analyzer.linkedProjects": [".\\src-tauri\\Cargo.toml"]
}
27 changes: 27 additions & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ sudo = "0.6.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.0.7", features = ["api-all"] }

# Arg parsing
args = "2.0"
getopts = "0.2"

# Access system process info.
sysinfo = "0.24.6"

Expand Down
44 changes: 44 additions & 0 deletions src-tauri/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::string::String;

#[derive(Serialize, Deserialize, Debug)]
pub struct Configuration {
pub toggle_grasscutter: bool,
pub game_install_path: String,
pub grasscutter_with_game: bool,
pub grasscutter_path: String,
pub java_path: String,
pub close_action: u64,
pub startup_launch: bool,
pub last_ip: String,
pub last_port: String,
pub language: String,
pub customBackground: String,
pub cert_generated: bool,
pub theme: String,
pub https_enabled: bool,
pub debug_enabled: bool,
pub patch_rsa: bool,
pub use_internal_proxy: bool,
pub wipe_login: bool,
pub horny_mode: bool,
pub auto_mongodb: bool,
pub un_elevated: bool,
}

pub fn config_path() -> PathBuf {
let mut path = tauri::api::path::data_dir().unwrap();
path.push("cultivation");
path.push("configuration.json");

path
}

pub fn get_config() -> Configuration {
let path = config_path();
let config = std::fs::read_to_string(path).unwrap();
let config: Configuration = serde_json::from_str(&config).unwrap();

config
}
121 changes: 111 additions & 10 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
windows_subsystem = "windows"
)]

use args::{Args, ArgsError};
use file_helpers::dir_exists;

use once_cell::sync::Lazy;
use proxy::set_proxy_addr;
use std::fs;
use std::io::Write;
use std::{collections::HashMap, sync::Mutex};
Expand All @@ -18,10 +21,12 @@ use sysinfo::{Pid, ProcessExt, System, SystemExt};
use crate::admin::reopen_as_admin;

mod admin;
mod config;
mod downloader;
mod file_helpers;
mod gamebanana;
mod lang;
mod patch;
mod proxy;
mod release;
mod system_helpers;
Expand All @@ -36,24 +41,116 @@ fn try_flush() {
std::io::stdout().flush().unwrap_or(())
}

fn has_arg(args: &[String], arg: &str) -> bool {
args.contains(&arg.to_string())
}
async fn parse_args(inp: &Vec<String>) -> Result<Args, ArgsError> {
let mut args = Args::new(
"Cultivation",
"Private server helper program for an Anime Game",
);
args.flag("h", "help", "Print various CLI args");
args.flag("p", "proxy", "Start the proxy server");
args.flag("G", "launch-game", "Launch the game");
args.flag(
"A",
"no-admin",
"Launch without requiring admin permissions",
);
args.flag(
"g",
"no-gui",
"Run in CLI mode. Requires -A to be passed as well.",
);
args.flag("s", "server", "Launch the configured GC server");
args.flag(
"P",
"patch",
"Patch your game before launching, with whatever your game version needs",
);
args.flag(
"N",
"non-elevated-game",
"Launch the game without admin permissions",
);
args.option(
"H",
"host",
"Set host to connect to (eg. 'localhost:443' or 'my.awesomeserver.com:6969)",
"SERVER_HOST",
getopts::Occur::Optional,
None,
);
args.option(
"a",
"game-args",
"Arguments to pass to the game process, if launching it",
r#""-opt-one -opt-two""#,
getopts::Occur::Optional,
None,
);

args.parse(inp).unwrap();

let config = config::get_config();

if args.value_of("help")? {
println!("{}", args.full_usage());
std::process::exit(0);
}

if args.value_of("launch-game")? {
let game_path = config.game_install_path;
let game_args: String = args.value_of("game-args").unwrap_or(String::new());

// Patch if needed
if args.value_of("patch")? {
patch::patch_game().await;
}

if args.value_of("non-elevated-game")? {
system_helpers::run_un_elevated(game_path.to_string(), Some(game_args))
} else {
system_helpers::run_program(game_path.to_string(), Some(game_args))
}
}

async fn arg_handler(args: &[String]) {
if has_arg(args, "--proxy") {
if args.value_of("server")? {
let server_jar = config.grasscutter_path;
let mut server_path = server_jar.clone();
// Strip jar name from path
if server_path.contains('/') {
// Can never panic because of if
let len = server_jar.rfind('/').unwrap();
server_path.truncate(len);
} else if server_path.contains('\\') {
let len = server_jar.rfind('\\').unwrap();
server_path.truncate(len);
}
let java_path = config.java_path;

system_helpers::run_jar(server_jar, server_path.to_string(), java_path);
}

if args.value_of::<String>("host").is_ok() && !args.value_of::<String>("host")?.is_empty() {
let host = args.value_of::<String>("host")?;
set_proxy_addr(host);
}

if args.value_of("proxy")? {
println!("Starting proxy server...");
let mut pathbuf = tauri::api::path::data_dir().unwrap();
pathbuf.push("cultivation");
pathbuf.push("ca");

connect(8035, pathbuf.to_str().unwrap().to_string()).await;
}

Ok(args)
}

fn main() {
fn main() -> Result<(), ArgsError> {
let args: Vec<String> = std::env::args().collect();
let parsed_args = block_on(parse_args(&args)).unwrap();

if !is_elevated() && !has_arg(&args, "--no-admin") {
if !is_elevated() && !parsed_args.value_of("no-admin")? {
println!("===============================================================================");
println!("You running as a non-elevated user. Some stuff will almost definitely not work.");
println!("===============================================================================");
Expand All @@ -71,16 +168,15 @@ fn main() {
exe_path.pop();
std::env::set_current_dir(&exe_path).unwrap();

block_on(arg_handler(&args));

// For disabled GUI
ctrlc::set_handler(|| {
disconnect();
block_on(patch::unpatch_game());
std::process::exit(0);
})
.unwrap_or(());

if !has_arg(&args, "--no-gui") {
if !parsed_args.value_of("no-gui")? {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
enable_process_watcher,
Expand Down Expand Up @@ -142,6 +238,11 @@ fn main() {

// Always disconnect upon closing the program
disconnect();

// Always unpatch game upon closing the program
block_on(patch::unpatch_game());

Ok(())
}

#[tauri::command]
Expand Down
59 changes: 59 additions & 0 deletions src-tauri/src/patch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::config;
use crate::file_helpers;
use crate::system_helpers;
use std::path::PathBuf;

pub async fn patch_game() -> bool {
let patch_path = PathBuf::from(system_helpers::install_location()).join("patch/version.dll");

// Are we already patched with mhypbase? If so, that's fine, just continue as normal
let game_is_patched = file_helpers::are_files_identical(
patch_path.clone().to_str().unwrap(),
PathBuf::from(get_game_rsa_path().await.unwrap())
.join("mhypbase.dll")
.to_str()
.unwrap(),
);

// Tell user they won't be unpatched with manual mhypbase patch
if game_is_patched {
println!(
"You are already patched using mhypbase, so you will not be auto patched and unpatched!"
);
return true;
}

// Copy the patch to game files
let replaced = file_helpers::copy_file_with_new_name(
patch_path.clone().to_str().unwrap().to_string(),
get_game_rsa_path().await.unwrap(),
String::from("version.dll"),
);

if !replaced {
return false;
}

true
}

pub async fn unpatch_game() -> bool {
// Just delete patch since it's not replacing any existing file
let deleted = file_helpers::delete_file(
PathBuf::from(get_game_rsa_path().await.unwrap())
.join("version.dll")
.to_str()
.unwrap()
.to_string(),
);

deleted
}

pub async fn get_game_rsa_path() -> Option<String> {
let config = config::get_config();
let mut game_folder = PathBuf::from(config.game_install_path);
game_folder.pop();

Some(format!("{}/", game_folder.to_str().unwrap()).replace('\\', "/"))
}
2 changes: 2 additions & 0 deletions src-tauri/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub fn set_proxy_addr(addr: String) {
} else {
*SERVER.lock().unwrap() = addr;
}

println!("Set server to {}", SERVER.lock().unwrap());
}

#[async_trait]
Expand Down
Loading

0 comments on commit c735b89

Please sign in to comment.