mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2025-04-26 23:49:18 +00:00
Fix button config parsing
This commit is contained in:
parent
0b99a611e3
commit
2f032c1fc0
4 changed files with 76 additions and 88 deletions
src
|
@ -1,5 +1,7 @@
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
use smash::app::lua_bind::ControlModule;
|
||||||
|
use smash::lib::lua_const::*;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use toml;
|
use toml;
|
||||||
|
@ -19,21 +21,27 @@ lazy_static! {
|
||||||
("SHARESTOCK", 0xD), // *CONTROL_PAD_BUTTON_STOCK_SHARE
|
("SHARESTOCK", 0xD), // *CONTROL_PAD_BUTTON_STOCK_SHARE
|
||||||
("JUMPMINI", 0xA), // *CONTROL_PAD_BUTTON_JUMP_MINI
|
("JUMPMINI", 0xA), // *CONTROL_PAD_BUTTON_JUMP_MINI
|
||||||
]);
|
]);
|
||||||
pub static ref OPEN_MENU_BTN_HOLD: Mutex<Vec<i32>> = Mutex::new(vec![BUTTON_MAPPING["SPECIAL"]]);
|
}
|
||||||
pub static ref OPEN_MENU_BTN_PRESS: Mutex<Vec<i32>> = Mutex::new(vec![BUTTON_MAPPING["UPTAUNT"]]);
|
static mut BUTTON_COMBO_CONFIG: BtnComboConfig = BtnComboConfig{
|
||||||
pub static ref SAVE_STATE_BTN_HOLD: Mutex<Vec<i32>> = Mutex::new(vec![BUTTON_MAPPING["GRAB"]]);
|
open_menu: BtnList{ hold: vec![], press: vec![] },
|
||||||
pub static ref SAVE_STATE_BTN_PRESS: Mutex<Vec<i32>> = Mutex::new(vec![BUTTON_MAPPING["DOWNTAUNT"]]);
|
save_state: BtnList{ hold: vec![], press: vec![] },
|
||||||
pub static ref LOAD_STATE_BTN_HOLD: Mutex<Vec<i32>> = Mutex::new(vec![BUTTON_MAPPING["GRAB"]]);
|
load_state: BtnList{ hold: vec![], press: vec![] },
|
||||||
pub static ref LOAD_STATE_BTN_PRESS: Mutex<Vec<i32>> = Mutex::new(vec![BUTTON_MAPPING["UPTAUNT"]]);
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ButtonCombo {
|
||||||
|
OpenMenu,
|
||||||
|
SaveState,
|
||||||
|
LoadState
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize, Default)]
|
||||||
struct BtnList {
|
struct BtnList {
|
||||||
hold: Vec<String>,
|
hold: Vec<String>,
|
||||||
press: Vec<String>,
|
press: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize, Default)]
|
||||||
struct BtnComboConfig {
|
struct BtnComboConfig {
|
||||||
open_menu: BtnList,
|
open_menu: BtnList,
|
||||||
save_state: BtnList,
|
save_state: BtnList,
|
||||||
|
@ -45,67 +53,68 @@ struct TopLevelBtnComboConfig {
|
||||||
button_config: BtnComboConfig,
|
button_config: BtnComboConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_btn_config(btnlist: BtnList, mutex_hold: &Mutex<Vec<i32>>, mutex_press: &Mutex<Vec<i32>>) {
|
pub fn validate_config(data: &str) -> bool {
|
||||||
let bad_keys: Vec<&String> = btnlist
|
let conf: TopLevelBtnComboConfig = toml::from_str(data).unwrap();
|
||||||
.hold
|
let conf = conf.button_config;
|
||||||
.iter()
|
let configs = [conf.open_menu, conf.save_state, conf.load_state];
|
||||||
.chain(btnlist.press.iter())
|
let bad_keys = configs.iter().flat_map(|btn_list| {
|
||||||
.filter(|x| !BUTTON_MAPPING.contains_key(x.as_str()))
|
btn_list.hold.iter()
|
||||||
.collect();
|
.chain(btn_list.press.iter())
|
||||||
|
.filter(|x| !BUTTON_MAPPING.contains_key(x.to_uppercase().as_str()))
|
||||||
|
}).collect::<Vec<&String>>();
|
||||||
|
|
||||||
if !bad_keys.is_empty() {
|
if !bad_keys.is_empty() {
|
||||||
skyline::error::show_error(
|
skyline::error::show_error(
|
||||||
0x71,
|
0x71,
|
||||||
"Training Modpack custom button\nconfiguration is invalid!",
|
"Training Modpack custom button\nconfiguration is invalid!\0",
|
||||||
&format!("The following keys are invalid in\nsd:/TrainingModpack/training_modpack.toml:\n{:?}", &bad_keys)
|
&format!(
|
||||||
|
"The following keys are invalid in\nsd:/TrainingModpack/training_modpack.toml:\n\
|
||||||
|
{:?}\n\nPossible Keys: {:#?}\0", &bad_keys, BUTTON_MAPPING.keys())
|
||||||
);
|
);
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// HOLD
|
pub fn save_all_btn_config_from_defaults() {
|
||||||
let mut global_hold = mutex_hold.lock();
|
let conf = TopLevelBtnComboConfig {
|
||||||
let vecopt_hold: Vec<Option<&i32>> = btnlist
|
button_config: BtnComboConfig {
|
||||||
.hold
|
open_menu: BtnList { hold: vec!["SPECIAL".to_string()], press: vec!["UPTAUNT".to_string()] },
|
||||||
.iter()
|
save_state: BtnList { hold: vec!["GRAB".to_string()], press: vec!["DOWNTAUNT".to_string()] },
|
||||||
.map(|x| BUTTON_MAPPING.get(x.as_str()))
|
load_state: BtnList { hold: vec!["GRAB".to_string()], press: vec!["UPTAUNT".to_string()] },
|
||||||
.collect();
|
}
|
||||||
if vecopt_hold.iter().all(|x| x.is_some()) {
|
};
|
||||||
// All entries valid keys of BUTTON_MAPPING
|
unsafe {
|
||||||
global_hold.clear();
|
// This println is necessary. Why?.......
|
||||||
global_hold.extend_from_slice(
|
println!("{:?}", &conf.button_config.load_state.press);
|
||||||
&vecopt_hold
|
BUTTON_COMBO_CONFIG = conf.button_config;
|
||||||
.into_iter()
|
|
||||||
.map(|x| *x.unwrap())
|
|
||||||
.collect::<Vec<i32>>(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// PRESS
|
|
||||||
let mut global_press = mutex_press.lock();
|
|
||||||
let vecopt_press: Vec<Option<&i32>> = btnlist
|
|
||||||
.press
|
|
||||||
.into_iter()
|
|
||||||
.map(|x| BUTTON_MAPPING.get(x.as_str()))
|
|
||||||
.collect();
|
|
||||||
if vecopt_press.iter().all(|x| x.is_some()) {
|
|
||||||
// All entries valid keys of BUTTON_MAPPING
|
|
||||||
global_press.clear();
|
|
||||||
global_press.extend_from_slice(
|
|
||||||
&vecopt_press
|
|
||||||
.into_iter()
|
|
||||||
.map(|x| *x.unwrap())
|
|
||||||
.collect::<Vec<i32>>(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_all_btn_config_from_toml(data: &str) {
|
pub fn save_all_btn_config_from_toml(data: &str) {
|
||||||
let conf: TopLevelBtnComboConfig = toml::from_str(data).unwrap();
|
let conf: TopLevelBtnComboConfig = toml::from_str(data).unwrap();
|
||||||
let open_menu_conf: BtnList = conf.button_config.open_menu;
|
unsafe {
|
||||||
let save_state_conf: BtnList = conf.button_config.save_state;
|
// This println is necessary. Why?.......
|
||||||
let load_state_conf: BtnList = conf.button_config.load_state;
|
println!("{:?}", &conf.button_config.load_state.press);
|
||||||
|
BUTTON_COMBO_CONFIG = conf.button_config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
save_btn_config(open_menu_conf, &OPEN_MENU_BTN_HOLD, &OPEN_MENU_BTN_PRESS);
|
pub fn combo_passes(module_accessor: *mut smash::app::BattleObjectModuleAccessor, combo: ButtonCombo) -> bool{
|
||||||
save_btn_config(save_state_conf, &SAVE_STATE_BTN_HOLD, &SAVE_STATE_BTN_PRESS);
|
unsafe {
|
||||||
save_btn_config(load_state_conf, &LOAD_STATE_BTN_HOLD, &LOAD_STATE_BTN_PRESS);
|
let (hold, press) = 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),
|
||||||
|
};
|
||||||
|
hold.iter()
|
||||||
|
.map(|hold| *BUTTON_MAPPING.get(&*hold.to_uppercase()).unwrap())
|
||||||
|
.all(|hold| ControlModule::check_button_on(module_accessor, hold))
|
||||||
|
&& press.iter()
|
||||||
|
.map(|press| *BUTTON_MAPPING.get(&*press.to_uppercase()).unwrap())
|
||||||
|
.all(|press| ControlModule::check_button_trigger(module_accessor, press))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const DEFAULT_BTN_CONFIG: &'static str = r#"[button_config]
|
pub const DEFAULT_BTN_CONFIG: &'static str = r#"[button_config]
|
||||||
|
|
|
@ -36,15 +36,7 @@ pub unsafe fn menu_condition(module_accessor: &mut smash::app::BattleObjectModul
|
||||||
// Only check for button combination if the counter is 0 (not locked out)
|
// Only check for button combination if the counter is 0 (not locked out)
|
||||||
match frame_counter::get_frame_count(FRAME_COUNTER_INDEX) {
|
match frame_counter::get_frame_count(FRAME_COUNTER_INDEX) {
|
||||||
0 => {
|
0 => {
|
||||||
let open_menu_btn_hold = button_config::OPEN_MENU_BTN_HOLD.lock();
|
button_config::combo_passes(module_accessor, button_config::ButtonCombo::OpenMenu)
|
||||||
let open_menu_btn_press = button_config::OPEN_MENU_BTN_PRESS.lock();
|
|
||||||
let return_value: bool = open_menu_btn_hold
|
|
||||||
.iter()
|
|
||||||
.all(|btn| ControlModule::check_button_on(module_accessor, *btn))
|
|
||||||
&& open_menu_btn_press
|
|
||||||
.iter()
|
|
||||||
.all(|btn| ControlModule::check_button_trigger(module_accessor, *btn));
|
|
||||||
return_value
|
|
||||||
}
|
}
|
||||||
1..MENU_LOCKOUT_FRAMES => false,
|
1..MENU_LOCKOUT_FRAMES => false,
|
||||||
_ => {
|
_ => {
|
||||||
|
|
11
src/lib.rs
11
src/lib.rs
|
@ -107,13 +107,16 @@ pub fn main() {
|
||||||
if fs::metadata(combo_path).is_ok() {
|
if fs::metadata(combo_path).is_ok() {
|
||||||
log!("Previous button combo settings found. Loading...");
|
log!("Previous button combo settings found. Loading...");
|
||||||
let combo_conf = fs::read_to_string(&combo_path).unwrap();
|
let combo_conf = fs::read_to_string(&combo_path).unwrap();
|
||||||
button_config::save_all_btn_config_from_toml(&combo_conf);
|
if button_config::validate_config(&combo_conf) {
|
||||||
|
button_config::save_all_btn_config_from_toml(&combo_conf);
|
||||||
|
} else {
|
||||||
|
button_config::save_all_btn_config_from_defaults();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log!("No previous button combo file found. Creating...");
|
log!("No previous button combo file found. Creating...");
|
||||||
std::fs::write(combo_path, button_config::DEFAULT_BTN_CONFIG)
|
fs::write(combo_path, button_config::DEFAULT_BTN_CONFIG)
|
||||||
.expect("Failed to write button config conf file");
|
.expect("Failed to write button config conf file");
|
||||||
// No need to run save_all_btn_config_from_toml()
|
button_config::save_all_btn_config_from_defaults();
|
||||||
// since the statics are preloaded with the defaults
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_emulator() {
|
if is_emulator() {
|
||||||
|
|
|
@ -237,14 +237,7 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
||||||
&& is_dead(module_accessor);
|
&& is_dead(module_accessor);
|
||||||
let mut triggered_reset: bool = false;
|
let mut triggered_reset: bool = false;
|
||||||
if !is_operation_cpu(module_accessor) {
|
if !is_operation_cpu(module_accessor) {
|
||||||
let load_state_btn_hold = button_config::LOAD_STATE_BTN_HOLD.lock();
|
triggered_reset = button_config::combo_passes(module_accessor, button_config::ButtonCombo::LoadState);
|
||||||
let load_state_btn_press = button_config::LOAD_STATE_BTN_PRESS.lock();
|
|
||||||
triggered_reset = load_state_btn_hold
|
|
||||||
.iter()
|
|
||||||
.all(|btn| ControlModule::check_button_on(module_accessor, *btn))
|
|
||||||
&& load_state_btn_press
|
|
||||||
.iter()
|
|
||||||
.all(|btn| ControlModule::check_button_trigger(module_accessor, *btn));
|
|
||||||
}
|
}
|
||||||
if (autoload_reset || triggered_reset) && !fighter_is_nana {
|
if (autoload_reset || triggered_reset) && !fighter_is_nana {
|
||||||
if save_state.state == NoAction {
|
if save_state.state == NoAction {
|
||||||
|
@ -430,16 +423,7 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab + Dpad down: Save state
|
// Grab + Dpad down: Save state
|
||||||
let save_state_btn_hold = button_config::SAVE_STATE_BTN_HOLD.lock();
|
if button_config::combo_passes(module_accessor, button_config::ButtonCombo::SaveState) {
|
||||||
let save_state_btn_press = button_config::SAVE_STATE_BTN_PRESS.lock();
|
|
||||||
let save_state_condition: bool = save_state_btn_hold
|
|
||||||
.iter()
|
|
||||||
.all(|btn| ControlModule::check_button_on(module_accessor, *btn))
|
|
||||||
&& save_state_btn_press
|
|
||||||
.iter()
|
|
||||||
.all(|btn| ControlModule::check_button_trigger(module_accessor, *btn))
|
|
||||||
&& !fighter_is_nana;
|
|
||||||
if save_state_condition {
|
|
||||||
// Don't begin saving state if Nana's delayed input is captured
|
// Don't begin saving state if Nana's delayed input is captured
|
||||||
MIRROR_STATE = 1.0;
|
MIRROR_STATE = 1.0;
|
||||||
SAVE_STATE_PLAYER.state = Save;
|
SAVE_STATE_PLAYER.state = Save;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue