feat: display module for chunithm

Also make the progress bar all shiny
This commit is contained in:
2025-04-12 17:33:39 +00:00
parent 7db36b7bc0
commit 6270fce05f
17 changed files with 188 additions and 83 deletions

View File

@ -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)
}
}

View File

@ -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"))?,

View File

@ -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
}

View File

@ -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;

View File

View 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;

View File

@ -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");
}
}
}

View File

@ -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" }
}

View File

@ -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
; -----------------------------------------------------------------------------