mirror of
https://github.com/Grasscutters/Cultivation.git
synced 2025-01-08 12:07:45 +08:00
Add an option that allows binding port 443
Kinda everts some changes of "Implement MongoDB autostart and GC watching". This commit makes launching MongoDB async
This commit is contained in:
parent
2c07cf90bd
commit
62b54f33df
12
src-tauri/Cargo.lock
generated
12
src-tauri/Cargo.lock
generated
@ -940,6 +940,7 @@ dependencies = [
|
||||
"tokio-tungstenite 0.17.2",
|
||||
"tracing",
|
||||
"unrar",
|
||||
"which",
|
||||
"windows-service",
|
||||
"zip 0.6.2",
|
||||
"zip-extract",
|
||||
@ -5341,6 +5342,17 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
|
||||
dependencies = [
|
||||
"either",
|
||||
"libc",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "1.0.2"
|
||||
|
@ -25,6 +25,7 @@ sudo = "0.6.0"
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
anyhow = "1.0.58"
|
||||
term-detect = "0.1.7"
|
||||
which = "4.4"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
@ -34,7 +34,8 @@
|
||||
"auto_mongodb": "Automatically Start MongoDB",
|
||||
"un_elevated": "Run the game non-elevated (no admin)",
|
||||
"redirect_more": "Also redirect other MHY games",
|
||||
"check_aagl": "For more options, check the other launcher"
|
||||
"check_aagl": "For more options, check the other launcher",
|
||||
"grasscutter_elevation": "Method of running GC on restricted ports"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Download Grasscutter All-in-One",
|
||||
@ -86,7 +87,8 @@
|
||||
"use_proxy": "Use the Cultivation internal proxy. You should have this enabled unless you use something like Fiddler",
|
||||
"patch_rsa": "Patch and unpatch your game RSA automatically. Unless playing with old/non-official versions (3.0 and older), this should be enabled.",
|
||||
"add_delay": "Set delay in 3dmigoto loader! \nThis should fix loading issues, but will add a small delay to when 3dmigoto is loaded upon launching the game. \nYou can now launch with 3dmigoto again.",
|
||||
"migoto": "For importing models from GameBanana"
|
||||
"migoto": "For importing models from GameBanana",
|
||||
"grasscutter_elevation_help_text": "The method used to allow Grasscutter to bind port 443 (which is not allowed for regular users on Linux)\nAvailable methods:\n Capability - grant the Java Virtual Machine the capability to bind ports below 1024. This also allows all other programs running on that JVM to bind these ports.\n Root - run GC as root. This also allows the GC server, its plugins and the JVM to do pretty much anything, including sending your nudes to the NSA, CIA, and the alphabet boys.\n None - for no method. This requires you to change the GC Dispatch port."
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
|
@ -34,7 +34,8 @@
|
||||
"auto_mongodb": "Automatycznie uruchamiaj MongoDB",
|
||||
"un_elevated": "Uruchamiaj grę bez uprawnień administratora/roota",
|
||||
"redirect_more": "Przekieruj też inne gry MHY",
|
||||
"check_aagl": "Więcej opcji znajdziesz w drugim launcherze"
|
||||
"check_aagl": "Więcej opcji znajdziesz w drugim launcherze",
|
||||
"grasscutter_elevation": "Sposób uruchomienia GC na ograniczonym porcie"
|
||||
},
|
||||
"downloads": {
|
||||
"grasscutter_fullbuild": "Pobierz Grasscutter (wszystko w jednym)",
|
||||
@ -86,7 +87,8 @@
|
||||
"use_proxy": "Używaj wewnętrznego proxy Cultivation. To powinno być włączone, chyba że używasz czegoś jak np. Fiddler",
|
||||
"patch_rsa": "Patchuj i odpatchuj RSA gry automatycznie. Jeżeli nie grasz w starą lub nieoficjalną wersję (3.0 lub starszą), to powinno być włączone.",
|
||||
"add_delay": "Ustaw opóźnienie 3dmigoto loadera! \nTo powinno naprawić problemy z ładowaniem, ale doda małe opóźnienie do czasu ładowania 3dmigoto do gry. \nTeraz możecie uruchamiać grę z 3dmigoto.",
|
||||
"migoto": "Do importowania modeli z GameBanana"
|
||||
"migoto": "Do importowania modeli z GameBanana",
|
||||
"grasscutter_elevation_help_text": "Metoda używana przez Grasscuttera do zbindowania portu 443 (co nie jest dozwolone dla zywkłych użytkowników w Linuxie)\nDostępne metody:\n Capability - daje wirtualnej maszynie Javy możliwość zbindowania portów poniżej 1024. To też pozwala wszystkim innym programom odpalonym na tej maszynie JVM zbindować te porty.\n Root - uruchamia GC jako root. To pozwala serwerowi GC, jego pluginom i maszynie JVM zrobić praktycznie wszystko, wliczając w to wysyłanie twoich nudesów do ABW, CBŚ, i innych trzyliterowych służb.\n None - czyli żadna metoda. Ta opcja wymaga zmiana portu Dispatch serwera GC."
|
||||
},
|
||||
"swag": {
|
||||
"akebi_name": "Akebi",
|
||||
|
@ -214,6 +214,7 @@ fn main() -> Result<(), ArgsError> {
|
||||
system_helpers::service_status,
|
||||
system_helpers::stop_service,
|
||||
system_helpers::run_jar,
|
||||
system_helpers::run_jar_root,
|
||||
system_helpers::open_in_browser,
|
||||
system_helpers::install_location,
|
||||
system_helpers::is_elevated,
|
||||
@ -222,6 +223,8 @@ fn main() -> Result<(), ArgsError> {
|
||||
system_helpers::wipe_registry,
|
||||
system_helpers::get_platform,
|
||||
system_helpers::run_un_elevated,
|
||||
system_helpers::jvm_add_cap,
|
||||
system_helpers::jvm_remove_cap,
|
||||
patch::patch_game,
|
||||
patch::unpatch_game,
|
||||
proxy::set_proxy_addr,
|
||||
|
@ -30,6 +30,56 @@ fn guess_user_terminal() -> String {
|
||||
"xterm".to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn rawstrcmd(cmd: &Command) -> String {
|
||||
format!("{:?}", cmd)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn strcmd(cmd: &Command) -> String {
|
||||
format!("bash -c {:?}", rawstrcmd(cmd))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub trait AsRoot {
|
||||
fn as_root(&self) -> Self;
|
||||
fn as_root_gui(&self) -> Self;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl AsRoot for Command {
|
||||
fn as_root(&self) -> Self {
|
||||
let mut cmd = Command::new("sudo");
|
||||
cmd.arg("--").arg("bash").arg("-c").arg(rawstrcmd(self));
|
||||
cmd
|
||||
}
|
||||
fn as_root_gui(&self) -> Self {
|
||||
let mut cmd = Command::new("pkexec");
|
||||
cmd.arg("bash").arg("-c").arg(rawstrcmd(self));
|
||||
cmd
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
trait InTerminalEmulator {
|
||||
fn in_terminal(&self) -> Self;
|
||||
fn in_terminal_noclose(&self) -> Self;
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
impl InTerminalEmulator for Command {
|
||||
fn in_terminal(&self) -> Self {
|
||||
let mut cmd = Command::new(guess_user_terminal());
|
||||
cmd.arg("-e").arg(strcmd(self));
|
||||
cmd
|
||||
}
|
||||
fn in_terminal_noclose(&self) -> Self {
|
||||
let mut cmd = Command::new(guess_user_terminal());
|
||||
cmd.arg("--noclose");
|
||||
cmd.arg("-e").arg(strcmd(self));
|
||||
cmd
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub trait SpawnItsFineReally {
|
||||
fn spawn_its_fine_really(&mut self, msg: &str) -> anyhow::Result<()>;
|
||||
@ -159,6 +209,38 @@ pub fn run_jar(path: String, execute_in: String, java_path: String) {
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[tauri::command]
|
||||
pub fn run_jar_root(path: String, execute_in: String, java_path: String) {
|
||||
panic!("Not implemented");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub fn run_jar_root(path: String, execute_in: String, java_path: String) {
|
||||
let mut command = if java_path.is_empty() {
|
||||
Command::new("java")
|
||||
} else {
|
||||
Command::new(java_path)
|
||||
};
|
||||
command.arg("-jar").arg(&path).current_dir(&execute_in);
|
||||
|
||||
println!("Launching .jar with command: {}", strcmd(&command));
|
||||
|
||||
// Open the program from the specified path.
|
||||
thread::spawn(move || {
|
||||
match command.as_root_gui().in_terminal().spawn() {
|
||||
Ok(mut handler) => {
|
||||
// Prevent creation of zombie processes
|
||||
handler
|
||||
.wait()
|
||||
.expect("Grasscutter exited with non-zero exit code");
|
||||
}
|
||||
Err(e) => println!("Failed to open jar ({} from {}): {}", &path, &execute_in, e),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[tauri::command]
|
||||
pub fn run_un_elevated(path: String, args: Option<String>) {
|
||||
@ -476,3 +558,55 @@ pub fn is_elevated() -> bool {
|
||||
pub fn get_platform() -> &'static str {
|
||||
std::env::consts::OS
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[tauri::command]
|
||||
pub async fn jvm_add_cap(_java_path: String) -> bool {
|
||||
panic!("Not implemented");
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[tauri::command]
|
||||
pub async fn jvm_remove_cap(_java_path: String) -> bool {
|
||||
panic!("Not implemented");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub async fn jvm_add_cap(java_path: String) -> bool {
|
||||
let mut java_bin = if java_path.is_empty() {
|
||||
which::which("java").expect("Java is not installed")
|
||||
} else {
|
||||
PathBuf::from(&java_path)
|
||||
};
|
||||
while java_bin.is_symlink() {
|
||||
java_bin = java_bin.read_link().unwrap()
|
||||
}
|
||||
println!("Removing cap on {:?}", &java_bin);
|
||||
Command::new("setcap")
|
||||
.arg("CAP_NET_BIND_SERVICE=+eip")
|
||||
.arg(java_bin)
|
||||
.as_root_gui()
|
||||
.spawn_its_fine_really(&format!("Failed to add cap to {}", java_path))
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tauri::command]
|
||||
pub async fn jvm_remove_cap(java_path: String) -> bool {
|
||||
let mut java_bin = if java_path.is_empty() {
|
||||
which::which("java").expect("Java is not installed")
|
||||
} else {
|
||||
PathBuf::from(&java_path)
|
||||
};
|
||||
while java_bin.is_symlink() {
|
||||
java_bin = java_bin.read_link().unwrap()
|
||||
}
|
||||
println!("Setting cap on {:?}", &java_bin);
|
||||
Command::new("setcap")
|
||||
.arg("-r")
|
||||
.arg(java_bin)
|
||||
.as_root_gui()
|
||||
.spawn_its_fine_really(&format!("Failed to remove cap from {}", java_path))
|
||||
.is_ok()
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import React from 'react'
|
||||
import TopBar from './components/TopBar'
|
||||
import ServerLaunchSection from './components/ServerLaunchSection'
|
||||
import MainProgressBar from './components/common/MainProgressBar'
|
||||
import Options from './components/menu/Options'
|
||||
import Options, { GrasscutterElevation } from './components/menu/Options'
|
||||
import MiniDialog from './components/MiniDialog'
|
||||
import DownloadList from './components/common/DownloadList'
|
||||
import Downloads from './components/menu/Downloads'
|
||||
@ -15,7 +15,7 @@ import { ExtrasMenu } from './components/menu/ExtrasMenu'
|
||||
import Notification from './components/common/Notification'
|
||||
import GamePathNotify from './components/menu/GamePathNotify'
|
||||
|
||||
import { getConfigOption, setConfigOption } from '../utils/configuration'
|
||||
import { getConfig, getConfigOption, setConfigOption } from '../utils/configuration'
|
||||
import { invoke } from '@tauri-apps/api'
|
||||
import { getVersion } from '@tauri-apps/api/app'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
@ -102,10 +102,28 @@ export class Main extends React.Component<IProps, IState> {
|
||||
// Emitted for automatic processes
|
||||
listen('grasscutter_closed', async () => {
|
||||
const autoService = await getConfigOption('auto_mongodb')
|
||||
const config = await getConfig()
|
||||
|
||||
if (autoService) {
|
||||
await invoke('stop_service', { service: 'MongoDB' })
|
||||
}
|
||||
|
||||
if ((await invoke('get_platform')) === 'linux') {
|
||||
switch (config.grasscutter_elevation) {
|
||||
case GrasscutterElevation.None:
|
||||
break
|
||||
|
||||
case GrasscutterElevation.Capability:
|
||||
await invoke('jvm_remove_cap', {
|
||||
javaPath: config.java_path,
|
||||
})
|
||||
break
|
||||
|
||||
default:
|
||||
console.error('Invalid grasscutter_elevation')
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let min = false
|
||||
|
@ -12,6 +12,7 @@ import Plus from '../../resources/icons/plus.svg'
|
||||
|
||||
import './ServerLaunchSection.css'
|
||||
import { dataDir } from '@tauri-apps/api/path'
|
||||
import { GrasscutterElevation } from './menu/Options'
|
||||
import { getGameExecutable, getGameVersion, getGrasscutterJar } from '../../utils/game'
|
||||
import { patchGame, unpatchGame } from '../../utils/rsa'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
@ -210,11 +211,12 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
|
||||
if (!config.grasscutter_path) return alert('Grasscutter not installed or set!')
|
||||
|
||||
const grasscutter_jar = await getGrasscutterJar()
|
||||
await invoke('enable_grasscutter_watcher', {
|
||||
process: proc_name || grasscutter_jar,
|
||||
})
|
||||
|
||||
if (config.auto_mongodb) {
|
||||
const grasscutter_jar = await getGrasscutterJar()
|
||||
await invoke('enable_grasscutter_watcher', {
|
||||
process: proc_name || grasscutter_jar,
|
||||
})
|
||||
// Check if MongoDB is running and start it if not
|
||||
invoke('service_status', { service: 'MongoDB' })
|
||||
}
|
||||
@ -227,8 +229,31 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
|
||||
jarFolder = jarFolder.substring(0, config.grasscutter_path.lastIndexOf('\\'))
|
||||
}
|
||||
|
||||
let cmd = 'run_jar'
|
||||
|
||||
if ((await invoke('get_platform')) === 'linux') {
|
||||
switch (config.grasscutter_elevation) {
|
||||
case GrasscutterElevation.None:
|
||||
break
|
||||
|
||||
case GrasscutterElevation.Capability:
|
||||
await invoke('jvm_add_cap', {
|
||||
javaPath: config.java_path,
|
||||
})
|
||||
break
|
||||
|
||||
case GrasscutterElevation.Root:
|
||||
cmd = 'run_jar_root'
|
||||
break
|
||||
|
||||
default:
|
||||
console.error('Invalid grasscutter_elevation')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Launch the jar
|
||||
await invoke('run_jar', {
|
||||
await invoke(cmd, {
|
||||
path: config.grasscutter_path,
|
||||
executeIn: jarFolder,
|
||||
javaPath: config.java_path || '',
|
||||
|
@ -17,6 +17,12 @@ import * as meta from '../../../utils/rsa'
|
||||
import HelpButton from '../common/HelpButton'
|
||||
import SmallButton from '../common/SmallButton'
|
||||
|
||||
export enum GrasscutterElevation {
|
||||
None = 'None',
|
||||
Capability = 'Capability',
|
||||
Root = 'Root',
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
closeFn: () => void
|
||||
downloadManager: DownloadHandler
|
||||
@ -44,6 +50,9 @@ interface IState {
|
||||
un_elevated: boolean
|
||||
redirect_more: boolean
|
||||
|
||||
// Linux stuff
|
||||
grasscutter_elevation: string
|
||||
|
||||
// Swag stuff
|
||||
akebi_path: string
|
||||
migoto_path: string
|
||||
@ -76,6 +85,9 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
un_elevated: false,
|
||||
redirect_more: false,
|
||||
|
||||
// Linux stuff
|
||||
grasscutter_elevation: GrasscutterElevation.None,
|
||||
|
||||
// Swag stuff
|
||||
akebi_path: '',
|
||||
migoto_path: '',
|
||||
@ -132,6 +144,9 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
un_elevated: config.un_elevated || false,
|
||||
redirect_more: config.redirect_more || false,
|
||||
|
||||
// Linux stuff
|
||||
grasscutter_elevation: config.grasscutter_elevation || GrasscutterElevation.None,
|
||||
|
||||
// Swag stuff
|
||||
akebi_path: config.akebi_path || '',
|
||||
migoto_path: config.migoto_path || '',
|
||||
@ -297,6 +312,14 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
})
|
||||
}
|
||||
|
||||
async setGCElevation(value: string) {
|
||||
setConfigOption('grasscutter_elevation', value)
|
||||
|
||||
this.setState({
|
||||
grasscutter_elevation: value,
|
||||
})
|
||||
}
|
||||
|
||||
async removeRSA() {
|
||||
await meta.unpatchGame()
|
||||
}
|
||||
@ -437,6 +460,25 @@ export default class Options extends React.Component<IProps, IState> {
|
||||
{this.state.platform === 'linux' && (
|
||||
<>
|
||||
<Divider />
|
||||
<div className="OptionSection" id="menuOptionsContainerGCElevation">
|
||||
<div className="OptionLabel" id="menuOptionsLabelGCElevation">
|
||||
<Tr text="options.grasscutter_elevation" />
|
||||
<HelpButton contents="help.grasscutter_elevation_help_text" />
|
||||
</div>
|
||||
<select
|
||||
value={this.state.grasscutter_elevation}
|
||||
id="menuOptionsSelectGCElevation"
|
||||
onChange={(event) => {
|
||||
this.setGCElevation(event.target.value)
|
||||
}}
|
||||
>
|
||||
{Object.keys(GrasscutterElevation).map((t) => (
|
||||
<option key={t} value={t}>
|
||||
{t}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="OptionSection" id="menuOptionsContainerCheckAAGL">
|
||||
<div className="OptionLabel" id="menuOptionsLabelCheckAAGL">
|
||||
<Tr text="options.check_aagl" />
|
||||
|
@ -28,6 +28,9 @@ let defaultConfig: Configuration
|
||||
auto_mongodb: false,
|
||||
un_elevated: false,
|
||||
redirect_more: false,
|
||||
|
||||
// Linux stuff
|
||||
grasscutter_elevation: 'None',
|
||||
}
|
||||
})()
|
||||
|
||||
@ -60,6 +63,9 @@ export interface Configuration {
|
||||
un_elevated: boolean
|
||||
redirect_more: boolean
|
||||
|
||||
// Linux stuff
|
||||
grasscutter_elevation: string
|
||||
|
||||
// Swag stuff
|
||||
akebi_path?: string
|
||||
migoto_path?: string
|
||||
|
Loading…
Reference in New Issue
Block a user