feat: audio mode
This commit is contained in:
@ -1,6 +1,9 @@
|
||||
use enumflags2::make_bitflags;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::pkg::PkgKey;
|
||||
|
||||
use super::profile::ProfileModule;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Copy)]
|
||||
pub enum Game {
|
||||
#[serde(rename = "ongeki")]
|
||||
@ -59,6 +62,13 @@ impl Game {
|
||||
Game::Chunithm => vec!["-c", "config_common.json", "config_server.json", "config_client.json", "config_cvt.json", "config_sp.json", "config_hook.json"]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_module(&self, module: ProfileModule) -> bool {
|
||||
match self {
|
||||
Game::Ongeki => make_bitflags!(ProfileModule::{Segatools | Display | Network | BepInEx | Mu3Ini}),
|
||||
Game::Chunithm => make_bitflags!(ProfileModule::{Segatools | Network}),
|
||||
}.contains(module)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Game {
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::path::PathBuf;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::pkg::PkgKey;
|
||||
use enumflags2::bitflags;
|
||||
|
||||
use super::misc::Game;
|
||||
|
||||
@ -136,3 +137,30 @@ impl Default for Wine {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, PartialEq, Debug, Copy)]
|
||||
pub enum Mu3Audio {
|
||||
Shared,
|
||||
Excl6Ch,
|
||||
Excl2Ch,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
pub struct Mu3Ini {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub audio: Option<Mu3Audio>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub blacklist: Option<(i32, i32)>,
|
||||
}
|
||||
|
||||
#[bitflags]
|
||||
#[repr(u8)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ProfileModule {
|
||||
Segatools,
|
||||
Network,
|
||||
Display,
|
||||
BepInEx,
|
||||
Mu3Ini
|
||||
}
|
@ -2,6 +2,7 @@ pub mod package;
|
||||
pub mod segatools;
|
||||
pub mod network;
|
||||
pub mod bepinex;
|
||||
pub mod mu3ini;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub mod display_windows;
|
30
rust/src/modules/mu3ini.rs
Normal file
30
rust/src/modules/mu3ini.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use std::path::Path;
|
||||
use 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");
|
||||
|
||||
if !file.exists() {
|
||||
std::fs::write(&file, "")?;
|
||||
}
|
||||
|
||||
let mut ini = Ini::load_from_file(&file)?;
|
||||
|
||||
if let Some(audio) = self.audio {
|
||||
let value = match audio {
|
||||
Mu3Audio::Shared => "0",
|
||||
Mu3Audio::Excl6Ch => "1",
|
||||
Mu3Audio::Excl2Ch => "2",
|
||||
};
|
||||
|
||||
ini.with_section(Some("Sound")).set("WasapiExclusive", value);
|
||||
}
|
||||
|
||||
ini.write_to_file(file)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::AppHandle;
|
||||
use std::{collections::BTreeSet, path::{Path, PathBuf}};
|
||||
use crate::{model::{misc::Game, profile::Aime}, modules::package::prepare_packages, pkg::PkgKey, pkg_store::PackageStore, util};
|
||||
use crate::{model::{misc::Game, profile::{Aime, Mu3Ini, ProfileModule}}, modules::package::prepare_packages, pkg::PkgKey, pkg_store::PackageStore, util};
|
||||
use tauri::Emitter;
|
||||
use std::process::Stdio;
|
||||
use crate::model::profile::BepInEx;
|
||||
@ -42,14 +42,19 @@ pub struct Profile {
|
||||
pub struct ProfileData {
|
||||
pub mods: BTreeSet<PkgKey>,
|
||||
pub sgt: Segatools,
|
||||
pub display: Option<Display>,
|
||||
pub network: Network,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub display: Option<Display>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub bepinex: Option<BepInEx>,
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub wine: crate::model::profile::Wine,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mu3_ini: Option<Mu3Ini>
|
||||
}
|
||||
|
||||
impl Profile {
|
||||
@ -68,6 +73,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 },
|
||||
},
|
||||
meta: meta.clone()
|
||||
};
|
||||
@ -138,18 +144,25 @@ impl Profile {
|
||||
self.data.sgt.fix(store);
|
||||
}
|
||||
pub fn sync(&mut self, source: ProfileData) {
|
||||
if self.data.bepinex.is_some() {
|
||||
if self.meta.game.has_module(ProfileModule::BepInEx) && source.bepinex.is_some() {
|
||||
self.data.bepinex = source.bepinex;
|
||||
}
|
||||
if self.data.display.is_some() {
|
||||
|
||||
if self.meta.game.has_module(ProfileModule::Display) && source.display.is_some() {
|
||||
self.data.display = source.display;
|
||||
}
|
||||
// if self.data.network.is_some() {
|
||||
|
||||
if self.meta.game.has_module(ProfileModule::Network) {
|
||||
self.data.network = source.network;
|
||||
// }
|
||||
// if self.data.sgt.is_some() {
|
||||
}
|
||||
|
||||
if self.meta.game.has_module(ProfileModule::Segatools) {
|
||||
self.data.sgt = source.sgt;
|
||||
// }
|
||||
}
|
||||
|
||||
if self.meta.game.has_module(ProfileModule::Mu3Ini) && source.mu3_ini.is_some() {
|
||||
self.data.mu3_ini = source.mu3_ini;
|
||||
}
|
||||
}
|
||||
pub async fn line_up(&self, pkg_hash: String, refresh: bool, _app: AppHandle) -> Result<()> {
|
||||
let info = match &self.data.display {
|
||||
@ -194,6 +207,10 @@ impl Profile {
|
||||
bepinex.line_up(&self.meta)?;
|
||||
}
|
||||
|
||||
if let Some(mu3ini) = &self.data.mu3_ini {
|
||||
mu3ini.line_up(&self.data.sgt.target.parent().unwrap())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import SelectButton from 'primevue/selectbutton';
|
||||
import ToggleSwitch from 'primevue/toggleswitch';
|
||||
import FileEditor from './FileEditor.vue';
|
||||
import OptionCategory from './OptionCategory.vue';
|
||||
@ -12,6 +14,54 @@ import { usePrfStore } from '../stores';
|
||||
|
||||
const prf = usePrfStore();
|
||||
|
||||
const audioModel = computed({
|
||||
get() {
|
||||
return prf.current?.data.mu3_ini?.audio ?? null;
|
||||
},
|
||||
set(value: 'Shared' | 'Excl6Ch' | 'Excl2Ch') {
|
||||
if (prf.current!.data.mu3_ini === undefined) {
|
||||
prf.current!.data.mu3_ini = {};
|
||||
}
|
||||
prf.current!.data.mu3_ini!.audio = value;
|
||||
},
|
||||
});
|
||||
|
||||
// const blacklistMinModel = computed({
|
||||
// get() {
|
||||
// if (prf.current?.data.mu3_ini?.blacklist === undefined) {
|
||||
// return null;
|
||||
// }
|
||||
// return prf.current?.data.mu3_ini?.blacklist[0];
|
||||
// },
|
||||
// set(value: number) {
|
||||
// if (prf.current!.data.mu3_ini === undefined) {
|
||||
// prf.current!.data.mu3_ini = {};
|
||||
// }
|
||||
// prf.current!.data.mu3_ini!.blacklist = [
|
||||
// value,
|
||||
// prf.current!.data.mu3_ini!.blacklist?.[1] ?? 19999,
|
||||
// ];
|
||||
// },
|
||||
// });
|
||||
|
||||
// const blacklistMaxModel = computed({
|
||||
// get() {
|
||||
// if (prf.current?.data.mu3_ini?.blacklist === undefined) {
|
||||
// return null;
|
||||
// }
|
||||
// return prf.current?.data.mu3_ini?.blacklist[1];
|
||||
// },
|
||||
// set(value: number) {
|
||||
// if (prf.current!.data.mu3_ini === undefined) {
|
||||
// prf.current!.data.mu3_ini = {};
|
||||
// }
|
||||
// prf.current!.data.mu3_ini!.blacklist = [
|
||||
// prf.current!.data.mu3_ini!.blacklist?.[0] ?? 10000,
|
||||
// value,
|
||||
// ];
|
||||
// },
|
||||
// });
|
||||
|
||||
prf.reload();
|
||||
</script>
|
||||
|
||||
@ -36,6 +86,47 @@ prf.reload();
|
||||
<!-- @vue-expect-error -->
|
||||
<ToggleSwitch v-model="prf.current!.data.bepinex.console" />
|
||||
</OptionRow>
|
||||
|
||||
<OptionRow
|
||||
title="Audio mode"
|
||||
tooltip="Exclusive 2-channel mode requires a patch"
|
||||
>
|
||||
<SelectButton
|
||||
v-model="audioModel"
|
||||
:options="[
|
||||
{ title: 'Shared', value: 'Shared' },
|
||||
{ title: 'Exclusive 6-channel', value: 'Excl6Ch' },
|
||||
{ title: 'Exclusive 2-channel', value: 'Excl2Ch' },
|
||||
]"
|
||||
:allow-empty="true"
|
||||
option-label="title"
|
||||
option-value="value"
|
||||
/></OptionRow>
|
||||
|
||||
<!-- <OptionRow
|
||||
class="number-input"
|
||||
title="Song ID Blacklist"
|
||||
tooltip="Requires a patch"
|
||||
><InputNumber
|
||||
class="shrink"
|
||||
size="small"
|
||||
:min="10000"
|
||||
:max="99999"
|
||||
placeholder="10000"
|
||||
:use-grouping="false"
|
||||
:allow-empty="false"
|
||||
v-model="blacklistMinModel" />
|
||||
x
|
||||
<InputNumber
|
||||
class="shrink"
|
||||
size="small"
|
||||
:min="10000"
|
||||
:max="99999"
|
||||
placeholder="19999"
|
||||
:use-grouping="false"
|
||||
:allow-empty="false"
|
||||
v-model="blacklistMaxModel"
|
||||
/></OptionRow> -->
|
||||
</OptionCategory>
|
||||
</template>
|
||||
|
||||
|
@ -19,6 +19,7 @@ const prf = usePrfStore();
|
||||
icon="pi pi-plus"
|
||||
class="chunithm-button profile-button"
|
||||
@click="() => prf.create('chunithm')"
|
||||
v-tooltip="'!!! Experimental !!!'"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-12 flex flex-col flex-wrap align-middle gap-4">
|
||||
|
@ -31,6 +31,15 @@ const aimeCodeModel = computed({
|
||||
},
|
||||
});
|
||||
|
||||
const aimeCodePaste = (ev: ClipboardEvent) => {
|
||||
aimeCodeModel.value =
|
||||
ev.clipboardData
|
||||
?.getData('text/plain')
|
||||
.split('')
|
||||
.filter((c) => c >= '0' && c <= '9')
|
||||
.join('') ?? '';
|
||||
};
|
||||
|
||||
(async () => {
|
||||
const aime_path = await path.join(await prf.configDir, 'aime.txt');
|
||||
aimeCode.value = await readTextFile(aime_path).catch(() => '');
|
||||
@ -67,6 +76,7 @@ const aimeCodeModel = computed({
|
||||
:maxlength="20"
|
||||
placeholder="00000000000000000000"
|
||||
v-model="aimeCodeModel"
|
||||
@paste="aimeCodePaste"
|
||||
/>
|
||||
</OptionRow>
|
||||
<div v-if="prf.current!.data.sgt.aime?.hasOwnProperty('AMNet')">
|
||||
|
@ -52,6 +52,7 @@ export interface ProfileData {
|
||||
display: DisplayConfig;
|
||||
network: NetworkConfig;
|
||||
bepinex: BepInExConfig;
|
||||
mu3_ini: Mu3IniConfig | undefined;
|
||||
}
|
||||
|
||||
export interface SegatoolsConfig {
|
||||
@ -88,10 +89,16 @@ export interface NetworkConfig {
|
||||
subnet: string;
|
||||
suffix: number | null;
|
||||
}
|
||||
|
||||
export interface BepInExConfig {
|
||||
console: boolean;
|
||||
}
|
||||
|
||||
export interface Mu3IniConfig {
|
||||
audio?: 'Shared' | 'Excl6Ch' | 'Excl2Ch';
|
||||
// blacklist?: [number, number];
|
||||
}
|
||||
|
||||
export interface Profile {
|
||||
meta: ProfileMeta;
|
||||
data: ProfileData;
|
||||
|
Reference in New Issue
Block a user