1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2025-02-16 06:00:31 +00:00

Move button config to menu

This commit is contained in:
jugeeya 2023-08-08 10:40:44 -07:00 committed by GitHub
parent cd7255fc2c
commit 7a7e7bdc52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 239 additions and 272 deletions

View file

@ -1,83 +1,43 @@
use std::fs;
use crate::common::menu::P1_CONTROLLER_STATE;
use crate::consts::TRAINING_MODPACK_TOML_PATH;
use crate::common::*;
use crate::input::{ControllerStyle::*, *};
use log::info;
use serde::Deserialize;
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
use toml;
const BUTTON_MAPPINGS: [&str; 12] = [
"A",
"B",
"X",
"Y",
"L",
"R",
"ZL",
"ZR",
"DPAD_UP",
"DPAD_DOWN",
"DPAD_LEFT",
"DPAD_RIGHT",
];
fn button_mapping(name: &str, style: ControllerStyle, b: ButtonBitfield) -> bool {
match name {
"A" => b.a(),
"B" => b.b(),
"X" => b.x(),
"Y" => b.y(),
"L" => match style {
fn button_mapping(button_config: ButtonConfig, style: ControllerStyle, b: ButtonBitfield) -> bool {
match button_config {
ButtonConfig::A => b.a(),
ButtonConfig::B => b.b(),
ButtonConfig::X => b.x(),
ButtonConfig::Y => b.y(),
ButtonConfig::L => match style {
GCController => false,
_ => b.l(),
},
"R" => match style {
ButtonConfig::R => match style {
GCController => b.zr(),
_ => b.r(),
},
"ZL" => match style {
ButtonConfig::ZL => match style {
GCController => b.l() || b.real_digital_l(),
_ => b.zl(),
},
"ZR" => match style {
ButtonConfig::ZR => match style {
GCController => b.r() || b.real_digital_r(),
_ => b.zr(),
},
"DPAD_UP" => b.dpad_up(),
"DPAD_DOWN" => b.dpad_down(),
"DPAD_LEFT" => b.dpad_left(),
"DPAD_RIGHT" => b.dpad_right(),
_ => panic!("Invalid button name: {}", name),
ButtonConfig::DpadUp => b.dpad_up(),
ButtonConfig::DpadDown => b.dpad_down(),
ButtonConfig::DpadLeft => b.dpad_left(),
ButtonConfig::DpadRight => b.dpad_right(),
ButtonConfig::Plus => b.plus(),
ButtonConfig::Minus => b.minus(),
ButtonConfig::LStick => b.stick_l(),
ButtonConfig::RStick => b.stick_r(),
}
}
static mut BUTTON_COMBO_CONFIG: BtnComboConfig = BtnComboConfig {
open_menu: BtnList {
hold: vec![],
press: vec![],
},
save_state: BtnList {
hold: vec![],
press: vec![],
},
load_state: BtnList {
hold: vec![],
press: vec![],
},
input_record: BtnList {
hold: vec![],
press: vec![],
},
input_playback: BtnList {
hold: vec![],
press: vec![],
},
};
#[derive(Debug, EnumIter, PartialEq)]
pub enum ButtonCombo {
OpenMenu,
@ -87,149 +47,13 @@ pub enum ButtonCombo {
InputPlayback,
}
#[derive(Deserialize, Default)]
struct BtnList {
hold: Vec<String>,
press: Vec<String>,
}
#[derive(Deserialize, Default)]
struct BtnComboConfig {
open_menu: BtnList,
save_state: BtnList,
load_state: BtnList,
input_record: BtnList,
input_playback: BtnList,
}
#[derive(Deserialize)]
pub struct TopLevelBtnComboConfig {
button_config: BtnComboConfig,
}
pub fn load_from_file() {
let combo_path = TRAINING_MODPACK_TOML_PATH;
info!("Checking for previous button combo settings in {TRAINING_MODPACK_TOML_PATH}...");
let mut valid_button_config = false;
if fs::metadata(combo_path).is_ok() {
info!("Previous button combo settings found. Loading...");
let combo_conf = fs::read_to_string(combo_path)
.unwrap_or_else(|_| panic!("Could not read {}", combo_path));
let conf: Result<TopLevelBtnComboConfig, toml::de::Error> = toml::from_str(&combo_conf);
if let Ok(conf) = conf {
if validate_config(conf) {
save_all_btn_config_from_toml(&combo_conf);
valid_button_config = true;
}
}
}
if !valid_button_config {
info!("No previous button combo file found. Creating...");
fs::write(combo_path, DEFAULT_BTN_CONFIG).expect("Failed to write button config conf file");
save_all_btn_config_from_defaults();
}
}
fn save_all_btn_config_from_defaults() {
let conf = TopLevelBtnComboConfig {
button_config: BtnComboConfig {
open_menu: BtnList {
hold: vec!["B".to_string()],
press: vec!["DPAD_UP".to_string()],
},
save_state: BtnList {
hold: vec!["ZL".to_string()],
press: vec!["DPAD_DOWN".to_string()],
},
load_state: BtnList {
hold: vec!["ZL".to_string()],
press: vec!["DPAD_UP".to_string()],
},
input_record: BtnList {
hold: vec!["ZR".to_string()],
press: vec!["DPAD_LEFT".to_string()],
},
input_playback: BtnList {
hold: vec!["ZR".to_string()],
press: vec!["DPAD_RIGHT".to_string()],
},
},
};
unsafe {
// This println is necessary. Why?.......
println!("{:?}", &conf.button_config.load_state.press);
BUTTON_COMBO_CONFIG = conf.button_config;
}
}
fn save_all_btn_config_from_toml(data: &str) {
let conf: TopLevelBtnComboConfig = toml::from_str(data).expect("Could not parse button config");
unsafe {
// This println is necessary. Why?.......
println!("{:?}", &conf.button_config.load_state.press);
BUTTON_COMBO_CONFIG = conf.button_config;
}
}
fn validate_config(conf: TopLevelBtnComboConfig) -> bool {
let conf = conf.button_config;
let configs = [
conf.open_menu,
conf.save_state,
conf.load_state,
conf.input_record,
conf.input_playback,
];
let bad_keys = configs
.iter()
.flat_map(|btn_list| {
btn_list
.hold
.iter()
.chain(btn_list.press.iter())
.filter(|x| !BUTTON_MAPPINGS.contains(&x.to_uppercase().as_str()))
})
.collect::<Vec<&String>>();
if !bad_keys.is_empty() {
skyline::error::show_error(
0x71,
"Training Modpack custom button\nconfiguration is invalid!\0",
&format!(
"The following keys are invalid in\n{}:\n\
{:?}\n\nPossible Keys: {:#?}\0",
TRAINING_MODPACK_TOML_PATH, &bad_keys, BUTTON_MAPPINGS
),
);
false
} else {
true
}
}
unsafe fn get_combo_keys(combo: ButtonCombo) -> (&'static Vec<String>, &'static Vec<String>) {
unsafe fn get_combo_keys(combo: ButtonCombo) -> (ButtonConfig, ButtonConfig) {
match combo {
ButtonCombo::OpenMenu => (
&BUTTON_COMBO_CONFIG.open_menu.hold,
&BUTTON_COMBO_CONFIG.open_menu.press,
),
ButtonCombo::SaveState => (
&BUTTON_COMBO_CONFIG.save_state.hold,
&BUTTON_COMBO_CONFIG.save_state.press,
),
ButtonCombo::LoadState => (
&BUTTON_COMBO_CONFIG.load_state.hold,
&BUTTON_COMBO_CONFIG.load_state.press,
),
ButtonCombo::InputRecord => (
&BUTTON_COMBO_CONFIG.input_record.hold,
&BUTTON_COMBO_CONFIG.input_record.press,
),
ButtonCombo::InputPlayback => (
&BUTTON_COMBO_CONFIG.input_playback.hold,
&BUTTON_COMBO_CONFIG.input_playback.press,
),
ButtonCombo::OpenMenu => (MENU.menu_open_hold, MENU.menu_open_press),
ButtonCombo::SaveState => (MENU.save_state_save_hold, MENU.save_state_save_press),
ButtonCombo::LoadState => (MENU.save_state_load_hold, MENU.save_state_load_press),
ButtonCombo::InputRecord => (MENU.input_record_hold, MENU.input_record_press),
ButtonCombo::InputPlayback => (MENU.input_playback_hold, MENU.input_playback_press),
}
}
@ -237,21 +61,16 @@ fn combo_passes(combo: ButtonCombo) -> bool {
unsafe {
let (hold, press) = get_combo_keys(combo);
let p1_controller_state = *P1_CONTROLLER_STATE.data_ptr();
let this_combo_passes = hold.iter().all(|hold| {
button_mapping(
&hold.to_uppercase(),
p1_controller_state.style,
p1_controller_state.current_buttons,
)
}) && press.iter().all(|hold| {
button_mapping(
&hold.to_uppercase(),
p1_controller_state.style,
p1_controller_state.just_down,
)
});
this_combo_passes
button_mapping(
hold,
p1_controller_state.style,
p1_controller_state.current_buttons,
) && button_mapping(
press,
p1_controller_state.style,
p1_controller_state.just_down,
)
}
}
@ -261,44 +80,3 @@ pub fn combo_passes_exclusive(combo: ButtonCombo) -> bool {
.any(combo_passes);
combo_passes(combo) && !other_combo_passes
}
const DEFAULT_BTN_CONFIG: &str = r#"[button_config]
# Available Options:
#
# DPAD_UP
# DPAD_RIGHT
# DPAD_DOWN
# DPAD_LEFT
# A
# B
# X
# Y
# L
# R
# ZL
# ZR
#
# It is recommended to only put one button in the "press" section for each button
# combination, but you can add several buttons to "hold" like this:
# hold=["A", "B",]
#
[button_config.open_menu]
hold=["B",]
press=["DPAD_UP",]
[button_config.save_state]
hold=["ZL",]
press=["DPAD_DOWN",]
[button_config.load_state]
hold=["ZL",]
press=["DPAD_UP",]
[button_config.input_record]
hold=["ZR",]
press=["DPAD_LEFT",]
[button_config.input_playback]
hold=["ZR",]
press=["DPAD_RIGHT",]
"#;

View file

@ -74,21 +74,6 @@ pub fn main() {
unsafe {
EVENT_QUEUE.push(Event::smash_open());
notification("Training Modpack".to_string(), "Welcome!".to_string(), 60);
notification(
"Open Menu".to_string(),
"Special + Uptaunt".to_string(),
120,
);
notification(
"Save State".to_string(),
"Shield + Downtaunt".to_string(),
120,
);
notification(
"Load State".to_string(),
"Shield + Uptaunt".to_string(),
120,
);
}
hitbox_visualizer::hitbox_visualization();
@ -118,7 +103,55 @@ pub fn main() {
release::version_check();
menu::load_from_file();
button_config::load_from_file();
unsafe {
notification("Training Modpack".to_string(), "Welcome!".to_string(), 60);
notification(
"Open Menu".to_string(),
format!(
"{} + {}",
MENU.menu_open_hold.as_str(),
MENU.menu_open_press.as_str()
),
120,
);
notification(
"Save State".to_string(),
format!(
"{} + {}",
MENU.save_state_save_hold.as_str(),
MENU.save_state_save_press.as_str()
),
120,
);
notification(
"Load State".to_string(),
format!(
"{} + {}",
MENU.save_state_load_hold.as_str(),
MENU.save_state_load_press.as_str()
),
120,
);
notification(
"Input Record".to_string(),
format!(
"{} + {}",
MENU.input_record_hold.as_str(),
MENU.input_record_press.as_str()
),
120,
);
notification(
"Input Playback".to_string(),
format!(
"{} + {}",
MENU.input_playback_hold.as_str(),
MENU.input_playback_press.as_str()
),
120,
);
}
std::thread::spawn(events_loop);

View file

@ -80,6 +80,16 @@ pub struct TrainingModpackMenu {
pub hitstun_playback: HitstunPlayback,
pub playback_mash: OnOff,
pub playback_loop: OnOff,
pub menu_open_hold: ButtonConfig,
pub menu_open_press: ButtonConfig,
pub save_state_save_hold: ButtonConfig,
pub save_state_save_press: ButtonConfig,
pub save_state_load_hold: ButtonConfig,
pub save_state_load_press: ButtonConfig,
pub input_record_hold: ButtonConfig,
pub input_record_press: ButtonConfig,
pub input_playback_hold: ButtonConfig,
pub input_playback_press: ButtonConfig,
}
#[repr(C)]
@ -178,6 +188,16 @@ pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu {
hitstun_playback: HitstunPlayback::Hitstun,
playback_mash: OnOff::On,
playback_loop: OnOff::Off,
menu_open_hold: ButtonConfig::B,
menu_open_press: ButtonConfig::DpadUp,
save_state_save_hold: ButtonConfig::L,
save_state_save_press: ButtonConfig::DpadDown,
save_state_load_hold: ButtonConfig::L,
save_state_load_press: ButtonConfig::DpadUp,
input_record_hold: ButtonConfig::R,
input_record_press: ButtonConfig::DpadDown,
input_playback_hold: ButtonConfig::R,
input_playback_press: ButtonConfig::DpadUp,
};
pub static mut MENU: TrainingModpackMenu = DEFAULTS_MENU;
@ -806,5 +826,82 @@ pub unsafe fn ui_menu(menu: TrainingModpackMenu) -> UiMenu<'static> {
);
overall_menu.tabs.push(input_tab);
let mut button_tab = Tab {
tab_id: "button",
tab_title: "Button Config",
tab_submenus: Vec::new(),
};
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Menu Open: Hold",
"menu_open_hold",
"Menu Open: Hold: Which button to hold down before pressing Menu Open: Press",
true,
&(menu.menu_open_hold as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Menu Open: Press",
"menu_open_press",
"Menu Open: Press: Which button to press after holding Menu Open: Hold",
true,
&(menu.menu_open_press as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Save State Save: Hold",
"save_state_save_hold",
"Save State Save: Hold: Which button to hold down before pressing Save State Save: Press",
true,
&(menu.save_state_save_hold as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Save State Save: Press",
"save_state_save_press",
"Save State Save: Press: Which button to press after holding Save State Save: Hold",
true,
&(menu.save_state_save_press as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Save State Load: Hold",
"save_state_load_hold",
"Save State Load: Hold: Which button to hold down before pressing Save State Load: Press",
true,
&(menu.save_state_load_hold as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Save State Load: Press",
"save_state_load_press",
"Save State Load: Press: Which button to press after holding Save State Load: Hold",
true,
&(menu.save_state_load_press as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Input Record: Hold",
"input_record_hold",
"Input Record: Hold: Which button to hold down before pressing Input Record: Press",
true,
&(menu.input_record_hold as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Input Record: Press",
"input_record_press",
"Input Record: Press: Which button to press after holding Input Record: Hold",
true,
&(menu.input_record_hold as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Input Playback: Hold",
"input_playback_hold",
"Input Playback: Hold: Which button to hold down before pressing Input Playback: Press",
true,
&(menu.input_playback_hold as u32),
);
button_tab.add_submenu_with_toggles::<ButtonConfig>(
"Input Playback: Press",
"input_playback_press",
"Input Playback: Press: Which button to press after holding Input Playback: Hold",
true,
&(menu.input_playback_press as u32),
);
overall_menu.tabs.push(button_tab);
overall_menu
}

View file

@ -1441,3 +1441,62 @@ impl ToggleTrait for RecordingFrames {
RecordingFrames::iter().map(|i| i as u32).collect()
}
}
#[repr(u32)]
#[derive(
Debug, Clone, Copy, PartialEq, FromPrimitive, EnumIter, Serialize_repr, Deserialize_repr,
)]
pub enum ButtonConfig {
A = 0b0000_0000_0000_0000_0001,
B = 0b0000_0000_0000_0000_0010,
X = 0b0000_0000_0000_0000_0100,
Y = 0b0000_0000_0000_0000_1000,
L = 0b0000_0000_0000_0001_0000,
R = 0b0000_0000_0000_0010_0000,
ZL = 0b0000_0000_0000_0100_0000,
ZR = 0b0000_0000_0000_1000_0000,
DpadUp = 0b0000_0000_0001_0000_0000,
DpadDown = 0b0000_0000_0010_0000_0000,
DpadLeft = 0b0000_0000_0100_0000_0000,
DpadRight = 0b0000_0000_1000_0000_0000,
Plus = 0b0000_0001_0000_0000_0000,
Minus = 0b0000_0010_0000_0000_0000,
LStick = 0b0000_0100_0000_0000_0000,
RStick = 0b0000_1000_0000_0000_0000,
}
impl ButtonConfig {
// Should we use the font glyphs? Or do that special casing in the menu?
pub fn as_str(self) -> &'static str {
match self {
ButtonConfig::A => "A",
ButtonConfig::B => "B",
ButtonConfig::X => "X",
ButtonConfig::Y => "Y",
ButtonConfig::L => "L",
ButtonConfig::R => "R",
ButtonConfig::ZL => "ZL",
ButtonConfig::ZR => "ZR",
ButtonConfig::DpadUp => "DPad Up",
ButtonConfig::DpadDown => "DPad Down",
ButtonConfig::DpadLeft => "DPad Left",
ButtonConfig::DpadRight => "DPad Right",
ButtonConfig::Plus => "Plus",
ButtonConfig::Minus => "Minus",
ButtonConfig::LStick => "Left Stick Press",
ButtonConfig::RStick => "Right Stick Press",
}
}
}
impl ToggleTrait for ButtonConfig {
fn to_toggle_strs() -> Vec<&'static str> {
ButtonConfig::iter()
.map(|i| i.as_str())
.collect()
}
fn to_toggle_vals() -> Vec<u32> {
ButtonConfig::iter().map(|i| i as u32).collect()
}
}