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