diff --git a/src/common/button_config.rs b/src/common/button_config.rs index f3a78a9..193d01f 100644 --- a/src/common/button_config.rs +++ b/src/common/button_config.rs @@ -3,11 +3,11 @@ use std::collections::HashMap; use crate::common::menu::{MENU_CLOSE_FRAME_COUNTER, QUICK_MENU_ACTIVE}; use crate::common::ButtonConfig; use crate::input::{ControllerStyle::*, *}; -use training_mod_sync::*; use crate::training::frame_counter; use crate::training::ui::menu::VANILLA_MENU_ACTIVE; use training_mod_consts::{OnOff, MENU}; +use training_mod_sync::*; use strum_macros::EnumIter; @@ -176,10 +176,10 @@ unsafe fn get_combo_keys(combo: ButtonCombo) -> ButtonConfig { match combo { // For OpenMenu, have a default in addition to accepting start press ButtonCombo::OpenMenu => DEFAULT_OPEN_MENU_CONFIG, - ButtonCombo::SaveState => MENU.save_state_save, - ButtonCombo::LoadState => MENU.save_state_load, - ButtonCombo::InputRecord => MENU.input_record, - ButtonCombo::InputPlayback => MENU.input_playback, + ButtonCombo::SaveState => get(&MENU).save_state_save, + ButtonCombo::LoadState => get(&MENU).save_state_load, + ButtonCombo::InputRecord => get(&MENU).input_record, + ButtonCombo::InputPlayback => get(&MENU).input_playback, } } @@ -245,7 +245,7 @@ pub fn handle_final_input_mapping(player_idx: i32, controller_struct: &mut SomeC let mut start_menu_request = false; let menu_close_wait_frame = frame_counter::get_frame_count(*MENU_CLOSE_FRAME_COUNTER); - if unsafe { MENU.menu_open_start_press == OnOff::ON } { + if get(&MENU).menu_open_start_press == OnOff::ON { let mut start_hold_frames = read_rwlock(&START_HOLD_FRAMES); if p1_controller.current_buttons.plus() { start_hold_frames += 1; diff --git a/src/common/menu.rs b/src/common/menu.rs index c44e1a2..790ccb2 100644 --- a/src/common/menu.rs +++ b/src/common/menu.rs @@ -37,7 +37,7 @@ pub fn load_from_file() { if let Ok(menu_conf_json) = serde_json::from_reader::<BufReader<_>, MenuJsonStruct>(reader) { unsafe { - MENU = menu_conf_json.menu; + assign_rwlock(&MENU, menu_conf_json.menu); DEFAULTS_MENU = menu_conf_json.defaults_menu; info!("Previous menu found. Loading..."); } @@ -68,7 +68,7 @@ pub unsafe fn set_menu_from_json(message: &str) { info!("Received menu message: {message}"); if let Ok(message_json) = response { // Includes both MENU and DEFAULTS_MENU - MENU = message_json.menu; + assign_rwlock(&MENU, message_json.menu); DEFAULTS_MENU = message_json.defaults_menu; fs::write( MENU_OPTIONS_PATH, diff --git a/src/common/release.rs b/src/common/release.rs index 15fb32c..b862af7 100644 --- a/src/common/release.rs +++ b/src/common/release.rs @@ -5,7 +5,8 @@ use zip::ZipArchive; use crate::common::dialog; use crate::consts::*; use crate::logging::*; -use training_mod_sync::LazyLock; + +use training_mod_sync::*; pub static CURRENT_VERSION: LazyLock<String> = LazyLock::new(|| { info!("Initialized lazy static value: CURRENT_VERSION"); @@ -74,7 +75,7 @@ impl Release { } fn get_update_policy() -> UpdatePolicy { - unsafe { MENU.update_policy } + get(&MENU).update_policy } fn get_release(beta: bool) -> Result<Release> { diff --git a/src/hazard_manager/mod.rs b/src/hazard_manager/mod.rs index 8be260f..7371e26 100644 --- a/src/hazard_manager/mod.rs +++ b/src/hazard_manager/mod.rs @@ -6,7 +6,8 @@ use smash::app::smashball::is_training_mode; use crate::common::consts::*; use crate::logging::*; -use training_mod_sync::LazyLock; + +use training_mod_sync::*; use HazardState::*; use HookState::*; @@ -93,7 +94,7 @@ fn hazard_intercept(_ctx: &skyline::hooks::InlineCtx) { fn mod_handle_hazards() { unsafe { let address = *HAZARD_FLAG_ADDRESS as *mut u8; - *address = (MENU.stage_hazards == OnOff::ON) as u8; + *address = (get(&MENU).stage_hazards == OnOff::ON) as u8; } } diff --git a/src/hitbox_visualizer/mod.rs b/src/hitbox_visualizer/mod.rs index c734941..d686ca5 100644 --- a/src/hitbox_visualizer/mod.rs +++ b/src/hitbox_visualizer/mod.rs @@ -5,6 +5,8 @@ use smash::phx::{Hash40, Vector3f}; use crate::common::{consts::*, *}; use crate::logging::*; +use training_mod_sync::*; + pub const ID_COLORS: &[Vector3f] = &[ // used to tint the hitbox effects -- make sure that at least one component // is equal to 1.0 @@ -135,7 +137,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModule // Resume Effect AnimCMD incase we don't display hitboxes MotionAnimcmdModule::set_sleep_effect(module_accessor, false); - if MENU.hitbox_vis == OnOff::OFF { + if get(&MENU).hitbox_vis == OnOff::OFF { return; } @@ -205,7 +207,7 @@ unsafe fn mod_handle_attack(lua_state: u64) { // necessary if param object fails // hacky way of forcing no shield damage on all hitboxes - if MENU.shield_state == Shield::INFINITE { + if get(&MENU).shield_state == Shield::INFINITE { let mut hitbox_params: Vec<L2CValue> = (0..36).map(|i| l2c_agent.pop_lua_stack(i + 1)).collect(); l2c_agent.clear_lua_stack(); @@ -219,7 +221,7 @@ unsafe fn mod_handle_attack(lua_state: u64) { } // Hitbox Visualization - if MENU.hitbox_vis == OnOff::ON { + if get(&MENU).hitbox_vis == OnOff::ON { // get all necessary grabbox params let id = l2c_agent.pop_lua_stack(1); // int let joint = l2c_agent.pop_lua_stack(3); // hash40 @@ -274,7 +276,7 @@ unsafe fn handle_catch(lua_state: u64) { } unsafe fn mod_handle_catch(lua_state: u64) { - if MENU.hitbox_vis == OnOff::OFF { + if get(&MENU).hitbox_vis == OnOff::OFF { return; } diff --git a/src/lib.rs b/src/lib.rs index 5c41ced..6ca428a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -126,38 +126,36 @@ pub fn main() { info!("Skipping version check because we are using an emulator"); } - unsafe { - notification("Training Modpack".to_string(), "Welcome!".to_string(), 60); - notification( - "Open Menu".to_string(), - if MENU.menu_open_start_press == OnOff::ON { - "Hold Start".to_string() - } else { - DEFAULT_OPEN_MENU_CONFIG.to_string() - }, - 120, - ); - notification( - "Save State".to_string(), - MENU.save_state_save.to_string(), - 120, - ); - notification( - "Load State".to_string(), - MENU.save_state_load.to_string(), - 120, - ); - notification( - "Input Record".to_string(), - MENU.input_record.to_string(), - 120, - ); - notification( - "Input Playback".to_string(), - MENU.input_playback.to_string(), - 120, - ); - } + notification("Training Modpack".to_string(), "Welcome!".to_string(), 60); + notification( + "Open Menu".to_string(), + if get(&MENU).menu_open_start_press == OnOff::ON { + "Hold Start".to_string() + } else { + DEFAULT_OPEN_MENU_CONFIG.to_string() + }, + 120, + ); + notification( + "Save State".to_string(), + get(&MENU).save_state_save.to_string(), + 120, + ); + notification( + "Load State".to_string(), + get(&MENU).save_state_load.to_string(), + 120, + ); + notification( + "Input Record".to_string(), + get(&MENU).input_record.to_string(), + 120, + ); + notification( + "Input Playback".to_string(), + get(&MENU).input_playback.to_string(), + 120, + ); std::thread::spawn(events_loop); } diff --git a/src/training/air_dodge_direction.rs b/src/training/air_dodge_direction.rs index 642bc2a..062f589 100644 --- a/src/training/air_dodge_direction.rs +++ b/src/training/air_dodge_direction.rs @@ -5,8 +5,8 @@ use smash::lib::lua_const::*; use crate::common::consts::*; use crate::common::*; -use training_mod_sync::*; use crate::training::directional_influence::should_reverse_angle; +use training_mod_sync::*; static AIRDODGE_STICK_DIRECTION: RwLock<Direction> = RwLock::new(Direction::empty()); @@ -32,7 +32,10 @@ unsafe fn get_angle(module_accessor: &mut app::BattleObjectModuleAccessor) -> Op return None; } - assign_rwlock(&AIRDODGE_STICK_DIRECTION, MENU.air_dodge_dir.get_random()); + assign_rwlock( + &AIRDODGE_STICK_DIRECTION, + get(&MENU).air_dodge_dir.get_random(), + ); let direction = read_rwlock(&AIRDODGE_STICK_DIRECTION); direction.into_angle().map(|angle| { if !should_reverse_angle(direction) { diff --git a/src/training/attack_angle.rs b/src/training/attack_angle.rs index 1a1f316..0ea8179 100644 --- a/src/training/attack_angle.rs +++ b/src/training/attack_angle.rs @@ -7,9 +7,10 @@ use training_mod_sync::*; static ATTACK_ANGLE_DIRECTION: RwLock<AttackAngle> = RwLock::new(AttackAngle::NEUTRAL); pub fn roll_direction() { - unsafe { - assign_rwlock(&ATTACK_ANGLE_DIRECTION, MENU.attack_angle.get_random()); - } + assign_rwlock( + &ATTACK_ANGLE_DIRECTION, + get(&MENU).attack_angle.get_random(), + ); } pub unsafe fn mod_get_stick_dir( diff --git a/src/training/buff.rs b/src/training/buff.rs index e7f7fb8..1e791b3 100644 --- a/src/training/buff.rs +++ b/src/training/buff.rs @@ -5,10 +5,11 @@ use smash::phx::{Hash40, Vector3f}; use crate::common::consts::*; use crate::is_operation_cpu; -use training_mod_sync::*; use crate::training::frame_counter; use crate::training::handle_add_limit; +use training_mod_sync::*; + static BUFF_REMAINING_PLAYER: RwLock<usize> = RwLock::new(0); static BUFF_REMAINING_CPU: RwLock<usize> = RwLock::new(0); @@ -77,7 +78,7 @@ pub unsafe fn handle_buffs( CameraModule::stop_quake(module_accessor, *CAMERA_QUAKE_KIND_M); // stops Psyche-Up quake CameraModule::stop_quake(module_accessor, *CAMERA_QUAKE_KIND_S); // stops Monado Art quake - let menu_vec = MENU.buff_state; + let menu_vec = get(&MENU).buff_state; if fighter_kind == *FIGHTER_KIND_BRAVE { return buff_hero(module_accessor, status); @@ -102,7 +103,7 @@ pub unsafe fn handle_buffs( } unsafe fn buff_hero(module_accessor: &mut app::BattleObjectModuleAccessor, status: i32) -> bool { - let buff_vec: Vec<BuffOption> = MENU.buff_state.hero_buffs().to_vec(); + let buff_vec: Vec<BuffOption> = get(&MENU).buff_state.hero_buffs().to_vec(); if !is_buffing(module_accessor) { // Initial set up for spells start_buff(module_accessor); @@ -239,7 +240,7 @@ unsafe fn buff_sepiroth(module_accessor: &mut app::BattleObjectModuleAccessor) - unsafe fn buff_wario(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool { if !is_buffing(module_accessor) { - let waft_level: BuffOption = MENU.buff_state.wario_buffs().get_random(); + let waft_level: BuffOption = get(&MENU).buff_state.wario_buffs().get_random(); let waft_count_secs = match waft_level { BuffOption::WAFT_MINI => WorkModule::get_param_float( module_accessor, @@ -275,7 +276,7 @@ unsafe fn buff_wario(module_accessor: &mut app::BattleObjectModuleAccessor) -> b } unsafe fn buff_shulk(module_accessor: &mut app::BattleObjectModuleAccessor, status: i32) -> bool { - let current_art = MENU.buff_state.shulk_buffs().get_random(); + let current_art = get(&MENU).buff_state.shulk_buffs().get_random(); if current_art == BuffOption::empty() { // No Monado Arts selected in the buff menu, so we don't need to buff return true; diff --git a/src/training/clatter.rs b/src/training/clatter.rs index a900081..05947fa 100644 --- a/src/training/clatter.rs +++ b/src/training/clatter.rs @@ -47,7 +47,7 @@ pub unsafe fn handle_clatter(module_accessor: &mut BattleObjectModuleAccessor) { // Don't do clatter inputs if we're not in clatter return; } - let repeat = MENU.clatter_strength.into_u32(); + let repeat = get(&MENU).clatter_strength.into_u32(); let mut counter_guard = lock_write_rwlock(&COUNTER); *counter_guard = ((*counter_guard) + 1) % repeat; diff --git a/src/training/combo.rs b/src/training/combo.rs index 4731e3b..bbe33c7 100644 --- a/src/training/combo.rs +++ b/src/training/combo.rs @@ -3,10 +3,11 @@ use training_mod_consts::OnOff; use crate::common::*; use crate::consts::Action; -use training_mod_sync::*; use crate::training::ui::notifications; use crate::training::*; +use training_mod_sync::*; + static PLAYER_WAS_ACTIONABLE: RwLock<bool> = RwLock::new(false); static CPU_WAS_ACTIONABLE: RwLock<bool> = RwLock::new(false); @@ -49,37 +50,35 @@ unsafe fn is_actionable(module_accessor: *mut BattleObjectModuleAccessor) -> boo } fn update_frame_advantage(frame_advantage: i32) { - unsafe { - if MENU.frame_advantage == OnOff::ON { - // Prioritize Frame Advantage over Input Recording Playback - notifications::clear_notifications_except("Input Recording"); - notifications::clear_notifications_except("Frame Advantage"); - notifications::color_notification( - "Frame Advantage".to_string(), - format!("{frame_advantage}"), - 60, - match frame_advantage { - x if x < 0 => ResColor { - r: 200, - g: 8, - b: 8, - a: 255, - }, - 0 => ResColor { - r: 0, - g: 0, - b: 0, - a: 255, - }, - _ => ResColor { - r: 31, - g: 198, - b: 0, - a: 255, - }, + if get(&MENU).frame_advantage == OnOff::ON { + // Prioritize Frame Advantage over Input Recording Playback + notifications::clear_notifications_except("Input Recording"); + notifications::clear_notifications_except("Frame Advantage"); + notifications::color_notification( + "Frame Advantage".to_string(), + format!("{frame_advantage}"), + 60, + match frame_advantage { + x if x < 0 => ResColor { + r: 200, + g: 8, + b: 8, + a: 255, }, - ); - } + 0 => ResColor { + r: 0, + g: 0, + b: 0, + a: 255, + }, + _ => ResColor { + r: 31, + g: 198, + b: 0, + a: 255, + }, + }, + ); } } @@ -101,7 +100,7 @@ pub unsafe fn once_per_frame(module_accessor: &mut BattleObjectModuleAccessor) { || frame_counter::is_counting(*CPU_FRAME_COUNTER_INDEX); if !is_counting { - if MENU.mash_state == Action::empty() + if get(&MENU).mash_state == Action::empty() && !player_is_actionable && !cpu_is_actionable && (!was_in_shieldstun(cpu_module_accessor) && is_in_shieldstun(cpu_module_accessor) diff --git a/src/training/crouch.rs b/src/training/crouch.rs index 39b318b..4852905 100644 --- a/src/training/crouch.rs +++ b/src/training/crouch.rs @@ -4,13 +4,15 @@ use smash::lib::lua_const::*; use crate::common::consts::OnOff; use crate::common::*; +use training_mod_sync::*; + pub unsafe fn mod_get_stick_y(module_accessor: &mut BattleObjectModuleAccessor) -> Option<f32> { if !is_operation_cpu(module_accessor) { return None; } let fighter_status_kind = StatusModule::status_kind(module_accessor); - if MENU.crouch == OnOff::ON + if get(&MENU).crouch == OnOff::ON && [ *FIGHTER_STATUS_KIND_WAIT, *FIGHTER_STATUS_KIND_SQUAT, diff --git a/src/training/directional_influence.rs b/src/training/directional_influence.rs index b58bf6d..9430fed 100644 --- a/src/training/directional_influence.rs +++ b/src/training/directional_influence.rs @@ -12,15 +12,12 @@ use training_mod_sync::*; static DI_CASE: RwLock<Direction> = RwLock::new(Direction::empty()); pub fn roll_di_case() { - unsafe { - let mut di_case_guard = lock_write_rwlock(&DI_CASE); - if *di_case_guard != Direction::empty() { - // DI direction already selected, don't pick a new one - return; - } - - *di_case_guard = MENU.di_state.get_random(); + let mut di_case_guard = lock_write_rwlock(&DI_CASE); + if *di_case_guard != Direction::empty() { + // DI direction already selected, don't pick a new one + return; } + *di_case_guard = get(&MENU).di_state.get_random(); } pub fn reset_di_case(module_accessor: &mut app::BattleObjectModuleAccessor) { @@ -47,7 +44,7 @@ pub unsafe fn handle_correct_damage_vector_common( } unsafe fn mod_handle_di(fighter: &L2CFighterCommon, _arg1: L2CValue) { - if MENU.di_state == Direction::empty() { + if get(&MENU).di_state == Direction::empty() { return; } diff --git a/src/training/fast_fall.rs b/src/training/fast_fall.rs index 001b263..1c41c7a 100644 --- a/src/training/fast_fall.rs +++ b/src/training/fast_fall.rs @@ -3,9 +3,10 @@ use smash::lib::lua_const::*; use smash::phx::{Hash40, Vector3f}; use crate::common::*; -use training_mod_sync::*; use crate::training::{frame_counter, input_record}; +use training_mod_sync::*; + static DELAY: RwLock<u32> = RwLock::new(0); static FAST_FALL: RwLock<bool> = RwLock::new(false); static FRAME_COUNTER_INDEX: LazyLock<usize> = @@ -16,9 +17,7 @@ fn should_fast_fall() -> bool { } pub fn roll_fast_fall() { - unsafe { - assign_rwlock(&FAST_FALL, MENU.fast_fall.get_random().into_bool()); - } + assign_rwlock(&FAST_FALL, get(&MENU).fast_fall.get_random().into_bool()); } pub fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModuleAccessor) { @@ -38,7 +37,7 @@ pub fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModuleAccesso unsafe { if !is_falling(module_accessor) { // Roll FF delay - assign_rwlock(&DELAY, MENU.fast_fall_delay.get_random().into_delay()); + assign_rwlock(&DELAY, get(&MENU).fast_fall_delay.get_random().into_delay()); frame_counter::full_reset(*FRAME_COUNTER_INDEX); return; } diff --git a/src/training/full_hop.rs b/src/training/full_hop.rs index c5d8b19..e3b1467 100644 --- a/src/training/full_hop.rs +++ b/src/training/full_hop.rs @@ -13,9 +13,7 @@ pub fn should_full_hop() -> bool { } pub fn roll_full_hop() { - unsafe { - assign_rwlock(&FULL_HOP, MENU.full_hop.get_random().into_bool()); - } + assign_rwlock(&FULL_HOP, get(&MENU).full_hop.get_random().into_bool()); } pub unsafe fn check_button_on( diff --git a/src/training/input_delay.rs b/src/training/input_delay.rs index a41246d..b99f5c6 100644 --- a/src/training/input_delay.rs +++ b/src/training/input_delay.rs @@ -4,6 +4,8 @@ use crate::common::input::*; use lazy_static::lazy_static; use parking_lot::Mutex; +use training_mod_sync::*; + use crate::common::MENU; lazy_static! { @@ -17,14 +19,14 @@ pub fn handle_final_input_mapping(player_idx: i32, out: *mut MappedInputs) { let mut delayed_mappings = P1_DELAYED_INPUT_MAPPINGS.lock(); let actual_mapping = *out; - if delayed_mappings.len() < MENU.input_delay.into_delay() as usize { + if delayed_mappings.len() < get(&MENU).input_delay.into_delay() as usize { *out = MappedInputs::empty(); } else if let Some(delayed_mapping) = delayed_mappings.back() { *out = *delayed_mapping; } delayed_mappings.push_front(actual_mapping); - delayed_mappings.truncate(MENU.input_delay.into_delay() as usize); + delayed_mappings.truncate(get(&MENU).input_delay.into_delay() as usize); } } } diff --git a/src/training/input_log.rs b/src/training/input_log.rs index e45dde2..5d43a47 100644 --- a/src/training/input_log.rs +++ b/src/training/input_log.rs @@ -3,11 +3,11 @@ use std::collections::VecDeque; use crate::common::input::*; use crate::menu::QUICK_MENU_ACTIVE; -use training_mod_sync::*; use crate::try_get_module_accessor; use skyline::nn::ui2d::ResColor; use smash::app::{lua_bind::*, utility}; use training_mod_consts::{FighterId, InputDisplay, MENU}; +use training_mod_sync::*; use super::{frame_counter, input_record::STICK_CLAMP_MULTIPLIER}; @@ -136,50 +136,51 @@ fn bin_stick_values(x: i8, y: i8) -> (DirectionStrength, f32) { impl InputLog { pub fn is_different(&self, other: &InputLog) -> bool { - unsafe { - match MENU.input_display { - InputDisplay::SMASH => self.is_smash_different(other), - InputDisplay::RAW => self.is_raw_different(other), - InputDisplay::STATUS => self.is_status_different(other), - InputDisplay::NONE => false, - _ => panic!("Invalid value in is_different: {}", MENU.input_display), - } + match get(&MENU).input_display { + InputDisplay::SMASH => self.is_smash_different(other), + InputDisplay::RAW => self.is_raw_different(other), + InputDisplay::STATUS => self.is_status_different(other), + InputDisplay::NONE => false, + _ => panic!( + "Invalid value in is_different: {}", + get(&MENU).input_display + ), } } pub fn binned_lstick(&self) -> (DirectionStrength, f32) { - unsafe { - match MENU.input_display { - InputDisplay::SMASH => self.smash_binned_lstick(), - InputDisplay::RAW => self.raw_binned_lstick(), - InputDisplay::STATUS => (DirectionStrength::None, 0.0), - InputDisplay::NONE => panic!("Invalid input display to log"), - _ => panic!("Invalid value in binned_lstick: {}", MENU.input_display), - } + match get(&MENU).input_display { + InputDisplay::SMASH => self.smash_binned_lstick(), + InputDisplay::RAW => self.raw_binned_lstick(), + InputDisplay::STATUS => (DirectionStrength::None, 0.0), + InputDisplay::NONE => panic!("Invalid input display to log"), + _ => panic!( + "Invalid value in binned_lstick: {}", + get(&MENU).input_display + ), } } pub fn binned_rstick(&self) -> (DirectionStrength, f32) { - unsafe { - match MENU.input_display { - InputDisplay::SMASH => self.smash_binned_rstick(), - InputDisplay::RAW => self.raw_binned_rstick(), - InputDisplay::STATUS => (DirectionStrength::None, 0.0), - InputDisplay::NONE => panic!("Invalid input display to log"), - _ => panic!("Invalid value in binned_rstick: {}", MENU.input_display), - } + match get(&MENU).input_display { + InputDisplay::SMASH => self.smash_binned_rstick(), + InputDisplay::RAW => self.raw_binned_rstick(), + InputDisplay::STATUS => (DirectionStrength::None, 0.0), + InputDisplay::NONE => panic!("Invalid input display to log"), + _ => panic!( + "Invalid value in binned_rstick: {}", + get(&MENU).input_display + ), } } pub fn button_icons(&self) -> VecDeque<(&str, ResColor)> { - unsafe { - match MENU.input_display { - InputDisplay::SMASH => self.smash_button_icons(), - InputDisplay::RAW => self.raw_button_icons(), - InputDisplay::STATUS => VecDeque::new(), - InputDisplay::NONE => panic!("Invalid input display to log"), - _ => unreachable!(), - } + match get(&MENU).input_display { + InputDisplay::SMASH => self.smash_button_icons(), + InputDisplay::RAW => self.raw_button_icons(), + InputDisplay::STATUS => VecDeque::new(), + InputDisplay::NONE => panic!("Invalid input display to log"), + _ => unreachable!(), } } @@ -260,14 +261,12 @@ impl InputLog { self.smash_inputs.buttons != other.smash_inputs.buttons || self.smash_binned_lstick() != other.smash_binned_lstick() || self.smash_binned_rstick() != other.smash_binned_rstick() - || (unsafe { MENU.input_display_status.as_bool() } && self.status != other.status) + || (get(&MENU).input_display_status.as_bool() && self.status != other.status) } fn is_status_different(&self, other: &InputLog) -> bool { - unsafe { - let input_display_status = MENU.input_display_status.as_bool(); - input_display_status && (self.status != other.status) - } + let input_display_status = get(&MENU).input_display_status.as_bool(); + input_display_status && (self.status != other.status) } fn smash_binned_lstick(&self) -> (DirectionStrength, f32) { @@ -282,7 +281,7 @@ impl InputLog { self.raw_inputs.current_buttons != other.raw_inputs.current_buttons || self.raw_binned_lstick() != other.raw_binned_lstick() || self.raw_binned_rstick() != other.raw_binned_rstick() - || (unsafe { MENU.input_display_status.as_bool() } && self.status != other.status) + || (get(&MENU).input_display_status.as_bool() && self.status != other.status) } fn raw_binned_lstick(&self) -> (DirectionStrength, f32) { @@ -316,7 +315,7 @@ pub fn handle_final_input_mapping( out: *mut MappedInputs, ) { unsafe { - if MENU.input_display == InputDisplay::NONE { + if get(&MENU).input_display == InputDisplay::NONE { return; } diff --git a/src/training/input_record.rs b/src/training/input_record.rs index cddd01b..34f4953 100644 --- a/src/training/input_record.rs +++ b/src/training/input_record.rs @@ -20,6 +20,8 @@ use crate::training::mash; use crate::training::ui::notifications::{clear_notifications_except, color_notification}; use crate::{error, warn}; +use training_mod_sync::*; + #[derive(PartialEq, Debug)] pub enum InputRecordState { None, @@ -104,17 +106,18 @@ unsafe fn should_mash_playback() { if is_in_hitstun(&mut *cpu_module_accessor) { // if we're in hitstun and want to enter the frame we start hitstop for SDI, start if we're in any damage status instantly - if MENU.hitstun_playback == HitstunPlayback::INSTANT { + if get(&MENU).hitstun_playback == HitstunPlayback::INSTANT { should_playback = true; } // if we want to wait until we exit hitstop and begin flying away for shield art etc, start if we're not in hitstop - if MENU.hitstun_playback == HitstunPlayback::HITSTOP + if get(&MENU).hitstun_playback == HitstunPlayback::HITSTOP && !StopModule::is_stop(cpu_module_accessor) { should_playback = true; } // if we're in hitstun and want to wait till FAF to act, then we want to match our starting status to the correct transition term to see if we can hitstun cancel - if MENU.hitstun_playback == HitstunPlayback::HITSTUN && can_transition(cpu_module_accessor) + if get(&MENU).hitstun_playback == HitstunPlayback::HITSTUN + && can_transition(cpu_module_accessor) { should_playback = true; } @@ -193,12 +196,12 @@ unsafe fn handle_recording_for_fighter(module_accessor: &mut BattleObjectModuleA let fighter_kind = utility::get_kind(module_accessor); let fighter_is_nana = fighter_kind == *FIGHTER_KIND_NANA; - CURRENT_RECORD_SLOT = MENU.recording_slot.into_idx().unwrap_or(0); + CURRENT_RECORD_SLOT = get(&MENU).recording_slot.into_idx().unwrap_or(0); if entry_id_int == 0 && !fighter_is_nana { if button_config::combo_passes(button_config::ButtonCombo::InputPlayback) { - playback(MENU.playback_button_slots.get_random().into_idx()); - } else if MENU.record_trigger.contains(&RecordTrigger::COMMAND) + playback(get(&MENU).playback_button_slots.get_random().into_idx()); + } else if get(&MENU).record_trigger.contains(&RecordTrigger::COMMAND) && button_config::combo_passes(button_config::ButtonCombo::InputRecord) { lockout_record(); @@ -217,7 +220,9 @@ unsafe fn handle_recording_for_fighter(module_accessor: &mut BattleObjectModuleA // If we need to crop the recording for neutral input // INPUT_RECORD_FRAME must be > 0 to prevent bounding errors - if INPUT_RECORD == Record && MENU.recording_crop == OnOff::ON && INPUT_RECORD_FRAME > 0 + if INPUT_RECORD == Record + && get(&MENU).recording_crop == OnOff::ON + && INPUT_RECORD_FRAME > 0 { while INPUT_RECORD_FRAME > 0 && is_input_neutral(INPUT_RECORD_FRAME - 1) { // Discard frames at the end of the recording until the last frame with input @@ -229,7 +234,7 @@ unsafe fn handle_recording_for_fighter(module_accessor: &mut BattleObjectModuleA INPUT_RECORD_FRAME = 0; - if MENU.playback_loop == OnOff::ON && INPUT_RECORD == Playback { + if get(&MENU).playback_loop == OnOff::ON && INPUT_RECORD == Playback { playback(Some(CURRENT_PLAYBACK_SLOT)); } else { INPUT_RECORD = None; @@ -327,7 +332,7 @@ pub unsafe fn lockout_record() { .for_each(|mapped_input| { *mapped_input = MappedInputs::empty(); }); - CURRENT_FRAME_LENGTH = MENU.recording_duration.into_frames(); + CURRENT_FRAME_LENGTH = get(&MENU).recording_duration.into_frames(); P1_FRAME_LENGTH_MAPPING.lock()[CURRENT_RECORD_SLOT] = CURRENT_FRAME_LENGTH; LOCKOUT_FRAME = 30; // This needs to be this high or issues occur dropping shield - but does this cause problems when trying to record ledge? BUFFER_FRAME = 0; diff --git a/src/training/ledge.rs b/src/training/ledge.rs index 2a96670..0eeee9a 100644 --- a/src/training/ledge.rs +++ b/src/training/ledge.rs @@ -3,9 +3,10 @@ use smash::lib::lua_const::*; use crate::common::consts::*; use crate::common::*; -use training_mod_sync::*; use crate::training::{frame_counter, input_record, mash}; +use training_mod_sync::*; + const NOT_SET: u32 = 9001; static LEDGE_DELAY: RwLock<u32> = RwLock::new(NOT_SET); static LEDGE_CASE: RwLock<LedgeOption> = RwLock::new(LedgeOption::empty()); @@ -35,10 +36,7 @@ fn roll_ledge_delay() { // Don't roll another ledge delay if one is already selected return; } - - unsafe { - *ledge_delay_guard = MENU.ledge_delay.get_random().into_longdelay(); - } + *ledge_delay_guard = get(&MENU).ledge_delay.get_random().into_longdelay(); } fn roll_ledge_case() { @@ -48,48 +46,43 @@ fn roll_ledge_case() { if *ledge_case_guard != LedgeOption::empty() { return; } - - unsafe { - *ledge_case_guard = MENU.ledge_state.get_random(); - } + *ledge_case_guard = get(&MENU).ledge_state.get_random(); } fn get_ledge_option() -> Option<Action> { - unsafe { - let mut override_action: Option<Action> = None; - let regular_action = if MENU.mash_triggers.contains(&MashTrigger::LEDGE) { - Some(MENU.mash_state.get_random()) - } else { - None - }; + let mut override_action: Option<Action> = None; + let regular_action = if get(&MENU).mash_triggers.contains(&MashTrigger::LEDGE) { + Some(get(&MENU).mash_state.get_random()) + } else { + None + }; - match read_rwlock(&LEDGE_CASE) { - LedgeOption::NEUTRAL => { - if MENU.ledge_neutral_override != Action::empty() { - override_action = Some(MENU.ledge_neutral_override.get_random()); - } - } - LedgeOption::ROLL => { - if MENU.ledge_roll_override != Action::empty() { - override_action = Some(MENU.ledge_roll_override.get_random()); - } - } - LedgeOption::JUMP => { - if MENU.ledge_jump_override != Action::empty() { - override_action = Some(MENU.ledge_jump_override.get_random()); - } - } - LedgeOption::ATTACK => { - if MENU.ledge_attack_override != Action::empty() { - override_action = Some(MENU.ledge_attack_override.get_random()); - } - } - _ => { - override_action = None; + match read_rwlock(&LEDGE_CASE) { + LedgeOption::NEUTRAL => { + if get(&MENU).ledge_neutral_override != Action::empty() { + override_action = Some(get(&MENU).ledge_neutral_override.get_random()); } } - override_action.or(regular_action) + LedgeOption::ROLL => { + if get(&MENU).ledge_roll_override != Action::empty() { + override_action = Some(get(&MENU).ledge_roll_override.get_random()); + } + } + LedgeOption::JUMP => { + if get(&MENU).ledge_jump_override != Action::empty() { + override_action = Some(get(&MENU).ledge_jump_override.get_random()); + } + } + LedgeOption::ATTACK => { + if get(&MENU).ledge_attack_override != Action::empty() { + override_action = Some(get(&MENU).ledge_attack_override.get_random()); + } + } + _ => { + override_action = None; + } } + override_action.or(regular_action) } pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor) { @@ -137,7 +130,7 @@ pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor // We buffer playback on frame 18 because we don't change status this frame from inputting on next frame; do we need to do one earlier for lasso? if should_buffer_playback && ledge_case.is_playback() - && MENU.ledge_delay != LongDelay::empty() + && get(&MENU).ledge_delay != LongDelay::empty() { input_record::playback_ledge(ledge_case.playback_slot()); return; @@ -180,7 +173,7 @@ pub unsafe fn is_enable_transition_term( // Only handle ledge scenarios from menu if StatusModule::status_kind(_module_accessor) != *FIGHTER_STATUS_KIND_CLIFF_WAIT - || MENU.ledge_state == LedgeOption::empty() + || get(&MENU).ledge_state == LedgeOption::empty() { return None; } @@ -210,7 +203,7 @@ pub fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModuleAccesso return; } - if MENU.ledge_state == LedgeOption::empty() { + if get(&MENU).ledge_state == LedgeOption::empty() { return; } diff --git a/src/training/mash.rs b/src/training/mash.rs index d2d7448..e82a3d5 100644 --- a/src/training/mash.rs +++ b/src/training/mash.rs @@ -11,6 +11,8 @@ use crate::training::input_record; use crate::training::shield; use crate::training::{attack_angle, save_states}; +use training_mod_sync::*; + use once_cell::sync::Lazy; const DISTANCE_CLOSE_THRESHOLD: f32 = 16.0; @@ -80,7 +82,7 @@ pub fn buffer_action(action: Action) { unsafe { // exit playback if we want to perform mash actions out of it // TODO: Figure out some way to deal with trying to playback into another playback - if MENU.playback_mash == OnOff::ON + if get(&MENU).playback_mash == OnOff::ON && input_record::is_playback() && !input_record::is_recording() && !input_record::is_standby() @@ -108,9 +110,7 @@ pub fn buffer_action(action: Action) { pub fn buffer_follow_up() { let action; - unsafe { - action = MENU.follow_up.get_random(); - } + action = get(&MENU).follow_up.get_random(); if action == Action::empty() { return; @@ -216,91 +216,100 @@ unsafe fn get_buffered_action( return None; } let fighter_distance = get_fighter_distance(); + let menu = get(&MENU); if is_in_tech(module_accessor) { - let action = MENU.tech_action_override.get_random(); + let action = menu.tech_action_override.get_random(); if action != Action::empty() { Some(action) - } else if MENU.mash_triggers.contains(&MashTrigger::TECH) { - Some(MENU.mash_state.get_random()) + } else if menu.mash_triggers.contains(&MashTrigger::TECH) { + Some(menu.mash_state.get_random()) } else { None } } else if is_in_clatter(module_accessor) { - let action = MENU.clatter_override.get_random(); + let action = menu.clatter_override.get_random(); if action != Action::empty() { Some(action) - } else if MENU.mash_triggers.contains(&MashTrigger::CLATTER) { - Some(MENU.mash_state.get_random()) + } else if menu.mash_triggers.contains(&MashTrigger::CLATTER) { + Some(menu.mash_state.get_random()) } else { None } } else if is_in_tumble(module_accessor) { // Note that the tumble check needs to come before hitstun, // otherwise the hitstun check will always return first - let action = MENU.tumble_override.get_random(); + let action = menu.tumble_override.get_random(); if action != Action::empty() { Some(action) - } else if MENU.mash_triggers.contains(&MashTrigger::TUMBLE) { - Some(MENU.mash_state.get_random()) + } else if menu.mash_triggers.contains(&MashTrigger::TUMBLE) { + Some(menu.mash_state.get_random()) } else { None } } else if is_in_hitstun(module_accessor) { - let action = MENU.hitstun_override.get_random(); + let action = menu.hitstun_override.get_random(); if action != Action::empty() { Some(action) - } else if MENU.mash_triggers.contains(&MashTrigger::HIT) { - Some(MENU.mash_state.get_random()) + } else if menu.mash_triggers.contains(&MashTrigger::HIT) { + Some(menu.mash_state.get_random()) } else { None } } else if is_in_parry(module_accessor) { - let action = MENU.parry_override.get_random(); + let action = menu.parry_override.get_random(); if action != Action::empty() { Some(action) - } else if MENU.mash_triggers.contains(&MashTrigger::PARRY) { - Some(MENU.mash_state.get_random()) + } else if menu.mash_triggers.contains(&MashTrigger::PARRY) { + Some(menu.mash_state.get_random()) } else { None } } else if is_in_footstool(module_accessor) { - let action = MENU.footstool_override.get_random(); + let action = menu.footstool_override.get_random(); if action != Action::empty() { Some(action) - } else if MENU.mash_triggers.contains(&MashTrigger::FOOTSTOOL) { - Some(MENU.mash_state.get_random()) + } else if menu.mash_triggers.contains(&MashTrigger::FOOTSTOOL) { + Some(menu.mash_state.get_random()) } else { None } } else if is_in_ledgetrump(module_accessor) { - let action = MENU.trump_override.get_random(); + let action = menu.trump_override.get_random(); if action != Action::empty() { Some(action) - } else if MENU.mash_triggers.contains(&MashTrigger::TRUMP) { - Some(MENU.mash_state.get_random()) + } else if menu.mash_triggers.contains(&MashTrigger::TRUMP) { + Some(menu.mash_state.get_random()) } else { None } } else if is_in_landing(module_accessor) { - let action = MENU.landing_override.get_random(); + let action = menu.landing_override.get_random(); if action != Action::empty() { Some(action) - } else if MENU.mash_triggers.contains(&MashTrigger::LANDING) { - Some(MENU.mash_state.get_random()) + } else if menu.mash_triggers.contains(&MashTrigger::LANDING) { + Some(menu.mash_state.get_random()) } else { None } - } else if (MENU.mash_triggers.contains(&MashTrigger::GROUNDED) && is_grounded(module_accessor)) - || (MENU.mash_triggers.contains(&MashTrigger::AIRBORNE) && is_airborne(module_accessor)) - || (MENU.mash_triggers.contains(&MashTrigger::DISTANCE_CLOSE) + } else if (menu.mash_triggers.contains(&MashTrigger::GROUNDED) + && is_grounded(module_accessor)) + || (menu.mash_triggers.contains(&MashTrigger::AIRBORNE) + && is_airborne(module_accessor)) + || (menu + .mash_triggers + .contains(&MashTrigger::DISTANCE_CLOSE) && fighter_distance < DISTANCE_CLOSE_THRESHOLD) - || (MENU.mash_triggers.contains(&MashTrigger::DISTANCE_MID) + || (menu + .mash_triggers + .contains(&MashTrigger::DISTANCE_MID) && fighter_distance < DISTANCE_MID_THRESHOLD) - || (MENU.mash_triggers.contains(&MashTrigger::DISTANCE_FAR) + || (menu + .mash_triggers + .contains(&MashTrigger::DISTANCE_FAR) && fighter_distance < DISTANCE_FAR_THRESHOLD) - || MENU.mash_triggers.contains(&MashTrigger::ALWAYS) + || menu.mash_triggers.contains(&MashTrigger::ALWAYS) { - Some(MENU.mash_state.get_random()) + Some(menu.mash_state.get_random()) } else { // SHIELD handled in shield.rs // LEDGE handled in ledge.rs @@ -313,7 +322,7 @@ fn buffer_menu_mash(action: Action) { buffer_action(action); full_hop::roll_full_hop(); fast_fall::roll_fast_fall(); - FALLING_AERIAL = MENU.falling_aerials.get_random().into_bool(); + FALLING_AERIAL = get(&MENU).falling_aerials.get_random().into_bool(); } } @@ -577,7 +586,7 @@ fn roll_aerial_delay(action: Action) { return; } unsafe { - AERIAL_DELAY = MENU.aerial_delay.get_random().into_delay(); + AERIAL_DELAY = get(&MENU).aerial_delay.get_random().into_delay(); } } diff --git a/src/training/mod.rs b/src/training/mod.rs index d2c5c6c..1c5bfc0 100644 --- a/src/training/mod.rs +++ b/src/training/mod.rs @@ -10,7 +10,6 @@ use crate::common::{ use crate::hitbox_visualizer; use crate::input::*; use crate::logging::*; -use training_mod_sync::*; use crate::training::character_specific::{items, kirby, pikmin, ptrainer}; use skyline::hooks::{getRegionAddress, InlineCtx, Region}; use skyline::nn::ro::LookupSymbol; @@ -20,6 +19,7 @@ use smash::app::{ use smash::lib::lua_const::*; use smash::params::*; use smash::phx::{Hash40, Vector3f}; +use training_mod_sync::*; pub mod buff; pub mod charge; @@ -134,7 +134,7 @@ fn once_per_frame_per_fighter(module_accessor: &mut BattleObjectModuleAccessor, // Handle dodge staling here b/c input recording or mash can cause dodging WorkModule::set_flag( module_accessor, - !(MENU.stale_dodges.as_bool()), + !(get(&MENU).stale_dodges.as_bool()), *FIGHTER_INSTANCE_WORK_ID_FLAG_DISABLE_ESCAPE_PENALTY, ); input_record::handle_recording(); @@ -428,7 +428,7 @@ pub unsafe fn handle_add_damage( #[skyline::hook(offset = *OFFSET_TRAINING_RESET_CHECK, inline)] unsafe fn lra_handle(ctx: &mut InlineCtx) { let x8 = ctx.registers[8].x.as_mut(); - if !(MENU.lra_reset.as_bool()) { + if !(get(&MENU).lra_reset.as_bool()) { *x8 = 0; } } @@ -766,7 +766,7 @@ pub unsafe fn handle_reused_ui( // If Little Mac is in the game and we're buffing him, set the meter to 100 if (player_fighter_kind == *FIGHTER_KIND_LITTLEMAC || cpu_fighter_kind == *FIGHTER_KIND_LITTLEMAC) - && MENU.buff_state.contains(&BuffOption::KO) + && get(&MENU).buff_state.contains(&BuffOption::KO) { param_2 = 100; } diff --git a/src/training/save_states.rs b/src/training/save_states.rs index e899360..7a5da23 100644 --- a/src/training/save_states.rs +++ b/src/training/save_states.rs @@ -27,7 +27,6 @@ use crate::common::get_module_accessor; use crate::common::is_dead; use crate::common::MENU; use crate::is_operation_cpu; -use training_mod_sync::*; use crate::training::buff; use crate::training::character_specific::{ptrainer, steve}; use crate::training::charge::{self, ChargeState}; @@ -36,6 +35,7 @@ use crate::training::items::apply_item; use crate::training::reset; use crate::training::ui::notifications; use crate::{is_ptrainer, ITEM_MANAGER_ADDR}; +use training_mod_sync::*; // Don't remove Mii hats, Pikmin, Luma, or crafting table const ARTICLE_ALLOWLIST: [(LuaConst, LuaConst); 9] = [ @@ -233,11 +233,11 @@ static mut MIRROR_STATE: f32 = 1.0; static mut RANDOM_SLOT: usize = 0; unsafe fn get_slot() -> usize { - let random_slot = MENU.randomize_slots.get_random(); + let random_slot = get(&MENU).randomize_slots.get_random(); if random_slot != SaveStateSlot::empty() { RANDOM_SLOT } else { - MENU.save_state_slot.into_idx().unwrap_or(0) + get(&MENU).save_state_slot.into_idx().unwrap_or(0) } } @@ -256,13 +256,13 @@ pub unsafe fn is_loading() -> bool { } pub unsafe fn should_mirror() -> f32 { - match MENU.save_state_mirroring { + match get(&MENU).save_state_mirroring { SaveStateMirroring::NONE => 1.0, SaveStateMirroring::ALTERNATE => -1.0 * MIRROR_STATE, SaveStateMirroring::RANDOM => ([-1.0, 1.0])[get_random_int(2) as usize], _ => panic!( "Invalid value in should_mirror: {}", - MENU.save_state_mirroring + get(&MENU).save_state_mirroring ), } } @@ -417,7 +417,7 @@ pub unsafe fn on_death(fighter_kind: i32, module_accessor: &mut app::BattleObjec } pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor) { - if MENU.save_state_enable == OnOff::OFF { + if get(&MENU).save_state_enable == OnOff::OFF { return; } @@ -449,7 +449,7 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor) .contains(&fighter_kind); // Reset state - let autoload_reset = MENU.save_state_autoload == OnOff::ON + let autoload_reset = get(&MENU).save_state_autoload == OnOff::ON && save_state.state == NoAction && is_dead(module_accessor); let mut triggered_reset: bool = false; @@ -458,7 +458,7 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor) } if (autoload_reset || triggered_reset) && !fighter_is_nana { if save_state.state == NoAction { - let random_slot = MENU.randomize_slots.get_random(); + let random_slot = get(&MENU).randomize_slots.get_random(); let slot = if random_slot != SaveStateSlot::empty() { RANDOM_SLOT = random_slot.into_idx().unwrap_or(0); RANDOM_SLOT @@ -573,48 +573,48 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor) if save_state.state == NoAction { // Set damage of the save state if !is_cpu { - match MENU.save_damage_player { + match get(&MENU).save_damage_player { SaveDamage::SAVED => { set_damage(module_accessor, save_state.percent); } SaveDamage::RANDOM => { // Gen random value let pct: f32 = get_random_float( - MENU.save_damage_limits_player.0 as f32, - MENU.save_damage_limits_player.1 as f32, + get(&MENU).save_damage_limits_player.0 as f32, + get(&MENU).save_damage_limits_player.1 as f32, ); set_damage(module_accessor, pct); } SaveDamage::DEFAULT => {} _ => panic!( "Invalid value in save_states()::save_damage_player: {}", - MENU.save_damage_player + get(&MENU).save_damage_player ), } } else { - match MENU.save_damage_cpu { + match get(&MENU).save_damage_cpu { SaveDamage::SAVED => { set_damage(module_accessor, save_state.percent); } SaveDamage::RANDOM => { // Gen random value let pct: f32 = get_random_float( - MENU.save_damage_limits_cpu.0 as f32, - MENU.save_damage_limits_cpu.1 as f32, + get(&MENU).save_damage_limits_cpu.0 as f32, + get(&MENU).save_damage_limits_cpu.1 as f32, ); set_damage(module_accessor, pct); } SaveDamage::DEFAULT => {} _ => panic!( "Invalid value in save_states()::save_damage_cpu: {}", - MENU.save_damage_cpu + get(&MENU).save_damage_cpu ), } } // Set to held item - if !is_cpu && !fighter_is_nana && MENU.character_item != CharacterItem::NONE { - apply_item(MENU.character_item); + if !is_cpu && !fighter_is_nana && get(&MENU).character_item != CharacterItem::NONE { + apply_item(get(&MENU).character_item); } // Set the charge of special moves if the fighter matches the kind in the save state @@ -662,17 +662,20 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor) } // if we're recording on state load, record - if MENU.record_trigger.contains(&RecordTrigger::SAVESTATE) { + if get(&MENU) + .record_trigger + .contains(&RecordTrigger::SAVESTATE) + { input_record::lockout_record(); return; } // otherwise, begin input recording playback if selected // for ledge, don't do this - if you want playback on a ledge, you have to set it as a ledge option, // otherwise there too many edge cases here - else if MENU.save_state_playback.get_random() != PlaybackSlot::empty() + else if get(&MENU).save_state_playback.get_random() != PlaybackSlot::empty() && save_state.situation_kind != SITUATION_KIND_CLIFF { - input_record::playback(MENU.save_state_playback.get_random().into_idx()); + input_record::playback(get(&MENU).save_state_playback.get_random().into_idx()); } return; @@ -707,12 +710,12 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor) if button_config::combo_passes(button_config::ButtonCombo::SaveState) { // Don't begin saving state if Nana's delayed input is captured MIRROR_STATE = 1.0; - save_state_player(MENU.save_state_slot.into_idx().unwrap_or(0)).state = Save; - save_state_cpu(MENU.save_state_slot.into_idx().unwrap_or(0)).state = Save; + save_state_player(get(&MENU).save_state_slot.into_idx().unwrap_or(0)).state = Save; + save_state_cpu(get(&MENU).save_state_slot.into_idx().unwrap_or(0)).state = Save; notifications::clear_notifications_except("Save State"); notifications::notification( "Save State".to_string(), - format!("Saved Slot {}", MENU.save_state_slot), + format!("Saved Slot {}", get(&MENU).save_state_slot), 120, ); } diff --git a/src/training/sdi.rs b/src/training/sdi.rs index fdbc039..2ef116f 100644 --- a/src/training/sdi.rs +++ b/src/training/sdi.rs @@ -5,8 +5,8 @@ use smash::Vector2f; use crate::common::consts::*; use crate::common::*; -use training_mod_sync::*; use crate::training::directional_influence; +use training_mod_sync::*; static COUNTER: RwLock<u32> = RwLock::new(0); static DIRECTION: RwLock<Direction> = RwLock::new(Direction::NEUTRAL); @@ -14,9 +14,7 @@ static DIRECTION: RwLock<Direction> = RwLock::new(Direction::NEUTRAL); // TODO! Bug - we only roll a new direction when loading a save state or on LRA reset pub fn roll_direction() { assign_rwlock(&COUNTER, 0); - unsafe { - assign_rwlock(&DIRECTION, MENU.sdi_state.get_random()); - } + assign_rwlock(&DIRECTION, get(&MENU).sdi_state.get_random()); } unsafe fn get_sdi_direction() -> Option<f64> { @@ -40,7 +38,7 @@ pub unsafe fn check_hit_stop_delay_command( if !is_training_mode() || !is_operation_cpu(module_accessor) { return original!()(module_accessor, sdi_direction); } - let repeat = MENU.sdi_strength.into_u32(); + let repeat = get(&MENU).sdi_strength.into_u32(); let mut counter_guard = lock_write_rwlock(&COUNTER); *counter_guard = (*counter_guard + 1) % repeat; if *counter_guard == repeat - 1 { diff --git a/src/training/shield.rs b/src/training/shield.rs index 3e1690e..3b0dedc 100644 --- a/src/training/shield.rs +++ b/src/training/shield.rs @@ -8,9 +8,10 @@ use smash::lua2cpp::L2CFighterCommon; use crate::common::consts::*; use crate::common::*; -use training_mod_sync::*; use crate::training::{frame_counter, input_record, mash, save_states}; +use training_mod_sync::*; + // TODO!() We only reset this on save state load or LRA reset // How many hits to hold shield until picking an Out Of Shield option static MULTI_HIT_OFFSET: RwLock<u32> = RwLock::new(0); @@ -43,16 +44,14 @@ fn should_pause_shield_decay() -> bool { } fn reset_oos_offset() { - unsafe { - /* - * Need to offset by 1, since we decrease as soon as shield gets hit - * but only check later if we can OOS - */ - assign_rwlock( - &MULTI_HIT_OFFSET, - MENU.oos_offset.get_random().into_delay() + 1, - ); - } + /* + * Need to offset by 1, since we decrease as soon as shield gets hit + * but only check later if we can OOS + */ + assign_rwlock( + &MULTI_HIT_OFFSET, + get(&MENU).oos_offset.get_random().into_delay() + 1, + ); } fn handle_oos_offset(module_accessor: &mut app::BattleObjectModuleAccessor) { @@ -70,9 +69,10 @@ fn handle_oos_offset(module_accessor: &mut app::BattleObjectModuleAccessor) { } // Roll shield delay - unsafe { - assign_rwlock(&SHIELD_DELAY, MENU.reaction_time.get_random().into_delay()); - } + assign_rwlock( + &SHIELD_DELAY, + get(&MENU).reaction_time.get_random().into_delay(), + ); // Decrease offset once if needed let mut multi_hit_offset_guard = lock_write_rwlock(&MULTI_HIT_OFFSET); @@ -116,7 +116,7 @@ pub unsafe fn get_param_float( return None; } - if MENU.shield_state != Shield::NONE { + if get(&MENU).shield_state != Shield::NONE { handle_oos_offset(module_accessor); } @@ -125,10 +125,7 @@ pub unsafe fn get_param_float( // Shield Decay//Recovery fn handle_shield_decay(param_type: u64, param_hash: u64) -> Option<f32> { - let menu_state; - unsafe { - menu_state = MENU.shield_state; - } + let menu_state = get(&MENU).shield_state; if menu_state != Shield::INFINITE && menu_state != Shield::CONSTANT @@ -166,7 +163,7 @@ pub unsafe fn param_installer() { *cached_shield_damage_mul_guard = Some(common_params.shield_damage_mul); } - if is_training_mode() && (MENU.shield_state == Shield::INFINITE) { + if is_training_mode() && (get(&MENU).shield_state == Shield::INFINITE) { // if you are in training mode and have infinite shield enabled, // set the game's shield_damage_mul to 0.0 common_params.shield_damage_mul = 0.0; @@ -190,10 +187,7 @@ pub fn should_hold_shield(module_accessor: &mut app::BattleObjectModuleAccessor) return true; } - let shield_state; - unsafe { - shield_state = &MENU.shield_state; - } + let shield_state = &get(&MENU).shield_state; // We should hold shield if the state requires it if unsafe { save_states::is_loading() } @@ -228,7 +222,7 @@ unsafe fn mod_handle_sub_guard_cont(fighter: &mut L2CFighterCommon) { } // Enable shield decay - if MENU.shield_state == Shield::HOLD { + if get(&MENU).shield_state == Shield::HOLD { set_shield_decay(true); } @@ -250,11 +244,11 @@ unsafe fn mod_handle_sub_guard_cont(fighter: &mut L2CFighterCommon) { return; } - if MENU.mash_triggers.contains(&MashTrigger::SHIELDSTUN) { - if MENU.shieldstun_override == Action::empty() { - mash::external_buffer_menu_mash(MENU.mash_state.get_random()) + if get(&MENU).mash_triggers.contains(&MashTrigger::SHIELDSTUN) { + if get(&MENU).shieldstun_override == Action::empty() { + mash::external_buffer_menu_mash(get(&MENU).mash_state.get_random()) } else { - mash::external_buffer_menu_mash(MENU.shieldstun_override.get_random()) + mash::external_buffer_menu_mash(get(&MENU).shieldstun_override.get_random()) } } @@ -360,10 +354,7 @@ fn needs_oos_handling_drop_shield() -> bool { } // Make sure we only flicker shield when Airdodge and Shield mash options are selected if action == Action::AIR_DODGE { - let shield_state; - unsafe { - shield_state = &MENU.shield_state; - } + let shield_state = &get(&MENU).shield_state; // If we're supposed to be holding shield, let airdodge make us drop shield if [Shield::HOLD, Shield::INFINITE, Shield::CONSTANT].contains(shield_state) { suspend_shield(Action::AIR_DODGE); @@ -373,10 +364,7 @@ fn needs_oos_handling_drop_shield() -> bool { // Make sure we only flicker shield when Airdodge and Shield mash options are selected if action == Action::AIR_DODGE { - let shield_state; - unsafe { - shield_state = &MENU.shield_state; - } + let shield_state = &get(&MENU).shield_state; // If we're supposed to be holding shield, let airdodge make us drop shield if [Shield::HOLD, Shield::INFINITE, Shield::CONSTANT].contains(shield_state) { suspend_shield(Action::AIR_DODGE); @@ -385,10 +373,7 @@ fn needs_oos_handling_drop_shield() -> bool { } if action == Action::SHIELD { - let shield_state; - unsafe { - shield_state = &MENU.shield_state; - } + let shield_state = &get(&MENU).shield_state; // Don't drop shield on shield hit if we're supposed to be holding shield if [Shield::HOLD, Shield::INFINITE, Shield::CONSTANT].contains(shield_state) { return false; diff --git a/src/training/shield_tilt.rs b/src/training/shield_tilt.rs index c7055dc..17b7828 100644 --- a/src/training/shield_tilt.rs +++ b/src/training/shield_tilt.rs @@ -7,24 +7,18 @@ use training_mod_sync::*; static SHIELD_STICK_DIRECTION: RwLock<Direction> = RwLock::new(Direction::OUT); pub fn roll_direction() { - unsafe { - assign_rwlock(&SHIELD_STICK_DIRECTION, MENU.shield_tilt.get_random()); - } + assign_rwlock(&SHIELD_STICK_DIRECTION, get(&MENU).shield_tilt.get_random()); } -pub unsafe fn mod_get_stick_x( - module_accessor: &mut app::BattleObjectModuleAccessor, -) -> Option<f32> { +pub fn mod_get_stick_x(module_accessor: &mut app::BattleObjectModuleAccessor) -> Option<f32> { get_angle(module_accessor).map(|a| a.cos() as f32) } -pub unsafe fn mod_get_stick_y( - module_accessor: &mut app::BattleObjectModuleAccessor, -) -> Option<f32> { +pub fn mod_get_stick_y(module_accessor: &mut app::BattleObjectModuleAccessor) -> Option<f32> { get_angle(module_accessor).map(|a| a.sin() as f32) } -unsafe fn get_angle(module_accessor: &mut app::BattleObjectModuleAccessor) -> Option<f64> { +fn get_angle(module_accessor: &mut app::BattleObjectModuleAccessor) -> Option<f64> { if !is_operation_cpu(module_accessor) { return None; } diff --git a/src/training/tech.rs b/src/training/tech.rs index 423bcee..25f247e 100644 --- a/src/training/tech.rs +++ b/src/training/tech.rs @@ -13,8 +13,8 @@ use crate::common::offsets::{ OFFSET_CHANGE_ACTIVE_CAMERA, OFFSET_SET_TRAINING_FIXED_CAMERA_VALUES, }; use crate::common::*; -use training_mod_sync::*; use crate::training::{frame_counter, mash, save_states}; +use training_mod_sync::*; static TECH_ROLL_DIRECTION: RwLock<Direction> = RwLock::new(Direction::empty()); static MISS_TECH_ROLL_DIRECTION: RwLock<Direction> = RwLock::new(Direction::empty()); @@ -63,7 +63,7 @@ unsafe fn mod_handle_change_status( .try_get_int() .unwrap_or(*FIGHTER_STATUS_KIND_WAIT as u64) as i32; - let state: TechFlags = MENU.tech_state.get_random(); + let state: TechFlags = get(&MENU).tech_state.get_random(); if handle_grnd_tech(module_accessor, status_kind, unk, status_kind_int, state) { return; @@ -125,11 +125,11 @@ unsafe fn handle_grnd_tech( } _ => false, }; - if do_tech && MENU.mash_triggers.contains(&MashTrigger::TECH) { - if MENU.tech_action_override == Action::empty() { - mash::external_buffer_menu_mash(MENU.mash_state.get_random()) + if do_tech && get(&MENU).mash_triggers.contains(&MashTrigger::TECH) { + if get(&MENU).tech_action_override == Action::empty() { + mash::external_buffer_menu_mash(get(&MENU).mash_state.get_random()) } else { - mash::external_buffer_menu_mash(MENU.tech_action_override.get_random()) + mash::external_buffer_menu_mash(get(&MENU).tech_action_override.get_random()) } } @@ -172,11 +172,11 @@ unsafe fn handle_wall_tech( } _ => false, }; - if do_tech && MENU.mash_triggers.contains(&MashTrigger::TECH) { - if MENU.tech_action_override == Action::empty() { - mash::external_buffer_menu_mash(MENU.mash_state.get_random()) + if do_tech && get(&MENU).mash_triggers.contains(&MashTrigger::TECH) { + if get(&MENU).tech_action_override == Action::empty() { + mash::external_buffer_menu_mash(get(&MENU).mash_state.get_random()) } else { - mash::external_buffer_menu_mash(MENU.tech_action_override.get_random()) + mash::external_buffer_menu_mash(get(&MENU).tech_action_override.get_random()) } } true @@ -207,18 +207,18 @@ unsafe fn handle_ceil_tech( *status_kind = FIGHTER_STATUS_KIND_PASSIVE_CEIL.as_lua_int(); *unk = LUA_TRUE; - if MENU.mash_triggers.contains(&MashTrigger::TECH) { - if MENU.tech_action_override == Action::empty() { - mash::external_buffer_menu_mash(MENU.mash_state.get_random()) + if get(&MENU).mash_triggers.contains(&MashTrigger::TECH) { + if get(&MENU).tech_action_override == Action::empty() { + mash::external_buffer_menu_mash(get(&MENU).mash_state.get_random()) } else { - mash::external_buffer_menu_mash(MENU.tech_action_override.get_random()) + mash::external_buffer_menu_mash(get(&MENU).tech_action_override.get_random()) } } true } pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAccessor) { - if !is_operation_cpu(module_accessor) || MENU.tech_state == TechFlags::empty() { + if !is_operation_cpu(module_accessor) || get(&MENU).tech_state == TechFlags::empty() { return; } @@ -231,7 +231,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces .contains(&status) { // Mistech - requested_status = match MENU.miss_tech_state.get_random() { + requested_status = match get(&MENU).miss_tech_state.get_random() { MissTechFlags::GETUP => *FIGHTER_STATUS_KIND_DOWN_STAND, MissTechFlags::ATTACK => *FIGHTER_STATUS_KIND_DOWN_STAND_ATTACK, MissTechFlags::ROLL_F => { @@ -250,7 +250,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces if frame_counter::should_delay(lockout_time, *FRAME_COUNTER) { return; }; - requested_status = match MENU.miss_tech_state.get_random() { + requested_status = match get(&MENU).miss_tech_state.get_random() { MissTechFlags::GETUP => *FIGHTER_STATUS_KIND_DOWN_STAND, MissTechFlags::ATTACK => *FIGHTER_STATUS_KIND_DOWN_STAND_ATTACK, MissTechFlags::ROLL_F => { @@ -265,7 +265,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces }; } else if status == *FIGHTER_STATUS_KIND_SLIP_WAIT { // Handle slips (like Diddy banana) - requested_status = match MENU.miss_tech_state.get_random() { + requested_status = match get(&MENU).miss_tech_state.get_random() { MissTechFlags::GETUP => *FIGHTER_STATUS_KIND_SLIP_STAND, MissTechFlags::ATTACK => *FIGHTER_STATUS_KIND_SLIP_STAND_ATTACK, MissTechFlags::ROLL_F => *FIGHTER_STATUS_KIND_SLIP_STAND_F, @@ -279,11 +279,11 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces if requested_status != 0 { StatusModule::change_status_force(module_accessor, requested_status, true); - if MENU.mash_triggers.contains(&MashTrigger::MISTECH) { - if MENU.tech_action_override == Action::empty() { - mash::external_buffer_menu_mash(MENU.mash_state.get_random()) + if get(&MENU).mash_triggers.contains(&MashTrigger::MISTECH) { + if get(&MENU).tech_action_override == Action::empty() { + mash::external_buffer_menu_mash(get(&MENU).mash_state.get_random()) } else { - mash::external_buffer_menu_mash(MENU.tech_action_override.get_random()) + mash::external_buffer_menu_mash(get(&MENU).tech_action_override.get_random()) } } } @@ -297,7 +297,7 @@ pub unsafe fn change_motion( return None; } - if MENU.tech_state == TechFlags::empty() { + if get(&MENU).tech_state == TechFlags::empty() { return None; } @@ -349,7 +349,7 @@ unsafe fn get_snake_laydown_lockout_time(module_accessor: &mut BattleObjectModul } pub unsafe fn hide_tech() { - if !is_training_mode() || MENU.tech_hide == OnOff::OFF { + if !is_training_mode() || get(&MENU).tech_hide == OnOff::OFF { return; } let module_accessor = get_module_accessor(FighterId::CPU); @@ -407,7 +407,7 @@ pub unsafe fn handle_fighter_req_quake_pos( return original!()(module_accessor, quake_kind); } let status = StatusModule::status_kind(module_accessor); - if status == FIGHTER_STATUS_KIND_DOWN && MENU.tech_hide == OnOff::ON { + if status == FIGHTER_STATUS_KIND_DOWN && get(&MENU).tech_hide == OnOff::ON { // We're hiding techs, prevent mistech quake from giving away missed tech return original!()(module_accessor, *CAMERA_QUAKE_KIND_NONE); } @@ -450,7 +450,7 @@ pub struct CameraManager { unsafe fn set_fixed_camera_values() { let camera_manager = get_camera_manager(); - if MENU.tech_hide == OnOff::OFF { + if get(&MENU).tech_hide == OnOff::OFF { // Use Stage's Default Values for fixed Camera camera_manager.fixed_camera_center = read_rwlock(&DEFAULT_FIXED_CAM_CENTER); } else { diff --git a/src/training/throw.rs b/src/training/throw.rs index baa7c65..65b8e0c 100644 --- a/src/training/throw.rs +++ b/src/training/throw.rs @@ -3,10 +3,9 @@ use smash::lib::lua_const::*; use crate::common::consts::*; use crate::common::*; -use training_mod_sync::*; use crate::training::frame_counter; use crate::training::mash; - +use training_mod_sync::*; const NOT_SET: u32 = 9001; static THROW_DELAY: RwLock<u32> = RwLock::new(NOT_SET); @@ -44,27 +43,27 @@ pub fn reset_throw_case() { fn roll_throw_delay() { if read_rwlock(&THROW_DELAY) == NOT_SET { // Only roll another throw delay if one is not already selected - unsafe { - assign_rwlock(&THROW_DELAY, MENU.throw_delay.get_random().into_meddelay()); - } + assign_rwlock( + &THROW_DELAY, + get(&MENU).throw_delay.get_random().into_meddelay(), + ); } } fn roll_pummel_delay() { if read_rwlock(&PUMMEL_DELAY) == NOT_SET { // Don't roll another pummel delay if one is already selected - unsafe { - assign_rwlock(&PUMMEL_DELAY, MENU.pummel_delay.get_random().into_meddelay()); - } + assign_rwlock( + &PUMMEL_DELAY, + get(&MENU).pummel_delay.get_random().into_meddelay(), + ); } } fn roll_throw_case() { if read_rwlock(&THROW_CASE) == ThrowOption::empty() { // Only re-roll if there is not already a throw option selected - unsafe { - assign_rwlock(&THROW_CASE, MENU.throw_state.get_random()); - } + assign_rwlock(&THROW_CASE, get(&MENU).throw_state.get_random()); } } @@ -113,7 +112,7 @@ pub unsafe fn get_command_flag_throw_direction( } // If no pummel delay is selected (default), then don't pummel - if MENU.pummel_delay == MedDelay::empty() { + if get(&MENU).pummel_delay == MedDelay::empty() { return 0; } @@ -132,7 +131,7 @@ pub unsafe fn get_command_flag_throw_direction( *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_THROW_HI, ) { let cmd = read_rwlock(&THROW_CASE).into_cmd().unwrap_or(0); - mash::external_buffer_menu_mash(MENU.mash_state.get_random()); + mash::external_buffer_menu_mash(get(&MENU).mash_state.get_random()); return cmd; } diff --git a/src/training/ui/input_log.rs b/src/training/ui/input_log.rs index 781e4b2..dccc49e 100644 --- a/src/training/ui/input_log.rs +++ b/src/training/ui/input_log.rs @@ -6,12 +6,12 @@ use training_mod_consts::{InputDisplay, MENU}; use crate::common::consts::status_display_name; use crate::menu::QUICK_MENU_ACTIVE; -use training_mod_sync::*; use crate::training::input_log::{ DirectionStrength, InputLog, DRAW_LOG_BASE_IDX, NUM_LOGS, P1_INPUT_LOGS, WHITE, YELLOW, }; use crate::training::ui::fade_out; use crate::training::ui::menu::VANILLA_MENU_ACTIVE; +use training_mod_sync::*; macro_rules! log_parent_fmt { ($x:ident) => { @@ -176,7 +176,7 @@ unsafe fn draw_log(root_pane: &Pane, log_idx: usize, log: &InputLog) { .as_textbox() .set_text_string(frame_text.as_str()); - let status_text = if MENU.input_display_status.as_bool() { + let status_text = if get(&MENU).input_display_status.as_bool() { status_display_name(log.fighter_kind, log.status) } else { "".to_string() @@ -195,9 +195,9 @@ pub unsafe fn draw(root_pane: &Pane) { logs_pane.set_visible( !read_rwlock(&QUICK_MENU_ACTIVE) && !read_rwlock(&VANILLA_MENU_ACTIVE) - && MENU.input_display != InputDisplay::NONE, + && get(&MENU).input_display != InputDisplay::NONE, ); - if MENU.input_display == InputDisplay::NONE { + if get(&MENU).input_display == InputDisplay::NONE { return; } diff --git a/src/training/ui/mod.rs b/src/training/ui/mod.rs index dd3026f..ea0a2eb 100644 --- a/src/training/ui/mod.rs +++ b/src/training/ui/mod.rs @@ -10,8 +10,8 @@ use crate::common::offsets::{OFFSET_DRAW, OFFSET_LAYOUT_ARC_MALLOC}; use crate::common::{is_ready_go, is_training_mode}; #[cfg(feature = "layout_arc_from_file")] use crate::consts::LAYOUT_ARC_PATH; -use training_mod_sync::*; use crate::training::frame_counter; +use training_mod_sync::*; mod damage; mod display; @@ -72,7 +72,7 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) { // InfluencedAlpha means "Should my children panes' alpha be influenced by mine, as the parent?" root_pane.flags |= 1 << PaneFlag::InfluencedAlpha as u8; - root_pane.set_visible(MENU.hud == OnOff::ON && !read_rwlock(&QUICK_MENU_ACTIVE)); + root_pane.set_visible(get(&MENU).hud == OnOff::ON && !read_rwlock(&QUICK_MENU_ACTIVE)); } damage::draw(root_pane, &layout_name); diff --git a/training_mod_consts/Cargo.toml b/training_mod_consts/Cargo.toml index e6d0480..87dee49 100644 --- a/training_mod_consts/Cargo.toml +++ b/training_mod_consts/Cargo.toml @@ -17,7 +17,8 @@ skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git" toml = "0.5.9" anyhow = "1.0.72" rand = { git = "https://github.com/skyline-rs/rand" } -training_mod_tui = { path = "../training_mod_tui"} +training_mod_sync = { path = "../training_mod_sync" } +training_mod_tui = { path = "../training_mod_tui" } [features] default = ["smash"] diff --git a/training_mod_consts/src/lib.rs b/training_mod_consts/src/lib.rs index 2add2e3..fa85630 100644 --- a/training_mod_consts/src/lib.rs +++ b/training_mod_consts/src/lib.rs @@ -12,6 +12,8 @@ pub mod config; pub use config::*; use paste::paste; + +use training_mod_sync::*; pub use training_mod_tui::*; pub const TOGGLE_MAX: u8 = 5; @@ -204,7 +206,7 @@ pub static DEFAULTS_MENU: TrainingModpackMenu = TrainingModpackMenu { lra_reset: OnOff::ON, }; -pub static mut MENU: TrainingModpackMenu = DEFAULTS_MENU; +pub static MENU: RwLock<TrainingModpackMenu> = RwLock::new(DEFAULTS_MENU); impl_toggletrait! { OnOff, diff --git a/training_mod_sync/src/lib.rs b/training_mod_sync/src/lib.rs index 941ded4..383600d 100644 --- a/training_mod_sync/src/lib.rs +++ b/training_mod_sync/src/lib.rs @@ -33,4 +33,9 @@ pub fn lock_write_rwlock<T>(rwlock: &RwLock<T>) -> RwLockWriteGuard<T> { /// Don't forget to drop the guard as soon as you're finished with it pub fn lock_read_rwlock<T>(rwlock: &RwLock<T>) -> RwLockReadGuard<T> { rwlock.read().unwrap() -} \ No newline at end of file +} + +/// Shorthand for read_rwlock +pub fn get<T: Copy>(rwlock: &RwLock<T>) -> T { + read_rwlock(rwlock) +}