forked from akanyan/STARTLINER
feat: 0.12 update
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::pkg::{Status, PkgKey, PkgKeyVersion};
|
||||
use crate::pkg::{PkgKey, PkgKeyVersion};
|
||||
|
||||
use super::misc::Game;
|
||||
|
||||
@ -22,6 +22,5 @@ pub type PackageList = BTreeMap<PkgKey, PackageListEntry>;
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct PackageListEntry {
|
||||
pub version: String,
|
||||
pub status: Status,
|
||||
pub games: Vec<Game>,
|
||||
}
|
@ -166,11 +166,26 @@ pub enum Mu3Audio {
|
||||
Excl2Ch,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
#[serde(default)]
|
||||
pub struct Mu3Ini {
|
||||
pub audio: Option<Mu3Audio>,
|
||||
pub sample_rate: i32,
|
||||
pub blacklist: Option<(i32, i32)>,
|
||||
pub gp: i32,
|
||||
pub enable_bonus_tracks: bool,
|
||||
}
|
||||
|
||||
impl Default for Mu3Ini {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
audio: Some(Mu3Audio::Shared),
|
||||
sample_rate: 48_000,
|
||||
blacklist: Some((10000, 19999)),
|
||||
gp: 999,
|
||||
enable_bonus_tracks: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
|
@ -1,11 +1,11 @@
|
||||
use std::path::Path;
|
||||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Result};
|
||||
use ini::Ini;
|
||||
use crate::model::profile::{Mu3Audio, Mu3Ini};
|
||||
|
||||
impl Mu3Ini {
|
||||
pub fn line_up(&self, game_path: impl AsRef<Path>) -> Result<()> {
|
||||
let file = game_path.as_ref().join("mu3.ini");
|
||||
pub fn line_up(&self, data_dir: impl AsRef<Path>, cfg_dir: impl AsRef<Path>) -> Result<()> {
|
||||
let file = cfg_dir.as_ref().join("mu3.ini");
|
||||
|
||||
if !file.exists() {
|
||||
std::fs::write(&file, "")?;
|
||||
@ -20,9 +20,26 @@ impl Mu3Ini {
|
||||
Mu3Audio::Excl2Ch => "2",
|
||||
};
|
||||
|
||||
ini.with_section(Some("Sound")).set("WasapiExclusive", value);
|
||||
ini.with_section(Some("Sound"))
|
||||
.set("WasapiExclusive", value)
|
||||
.set("SampleRate", self.sample_rate.to_string());
|
||||
}
|
||||
|
||||
if let Some(blacklist) = self.blacklist {
|
||||
ini.with_section(Some("Extra"))
|
||||
.set("BlacklistMin", blacklist.0.to_string())
|
||||
.set("BlacklistMax", blacklist.1.to_string());
|
||||
}
|
||||
|
||||
let cache_path = data_dir.as_ref().join("mu3-mods-cache");
|
||||
let cache_path = cache_path.to_str()
|
||||
.ok_or_else(|| anyhow!("Invalid cache path"))?;
|
||||
|
||||
ini.with_section(Some("Extra"))
|
||||
.set("GP", self.gp.to_string())
|
||||
.set("CacheDir", cache_path)
|
||||
.set("UnlockBonusTracks", crate::util::bool_to_01(self.enable_bonus_tracks));
|
||||
|
||||
ini.write_to_file(file)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -15,10 +15,14 @@ impl PatchFileVec {
|
||||
let mut res = Vec::new();
|
||||
for f in std::fs::read_dir(path)? {
|
||||
let f = f?;
|
||||
let f = f.path();
|
||||
res.push(
|
||||
serde_json5::from_str::<PatchFile>(&std::fs::read_to_string(f)?)?
|
||||
);
|
||||
let f = &f.path();
|
||||
match serde_json5::from_str::<PatchFile>(&std::fs::read_to_string(f)?) {
|
||||
Ok(parsed) => res.push(parsed),
|
||||
Err(e) => {
|
||||
log::error!("Error parsing {f:?}: {e}");
|
||||
anyhow::bail!("Error parsing {f:?}: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(PatchFileVec(res))
|
||||
}
|
||||
@ -29,8 +33,8 @@ impl PatchFileVec {
|
||||
let mut res = Vec::new();
|
||||
for pfile in &self.0 {
|
||||
for plist in &pfile.0 {
|
||||
log::debug!("checking {}", plist.sha256);
|
||||
if plist.sha256 == checksum {
|
||||
log::debug!("checking {}", plist.sha256.to_ascii_lowercase());
|
||||
if plist.sha256.to_ascii_lowercase() == checksum {
|
||||
let mut cloned = plist.clone().patches;
|
||||
res.append(&mut cloned);
|
||||
}
|
||||
|
@ -152,7 +152,6 @@ impl PackageStore {
|
||||
PackageListEntry {
|
||||
// from_rainy() is guaranteed to include rmt
|
||||
version: r.rmt.as_ref().unwrap().version.clone(),
|
||||
status: Status::Unchecked,
|
||||
games: vec![ game ],
|
||||
}
|
||||
});
|
||||
|
@ -28,7 +28,7 @@ impl Profile {
|
||||
bepinex: if meta.game == Game::Ongeki { Some(BepInEx::default()) } else { None },
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
wine: crate::model::profile::Wine::default(),
|
||||
mu3_ini: if meta.game == Game::Ongeki { Some(Mu3Ini { audio: None, blacklist: None }) } else { None },
|
||||
mu3_ini: if meta.game == Game::Ongeki { Some(Mu3Ini::default()) } else { None },
|
||||
keyboard:
|
||||
if meta.game == Game::Ongeki {
|
||||
Some(Keyboard::Ongeki(OngekiKeyboard::default()))
|
||||
@ -43,6 +43,12 @@ impl Profile {
|
||||
std::fs::create_dir_all(p.config_dir())?;
|
||||
std::fs::create_dir_all(p.data_dir())?;
|
||||
|
||||
if meta.game == Game::Ongeki {
|
||||
if let Err(e) = Self::load_existing_mu3_ini(&p.data, &p.meta) {
|
||||
log::error!("unable to load existing mu3.ini: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
match meta.game {
|
||||
Game::Ongeki => std::fs::write(p.config_dir().join("segatools-base.ini"), include_bytes!("../../static/segatools-ongeki.ini"))?,
|
||||
Game::Chunithm => std::fs::write(p.config_dir().join("segatools-base.ini"), include_bytes!("../../static/segatools-chunithm.ini"))?,
|
||||
@ -67,6 +73,18 @@ impl Profile {
|
||||
data.sgt.io2 = IOSelection::Custom(io);
|
||||
data.sgt.io = None;
|
||||
}
|
||||
if let Some(ini) = &mut data.mu3_ini {
|
||||
if ini.audio.is_none() {
|
||||
ini.audio = Some(crate::model::profile::Mu3Audio::Shared);
|
||||
}
|
||||
if ini.blacklist.is_none() {
|
||||
ini.blacklist = Some((10000, 19999));
|
||||
}
|
||||
} else {
|
||||
data.mu3_ini = Some(Mu3Ini::default());
|
||||
}
|
||||
|
||||
Self::load_existing_mu3_ini(&data, &ProfileMeta { game, name: name.clone() })?;
|
||||
}
|
||||
if game == Game::Chunithm {
|
||||
if data.keyboard.is_none() {
|
||||
@ -203,7 +221,7 @@ impl Profile {
|
||||
}
|
||||
|
||||
if let Some(mu3ini) = &self.data.mu3_ini {
|
||||
mu3ini.line_up(&self.data.sgt.target.parent().unwrap())?;
|
||||
mu3ini.line_up(&self.data_dir(), &self.config_dir())?;
|
||||
}
|
||||
|
||||
if let Some(patches) = &self.data.patches {
|
||||
@ -283,6 +301,14 @@ impl Profile {
|
||||
"ONGEKI_LANG_PATH",
|
||||
self.data_dir().join("lang"),
|
||||
)
|
||||
.env(
|
||||
"MU3_MODS_CONFIG_PATH",
|
||||
self.config_dir().join("mu3.ini"),
|
||||
)
|
||||
.env(
|
||||
"STARTLINER",
|
||||
"1"
|
||||
)
|
||||
.current_dir(&exe_dir)
|
||||
.raw_arg("-d")
|
||||
.raw_arg("-k")
|
||||
@ -403,6 +429,17 @@ impl Profile {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn load_existing_mu3_ini(data: &ProfileData, meta: &ProfileMeta) -> Result<()> {
|
||||
let mu3_ini_target_path = data.sgt.target.parent().ok_or_else(|| anyhow!("invalid target directory"))?.join("mu3.ini");
|
||||
let mu3_ini_profile_path = util::profile_config_dir(meta.game, &meta.name).join("mu3.ini");
|
||||
log::debug!("mu3.ini paths: {:?} {:?}", mu3_ini_target_path, mu3_ini_profile_path);
|
||||
if mu3_ini_target_path.exists() && !mu3_ini_profile_path.exists() {
|
||||
std::fs::copy(&mu3_ini_target_path, &mu3_ini_profile_path)?;
|
||||
log::info!("copied mu3.ini from {:?}", &mu3_ini_target_path);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ProfilePaths for Profile {
|
||||
|
@ -199,7 +199,7 @@ pub fn create_shortcut(
|
||||
obj.SetDescription(&format!("{} – {} (STARTLINER)", &meta.game.print(), &meta.name))?;
|
||||
obj.SetArguments(&format!("--start --game {} --profile {}", &meta.game, &meta.name))?;
|
||||
obj.SetIconLocation(
|
||||
target_dir.join(format!("icon-{}.ico", &meta.game)).to_str().ok_or_else(|| anyhow!("Illegal icon path"))?,
|
||||
target_dir.join(format!("icon-{}.ico", &meta.game)).to_str().ok_or_else(|| anyhow!("Illegal icon path"))?,
|
||||
0
|
||||
)?;
|
||||
|
||||
|
Reference in New Issue
Block a user