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