forked from akanyan/STARTLINER
fix: restore wine configuration
This commit is contained in:
@ -18,7 +18,7 @@ bun run tauri build
|
||||
Once a profile is set up, it is possible to bypass the GUI:
|
||||
|
||||
```sh
|
||||
startliner --start --game ongeki --name profile-name
|
||||
startliner --start --game ongeki --profile <name>
|
||||
```
|
||||
|
||||
### Package format
|
||||
|
@ -13,6 +13,8 @@
|
||||
"deep-link:default",
|
||||
"fs:default",
|
||||
"fs:allow-data-read-recursive",
|
||||
"fs:allow-data-write-recursive"
|
||||
"fs:allow-data-write-recursive",
|
||||
"fs:allow-config-read-recursive",
|
||||
"fs:allow-config-write-recursive"
|
||||
]
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ pub async fn run(_args: Vec<String>) {
|
||||
if let Ok(matches) = app.cli().matches() {
|
||||
let start_arg = matches.args.get("start").expect("Invalid argument configuration");
|
||||
let game_arg = matches.args.get("game").expect("Invalid argument configuration");
|
||||
let name_arg = matches.args.get("name").expect("Invalid argument configuration");
|
||||
let name_arg = matches.args.get("profile").expect("Invalid argument configuration");
|
||||
log::debug!("{:?} {:?} {:?}", start_arg, game_arg, name_arg);
|
||||
if start_arg.occurrences > 0 {
|
||||
start_immediately = true;
|
||||
|
@ -11,6 +11,19 @@ pub struct Segatools {
|
||||
pub intel: bool,
|
||||
}
|
||||
|
||||
impl Default for Segatools {
|
||||
fn default() -> Self {
|
||||
Segatools {
|
||||
target: PathBuf::default(),
|
||||
amfs: PathBuf::default(),
|
||||
option: PathBuf::default(),
|
||||
appdata: PathBuf::from("appdata"),
|
||||
enable_aime: false,
|
||||
intel: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Default, PartialEq)]
|
||||
pub enum DisplayMode {
|
||||
Window,
|
||||
@ -28,6 +41,19 @@ pub struct Display {
|
||||
pub borderless_fullscreen: bool,
|
||||
}
|
||||
|
||||
impl Default for Display {
|
||||
fn default() -> Self {
|
||||
Display {
|
||||
target: "default".to_owned(),
|
||||
rez: (1080, 1920),
|
||||
mode: DisplayMode::Borderless,
|
||||
rotation: 0,
|
||||
frequency: 60,
|
||||
borderless_fullscreen: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Default, PartialEq)]
|
||||
pub enum NetworkType {
|
||||
#[default] Remote,
|
||||
@ -38,7 +64,7 @@ pub enum NetworkType {
|
||||
pub struct Network {
|
||||
pub network_type: NetworkType,
|
||||
|
||||
pub local_path: String,
|
||||
pub local_path: PathBuf,
|
||||
pub local_console: bool,
|
||||
|
||||
pub remote_address: String,
|
||||
@ -50,5 +76,22 @@ pub struct Network {
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Default)]
|
||||
pub struct BepInEx {
|
||||
pub console: bool
|
||||
pub console: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub struct Wine {
|
||||
pub runtime: PathBuf,
|
||||
pub prefix: PathBuf,
|
||||
}
|
||||
|
||||
impl Default for Wine {
|
||||
fn default() -> Self {
|
||||
Wine {
|
||||
runtime: PathBuf::from("/usr/bin/wine"),
|
||||
prefix: std::env::var("HOME")
|
||||
.and_then(|home| Ok(PathBuf::from(home).join(".wine")))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@ use anyhow::Result;
|
||||
use displayz::{query_displays, DisplaySet};
|
||||
use tauri::{AppHandle, Listener};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[derive(Clone)]
|
||||
pub struct DisplayInfo {
|
||||
pub primary: String,
|
||||
@ -20,20 +19,6 @@ impl Default for DisplayInfo {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Display {
|
||||
fn default() -> Self {
|
||||
Display {
|
||||
target: "default".to_owned(),
|
||||
rez: (1080, 1920),
|
||||
mode: DisplayMode::Borderless,
|
||||
rotation: 0,
|
||||
frequency: 60,
|
||||
borderless_fullscreen: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
impl Display {
|
||||
pub fn activate(&self, app: AppHandle) {
|
||||
let display = self.clone();
|
@ -1,5 +1,7 @@
|
||||
pub mod display;
|
||||
pub mod package;
|
||||
pub mod segatools;
|
||||
pub mod network;
|
||||
pub mod bepinex;
|
||||
pub mod bepinex;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub mod display_windows;
|
@ -27,7 +27,7 @@ impl Network {
|
||||
if self.network_type == NetworkType::Artemis {
|
||||
let network_path = PathBuf::from(&self.local_path);
|
||||
let artemis_dir = network_path.parent()
|
||||
.ok_or_else(|| anyhow!("Invalid ARTEMiS path {}", &self.local_path))?;
|
||||
.ok_or_else(|| anyhow!("Invalid ARTEMiS path {:?}", &self.local_path))?;
|
||||
let cfg_path = artemis_dir.join("config").join("core.yaml");
|
||||
|
||||
let cfg = std::fs::read_to_string(&cfg_path)
|
||||
@ -41,15 +41,22 @@ impl Network {
|
||||
if let Some(hostname) = hostname {
|
||||
ini.with_section(Some("dns")).set("default", hostname);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
let mut cmd = Command::new("cmd.exe");
|
||||
|
||||
cmd.arg("/C");
|
||||
let mut cmd: Command;
|
||||
|
||||
if self.local_console == true {
|
||||
cmd.arg("start");
|
||||
if cfg!(target_os = "windows") {
|
||||
cmd = Command::new("cmd.exe");
|
||||
cmd.arg("/C");
|
||||
|
||||
if self.local_console == true {
|
||||
cmd.arg("start");
|
||||
}
|
||||
} else {
|
||||
cmd = Command::new("sh");
|
||||
}
|
||||
cmd.args(["python", &self.local_path]);
|
||||
|
||||
cmd.arg("python");
|
||||
cmd.arg(&self.local_path);
|
||||
cmd.current_dir(artemis_dir);
|
||||
cmd.spawn()
|
||||
.map_err(|e| anyhow!("Unable to spawn artemis: {}", e))?;
|
||||
|
@ -1,23 +1,7 @@
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use ini::Ini;
|
||||
use crate::{model::{config::Segatools, segatools_base::segatools_base}, profiles::ProfilePaths, util::{self, PathStr}};
|
||||
|
||||
impl Default for Segatools {
|
||||
fn default() -> Self {
|
||||
Segatools {
|
||||
target: PathBuf::default(),
|
||||
amfs: PathBuf::default(),
|
||||
option: PathBuf::default(),
|
||||
appdata: PathBuf::from("appdata"),
|
||||
enable_aime: false,
|
||||
intel: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Segatools {
|
||||
pub async fn line_up(&self, p: &impl ProfilePaths) -> Result<Ini> {
|
||||
log::debug!("begin line-up: segatools");
|
||||
|
@ -70,7 +70,7 @@ impl AnyProfile {
|
||||
Self::OngekiProfile(p) => &mut p.mods
|
||||
}
|
||||
}
|
||||
pub async fn line_up(&self, app: AppHandle, pkg_hash: String) -> Result<()> {
|
||||
pub async fn line_up(&self, _app: AppHandle, pkg_hash: String) -> Result<()> {
|
||||
match self {
|
||||
Self::OngekiProfile(p) => {
|
||||
if !p.data_dir().exists() {
|
||||
@ -80,7 +80,8 @@ impl AnyProfile {
|
||||
let hash_path = p.data_dir().join(".sl-state");
|
||||
let meta = self.meta();
|
||||
|
||||
p.display.activate(app.clone());
|
||||
#[cfg(target_os = "windows")]
|
||||
p.display.activate(_app.clone());
|
||||
|
||||
util::clean_up_opts(p.data_dir().join("option"))?;
|
||||
|
||||
|
@ -4,7 +4,6 @@ use tauri::Emitter;
|
||||
use std::{collections::BTreeSet, path::PathBuf, process::Stdio};
|
||||
use crate::model::config::BepInEx;
|
||||
use crate::profiles::fixed_name;
|
||||
use crate::util::PathStr;
|
||||
use crate::{model::{config::{Display, DisplayMode, Network, Segatools}, misc::Game, segatools_base::segatools_base}, pkg::PkgKey, util};
|
||||
use super::{Profile, ProfileMeta, ProfilePaths};
|
||||
use anyhow::{anyhow, Result};
|
||||
@ -23,7 +22,10 @@ pub struct OngekiProfile {
|
||||
pub sgt: Segatools,
|
||||
pub display: Display,
|
||||
pub network: Network,
|
||||
pub bepinex: BepInEx
|
||||
pub bepinex: BepInEx,
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub wine: crate::model::config::Wine,
|
||||
}
|
||||
|
||||
impl Profile for OngekiProfile {
|
||||
@ -36,7 +38,9 @@ impl Profile for OngekiProfile {
|
||||
sgt: Segatools::default(),
|
||||
display: Display::default(),
|
||||
network: Network::default(),
|
||||
bepinex: BepInEx::default()
|
||||
bepinex: BepInEx::default(),
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
wine: crate::model::config::Wine::default(),
|
||||
};
|
||||
p.save()?;
|
||||
std::fs::write(p.config_dir().join("segatools-base.ini"), segatools_base())?;
|
||||
@ -92,11 +96,8 @@ impl Profile for OngekiProfile {
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let wine = p.data.wine_runtime.clone()
|
||||
.unwrap_or_else(|| std::path::PathBuf::from("/usr/bin/wine"));
|
||||
|
||||
game_builder = Command::new(&wine);
|
||||
amd_builder = Command::new(&wine);
|
||||
game_builder = Command::new(&self.wine.runtime);
|
||||
amd_builder = Command::new(&self.wine.runtime);
|
||||
|
||||
game_builder.arg(exe_dir.join("inject.exe"));
|
||||
amd_builder.arg("cmd.exe");
|
||||
@ -107,9 +108,10 @@ impl Profile for OngekiProfile {
|
||||
&ini_path,
|
||||
)
|
||||
.current_dir(&exe_dir)
|
||||
.arg("/C")
|
||||
.arg(&exe_dir.join("inject.exe"))
|
||||
.args([
|
||||
"/C",
|
||||
&exe_dir.join("inject.exe").stringify()?, "-d", "-k", "mu3hook.dll",
|
||||
"-d", "-k", "mu3hook.dll",
|
||||
"amdaemon.exe", "-f", "-c", "config_common.json", "config_server.json", "config_client.json"
|
||||
]);
|
||||
game_builder
|
||||
@ -136,17 +138,10 @@ impl Profile for OngekiProfile {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let wineprefix = p.data.wine_prefix.clone().unwrap_or_else(||
|
||||
directories::UserDirs::new()
|
||||
.expect("No home directory")
|
||||
.home_dir()
|
||||
.join(".wine")
|
||||
);
|
||||
amd_builder.env("WINEPREFIX", &wineprefix);
|
||||
game_builder.env("WINEPREFIX", &wineprefix);
|
||||
amd_builder.env("WINEPREFIX", &self.wine.prefix);
|
||||
game_builder.env("WINEPREFIX", &self.wine.prefix);
|
||||
}
|
||||
|
||||
|
||||
let amd_log = File::create(self.data_dir().join("amdaemon.log"))?;
|
||||
let game_log = File::create(self.data_dir().join("mu3.log"))?;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::{AppHandle, Manager};
|
||||
use tokio::process::Command;
|
||||
use std::{path::{Path, PathBuf}, sync::OnceLock};
|
||||
|
||||
use crate::model::misc::Game;
|
||||
@ -86,7 +87,7 @@ pub fn copy_directory(src: impl AsRef<Path>, dst: impl AsRef<Path>, recursive: b
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub async fn symlink(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> {
|
||||
fs::symlink(src, dst).await
|
||||
tokio::fs::symlink(src, dst).await
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
@ -100,8 +101,6 @@ pub static CREATE_NO_WINDOW: u32 = 0x08000000;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub async fn pkill(process_name: &str) {
|
||||
use tokio::process::Command;
|
||||
|
||||
_ = Command::new("taskkill.exe").arg("/f").arg("/im").arg(process_name)
|
||||
.creation_flags(CREATE_NO_WINDOW).output().await;
|
||||
}
|
||||
@ -120,7 +119,10 @@ pub fn clean_up_opts(dir: impl AsRef<Path>) -> Result<()> {
|
||||
let path = entry.path();
|
||||
log::debug!("{:?}", path);
|
||||
if path.is_symlink() {
|
||||
#[cfg(target_os = "windows")]
|
||||
std::fs::remove_dir(path)?;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
std::fs::remove_file(path)?;
|
||||
} else {
|
||||
log::error!("Not a symlink: {:?}", path);
|
||||
}
|
||||
|
@ -34,8 +34,8 @@
|
||||
"possibleValues": ["chunithm", "ongeki"]
|
||||
},
|
||||
{
|
||||
"short": "n",
|
||||
"name": "name",
|
||||
"short": "p",
|
||||
"name": "profile",
|
||||
"takesValue": true,
|
||||
"description": "Profile name"
|
||||
}
|
||||
|
@ -181,7 +181,11 @@ const extraDisplayOptionsDisabled = computed(() => {
|
||||
:disabled="extraDisplayOptionsDisabled"
|
||||
/>
|
||||
</OptionRow>
|
||||
<OptionRow class="number-input" title="Refresh Rate">
|
||||
<OptionRow
|
||||
v-if="capabilities.includes('display')"
|
||||
class="number-input"
|
||||
title="Refresh Rate"
|
||||
>
|
||||
<InputNumber
|
||||
class="shrink"
|
||||
size="small"
|
||||
|
Reference in New Issue
Block a user