forked from akanyan/STARTLINER
feat: display module for chunithm
Also make the progress bar all shiny
This commit is contained in:
@ -66,7 +66,7 @@ impl Game {
|
||||
pub fn has_module(&self, module: ProfileModule) -> bool {
|
||||
match self {
|
||||
Game::Ongeki => make_bitflags!(ProfileModule::{Segatools | Display | Network | BepInEx | Mu3Ini | Keyboard}),
|
||||
Game::Chunithm => make_bitflags!(ProfileModule::{Segatools | Network | Keyboard}),
|
||||
Game::Chunithm => make_bitflags!(ProfileModule::{Segatools | Display | Network | Keyboard | Mempatcher}),
|
||||
}.contains(module)
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ pub struct NormalPatchField {
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
pub struct NumberPatch {
|
||||
pub offset: u64,
|
||||
pub default: i32,
|
||||
pub size: i64,
|
||||
pub min: i32,
|
||||
pub max: i32
|
||||
@ -77,6 +78,7 @@ impl Serialize for Patch {
|
||||
PatchData::Number(patch) => {
|
||||
state.serialize_field("type", "number")?;
|
||||
state.serialize_field("offset", &patch.offset)?;
|
||||
state.serialize_field("default", &patch.default)?;
|
||||
state.serialize_field("size", &patch.size)?;
|
||||
state.serialize_field("min", &patch.min)?;
|
||||
state.serialize_field("max", &patch.max)?;
|
||||
@ -95,6 +97,10 @@ impl<'de> serde::Deserialize<'de> for Patch {
|
||||
offset: value.get("offset")
|
||||
.and_then(Value::as_u64)
|
||||
.ok_or_else(|| de::Error::missing_field("offset"))?,
|
||||
default: i32::try_from(value.get("default")
|
||||
.and_then(Value::as_i64)
|
||||
.ok_or_else(|| de::Error::missing_field("default"))?
|
||||
).map_err(|_| de::Error::missing_field("default"))?,
|
||||
size: value.get("size")
|
||||
.and_then(Value::as_i64)
|
||||
.ok_or_else(|| de::Error::missing_field("size"))?,
|
||||
|
@ -74,7 +74,7 @@ pub struct Display {
|
||||
pub target: String,
|
||||
pub rez: (i32, i32),
|
||||
pub mode: DisplayMode,
|
||||
pub rotation: i32,
|
||||
pub rotation: Option<i32>,
|
||||
pub frequency: i32,
|
||||
pub borderless_fullscreen: bool,
|
||||
|
||||
@ -94,7 +94,7 @@ impl Display {
|
||||
Game::Ongeki => (1080, 1920),
|
||||
},
|
||||
mode: DisplayMode::Borderless,
|
||||
rotation: 0,
|
||||
rotation: None,
|
||||
frequency: match game {
|
||||
Game::Chunithm => 120,
|
||||
Game::Ongeki => 60,
|
||||
@ -232,7 +232,7 @@ pub enum Keyboard {
|
||||
}
|
||||
|
||||
#[bitflags]
|
||||
#[repr(u8)]
|
||||
#[repr(u16)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ProfileModule {
|
||||
Segatools,
|
||||
@ -241,4 +241,5 @@ pub enum ProfileModule {
|
||||
BepInEx,
|
||||
Mu3Ini,
|
||||
Keyboard,
|
||||
Mempatcher
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
use crate::model::profile::{Display, DisplayMode};
|
||||
use crate::{model::{misc::Game, profile::{Display, DisplayMode}}, util::bool_to_01};
|
||||
use anyhow::Result;
|
||||
use displayz::{query_displays, DisplaySet};
|
||||
use ini::Ini;
|
||||
use tauri::{AppHandle, Listener};
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -30,7 +31,7 @@ impl Display {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn line_up(&self) -> Result<Option<DisplayInfo>> {
|
||||
pub fn prepare(&self) -> Result<Option<DisplayInfo>> {
|
||||
use anyhow::anyhow;
|
||||
use displayz::{query_displays, Orientation, Resolution, Frequency};
|
||||
|
||||
@ -63,11 +64,23 @@ impl Display {
|
||||
set: Some(display_set.clone()),
|
||||
};
|
||||
|
||||
if self.rotation == 90 || self.rotation == 270 {
|
||||
if let Some(rotation) = self.rotation {
|
||||
let rez = settings.borrow_mut().resolution;
|
||||
settings.borrow_mut().orientation = if self.rotation == 90 { Orientation::PortraitFlipped } else { Orientation::Portrait };
|
||||
settings.borrow_mut().orientation = match rotation {
|
||||
0 => Orientation::Landscape,
|
||||
90 => Orientation::PortraitFlipped,
|
||||
180 => Orientation::LandscapeFlipped,
|
||||
270 => Orientation::Portrait,
|
||||
_ => panic!("Invalid display rotation")
|
||||
};
|
||||
if rez.height < rez.width {
|
||||
settings.borrow_mut().resolution = Resolution::new(rez.height, rez.width);
|
||||
if rotation == 90 || rotation == 270 {
|
||||
settings.borrow_mut().resolution = Resolution::new(rez.height, rez.width);
|
||||
}
|
||||
} else {
|
||||
if rotation == 0 || rotation == 180 {
|
||||
settings.borrow_mut().resolution = Resolution::new(rez.height, rez.width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,6 +112,20 @@ impl Display {
|
||||
Ok(Some(res))
|
||||
}
|
||||
|
||||
pub fn line_up(&self, game: Game, ini: &mut Ini) {
|
||||
if game == Game::Chunithm {
|
||||
let autism = self.monitor_index_override.unwrap_or(0).to_string();
|
||||
ini.with_section(Some("gfx"))
|
||||
.set("enable", "1")
|
||||
.set("windowed", bool_to_01(self.mode != DisplayMode::Fullscreen))
|
||||
.set("framed", bool_to_01(self.mode == DisplayMode::Window))
|
||||
.set("monitor", if self.dont_switch_primary { &autism } else { "0" });
|
||||
ini.with_section(Some("system"))
|
||||
.set("dipsw2", bool_to_01(self.frequency == 60))
|
||||
.set("dipsw3", bool_to_01(self.frequency == 60));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clean_up(info: &DisplayInfo) -> Result<()> {
|
||||
use anyhow::anyhow;
|
||||
|
||||
|
0
rust/src/modules/mempatcher.rs
Normal file
0
rust/src/modules/mempatcher.rs
Normal file
@ -4,6 +4,7 @@ pub mod network;
|
||||
pub mod bepinex;
|
||||
pub mod mu3ini;
|
||||
pub mod keyboard;
|
||||
pub mod mempatcher;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub mod display_windows;
|
@ -72,7 +72,7 @@ impl Profile {
|
||||
mods: BTreeSet::new(),
|
||||
sgt: Segatools::default_for(meta.game),
|
||||
#[cfg(target_os = "windows")]
|
||||
display: if meta.game == Game::Ongeki { Some(Display::default_for(meta.game)) } else { None },
|
||||
display: Some(Display::default_for(meta.game)),
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
display: None,
|
||||
network: Network::default(),
|
||||
@ -120,6 +120,9 @@ impl Profile {
|
||||
if data.patches.is_none() {
|
||||
data.patches = Some(PatchSelection(BTreeMap::new()));
|
||||
}
|
||||
if data.display.is_none() {
|
||||
data.display = Some(Display::default_for(Game::Chunithm));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Profile {
|
||||
@ -205,7 +208,7 @@ impl Profile {
|
||||
pub async fn line_up(&self, pkg_hash: String, refresh: bool, _app: AppHandle) -> Result<()> {
|
||||
let info = match &self.data.display {
|
||||
None => None,
|
||||
Some(display) => display.line_up()?
|
||||
Some(display) => display.prepare()?
|
||||
};
|
||||
|
||||
let res = self.line_up_the_rest(pkg_hash, refresh).await;
|
||||
@ -238,6 +241,10 @@ impl Profile {
|
||||
.map_err(|e| anyhow!("segatools configuration failed:\n{:?}", e))?;
|
||||
self.data.network.line_up(&mut ini)?;
|
||||
|
||||
if let Some(display) = &self.data.display {
|
||||
display.line_up(self.meta.game, &mut ini);
|
||||
}
|
||||
|
||||
if let Some(keyboard) = &self.data.keyboard {
|
||||
keyboard.line_up(&mut ini)?;
|
||||
}
|
||||
@ -305,24 +312,30 @@ impl Profile {
|
||||
"INOHARA_CONFIG_PATH",
|
||||
self.config_dir().join("inohara.cfg"),
|
||||
)
|
||||
.env(
|
||||
"SAEKAWA_CONFIG_PATH",
|
||||
self.config_dir().join("saekawa.toml"),
|
||||
)
|
||||
.current_dir(&exe_dir)
|
||||
.args(["-d", "-k"])
|
||||
.arg(sgt_dir.join(self.meta.game.hook_exe()))
|
||||
.arg(self.meta.game.exe());
|
||||
|
||||
if let Some(display) = &self.data.display {
|
||||
if display.dont_switch_primary && display.target != "default" {
|
||||
game_builder.args(["-monitor", &display.monitor_index_override.unwrap_or_else(|| 1).to_string()]);
|
||||
} else {
|
||||
game_builder.args(["-monitor", "1"]);
|
||||
}
|
||||
game_builder.args([
|
||||
"-screen-width", &display.rez.0.to_string(),
|
||||
"-screen-height", &display.rez.1.to_string(),
|
||||
"-screen-fullscreen", if display.mode == DisplayMode::Fullscreen { "1" } else { "0" }
|
||||
]);
|
||||
if display.mode == DisplayMode::Borderless {
|
||||
game_builder.arg("-popupwindow");
|
||||
if self.meta.game.has_module(ProfileModule::BepInEx) {
|
||||
if let Some(display) = &self.data.display {
|
||||
if display.dont_switch_primary && display.target != "default" {
|
||||
game_builder.args(["-monitor", &display.monitor_index_override.unwrap_or_else(|| 1).to_string()]);
|
||||
} else {
|
||||
game_builder.args(["-monitor", "1"]);
|
||||
}
|
||||
game_builder.args([
|
||||
"-screen-width", &display.rez.0.to_string(),
|
||||
"-screen-height", &display.rez.1.to_string(),
|
||||
"-screen-fullscreen", if display.mode == DisplayMode::Fullscreen { "1" } else { "0" }
|
||||
]);
|
||||
if display.mode == DisplayMode::Borderless {
|
||||
game_builder.arg("-popupwindow");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,4 +150,8 @@ impl PathStr for PathBuf {
|
||||
fn stringify(&self) -> Result<String> {
|
||||
path_to_str(&self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bool_to_01(val: bool) -> &'static str {
|
||||
return if val { "1" } else { "0" }
|
||||
}
|
@ -15,26 +15,11 @@ freeplay=0
|
||||
; LAN Install: If multiple machines are present on the same LAN then set
|
||||
; this to 1 on exactly one machine and set this to 0 on all others.
|
||||
dipsw1=1
|
||||
; Monitor type: 0 = 120FPS, 1 = 60FPS
|
||||
dipsw2=1
|
||||
; Cab type: 0 = SP, 1 = CVT. SP will enable VFD and eMoney. This setting will switch
|
||||
; the LED 837-15093-06 COM port and the AiMe reder hardware generation as well.
|
||||
dipsw3=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hooks settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[gfx]
|
||||
; Enables the graphics hook.
|
||||
enable=1
|
||||
; Force the game to run windowed.
|
||||
windowed=1
|
||||
; Add a frame to the game window if running windowed.
|
||||
framed=0
|
||||
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
||||
monitor=0
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
Reference in New Issue
Block a user