From 8d8292ffc2c6f0f0d64462b73d84e75e855bb392 Mon Sep 17 00:00:00 2001 From: jugeeya Date: Thu, 24 Aug 2023 13:59:33 -0700 Subject: [PATCH] Frame Counter Refactor (#612) * Initial * Fixes and formatting * FIX FOR MENU --- src/common/button_config.rs | 3 +- src/common/menu.rs | 16 +++++--- src/training/buff.rs | 19 ++++------ src/training/combo.rs | 25 ++++++------ src/training/fast_fall.rs | 13 +++---- src/training/frame_counter.rs | 71 +++++++++++++++++++++++------------ src/training/ledge.rs | 16 ++++---- src/training/mash.rs | 16 ++++---- src/training/mod.rs | 10 +---- src/training/shield.rs | 15 +++----- src/training/tech.rs | 14 +++---- src/training/throw.rs | 25 ++++++------ src/training/ui/menu.rs | 13 ++----- src/training/ui/mod.rs | 6 ++- 14 files changed, 128 insertions(+), 134 deletions(-) diff --git a/src/common/button_config.rs b/src/common/button_config.rs index b4f6675..7a42ef1 100644 --- a/src/common/button_config.rs +++ b/src/common/button_config.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use crate::common::*; use crate::input::{ControllerStyle::*, *}; +use crate::training::frame_counter; use crate::training::ui::menu::VANILLA_MENU_ACTIVE; use lazy_static::lazy_static; @@ -136,7 +137,7 @@ pub fn handle_final_input_mapping(player_idx: i32, controller_struct: &mut SomeC let p1_controller = &mut *controller_struct.controller; let mut start_menu_request = false; - let menu_close_wait_frame = unsafe { *menu::VISUAL_FRAME_COUNTER.data_ptr() }; + let menu_close_wait_frame = frame_counter::get_frame_count(*menu::MENU_CLOSE_FRAME_COUNTER); if unsafe { MENU.menu_open_start_press == OnOff::On } { let start_hold_frames = &mut *START_HOLD_FRAMES.lock(); if p1_controller.current_buttons.plus() { diff --git a/src/common/menu.rs b/src/common/menu.rs index cbdd5f4..99d1560 100644 --- a/src/common/menu.rs +++ b/src/common/menu.rs @@ -1,3 +1,4 @@ +use once_cell::sync::Lazy; use std::collections::HashMap; use std::fs; @@ -13,6 +14,7 @@ use crate::consts::MENU_OPTIONS_PATH; use crate::events::{Event, EVENT_QUEUE}; use crate::input::*; use crate::logging::*; +use crate::training::frame_counter; pub const MENU_CLOSE_WAIT_FRAMES: u32 = 15; pub static mut QUICK_MENU_ACTIVE: bool = false; @@ -109,10 +111,11 @@ lazy_static! { (RUp, 0), ])) }; - pub static ref VISUAL_FRAME_COUNTER: Mutex = Mutex::new(0); - pub static ref VISUAL_FRAME_COUNTER_SHOULD_COUNT: Mutex = Mutex::new(false); } +pub static MENU_CLOSE_FRAME_COUNTER: Lazy = + Lazy::new(|| frame_counter::register_counter(frame_counter::FrameCounterType::Real)); + pub fn handle_final_input_mapping( player_idx: i32, controller_struct: &mut SomeControllerStruct, @@ -122,7 +125,7 @@ pub fn handle_final_input_mapping( if player_idx == 0 { let p1_controller = &mut *controller_struct.controller; *P1_CONTROLLER_STYLE.lock() = p1_controller.style; - let visual_frame_count = *VISUAL_FRAME_COUNTER.data_ptr(); + let visual_frame_count = frame_counter::get_frame_count(*MENU_CLOSE_FRAME_COUNTER); if visual_frame_count > 0 && visual_frame_count < MENU_CLOSE_WAIT_FRAMES { // If we just closed the menu, kill all inputs to avoid accidental presses *out = MappedInputs::empty(); @@ -131,7 +134,8 @@ pub fn handle_final_input_mapping( p1_controller.just_down = ButtonBitfield::default(); p1_controller.just_release = ButtonBitfield::default(); } else if visual_frame_count >= MENU_CLOSE_WAIT_FRAMES { - *VISUAL_FRAME_COUNTER_SHOULD_COUNT.lock() = false; + frame_counter::stop_counting(*MENU_CLOSE_FRAME_COUNTER); + frame_counter::reset_frame_count(*MENU_CLOSE_FRAME_COUNTER); } if QUICK_MENU_ACTIVE { @@ -190,7 +194,7 @@ pub fn handle_final_input_mapping( app.on_b() } else { // Leave menu. - *VISUAL_FRAME_COUNTER_SHOULD_COUNT.lock() = true; + frame_counter::start_counting(*MENU_CLOSE_FRAME_COUNTER); QUICK_MENU_ACTIVE = false; let menu_json = app.get_menu_selections(); set_menu_from_json(&menu_json); @@ -202,7 +206,7 @@ pub fn handle_final_input_mapping( .then(|| { received_input = true; // Leave menu. - *VISUAL_FRAME_COUNTER_SHOULD_COUNT.lock() = true; + frame_counter::start_counting(*MENU_CLOSE_FRAME_COUNTER); QUICK_MENU_ACTIVE = false; let menu_json = app.get_menu_selections(); set_menu_from_json(&menu_json); diff --git a/src/training/buff.rs b/src/training/buff.rs index 6a81aeb..afd8634 100644 --- a/src/training/buff.rs +++ b/src/training/buff.rs @@ -6,7 +6,7 @@ use crate::is_operation_cpu; use crate::training::frame_counter; use crate::training::handle_add_limit; -static mut BUFF_DELAY_COUNTER: usize = 0; +use once_cell::sync::Lazy; static mut BUFF_REMAINING_PLAYER: i32 = 0; static mut BUFF_REMAINING_CPU: i32 = 0; @@ -14,11 +14,8 @@ static mut BUFF_REMAINING_CPU: i32 = 0; static mut IS_BUFFING_PLAYER: bool = false; static mut IS_BUFFING_CPU: bool = false; -pub fn init() { - unsafe { - BUFF_DELAY_COUNTER = frame_counter::register_counter(); - } -} +static BUFF_DELAY_COUNTER: Lazy = + Lazy::new(|| frame_counter::register_counter(frame_counter::FrameCounterType::InGame)); pub unsafe fn restart_buff(module_accessor: &mut app::BattleObjectModuleAccessor) { if is_operation_cpu(module_accessor) { @@ -107,7 +104,7 @@ unsafe fn buff_hero(module_accessor: &mut app::BattleObjectModuleAccessor, statu } if get_buff_rem(module_accessor) <= 0 { // If there are no buffs selected/left, we're done - if frame_counter::should_delay(3_u32, BUFF_DELAY_COUNTER) { + if frame_counter::should_delay(3_u32, *BUFF_DELAY_COUNTER) { // Need to wait 3 frames to make sure we stop the spell SFX, since it's a bit delayed return false; } @@ -160,7 +157,7 @@ unsafe fn buff_cloud(module_accessor: &mut app::BattleObjectModuleAccessor) -> b start_buff(module_accessor); handle_add_limit(100.0, module_accessor, 0); } - if frame_counter::should_delay(2_u32, BUFF_DELAY_COUNTER) { + if frame_counter::should_delay(2_u32, *BUFF_DELAY_COUNTER) { // Need to wait 2 frames to make sure we stop the limit SFX, since it's a bit delayed return false; } @@ -175,7 +172,7 @@ unsafe fn buff_joker(module_accessor: &mut app::BattleObjectModuleAccessor) -> b // Strangely, this doesn't actually matter and works for both fighters app::FighterSpecializer_Jack::add_rebel_gauge(module_accessor, entry_id, 120.0); } - if frame_counter::should_delay(2_u32, BUFF_DELAY_COUNTER) { + if frame_counter::should_delay(2_u32, *BUFF_DELAY_COUNTER) { // Need to wait 2 frames to make sure we stop the voice call, since it's a bit delayed return false; } @@ -192,7 +189,7 @@ unsafe fn buff_mac(module_accessor: &mut app::BattleObjectModuleAccessor) -> boo *FIGHTER_LITTLEMAC_INSTANCE_WORK_ID_FLOAT_KO_GAGE, ); } - if frame_counter::should_delay(2_u32, BUFF_DELAY_COUNTER) { + if frame_counter::should_delay(2_u32, *BUFF_DELAY_COUNTER) { // Need to wait 2 frames to make sure we stop the KO sound, since it's a bit delayed return false; } @@ -242,7 +239,7 @@ unsafe fn buff_shulk(module_accessor: &mut app::BattleObjectModuleAccessor, stat start_buff(module_accessor); let prev_status_kind = StatusModule::prev_status_kind(module_accessor, 0); if prev_status_kind == FIGHTER_SHULK_STATUS_KIND_SPECIAL_N_ACTION { - if frame_counter::should_delay(3_u32, BUFF_DELAY_COUNTER) { + if frame_counter::should_delay(3_u32, *BUFF_DELAY_COUNTER) { // Need to continue to be buffing to make sure we stop "JUMP!" voice line return false; } diff --git a/src/training/combo.rs b/src/training/combo.rs index 1aed4f3..f440a90 100644 --- a/src/training/combo.rs +++ b/src/training/combo.rs @@ -5,6 +5,8 @@ use crate::common::consts::FighterId; use crate::common::*; use crate::training::*; +use once_cell::sync::Lazy; + pub static mut FRAME_ADVANTAGE: i32 = 0; static mut PLAYER_ACTIONABLE: bool = false; static mut CPU_ACTIONABLE: bool = false; @@ -12,13 +14,8 @@ static mut PLAYER_ACTIVE_FRAME: u32 = 0; static mut CPU_ACTIVE_FRAME: u32 = 0; static mut FRAME_ADVANTAGE_CHECK: bool = false; -static mut FRAME_COUNTER_INDEX: usize = 0; - -pub fn init() { - unsafe { - FRAME_COUNTER_INDEX = frame_counter::register_counter(); - } -} +static FRAME_COUNTER_INDEX: Lazy = + Lazy::new(|| frame_counter::register_counter(frame_counter::FrameCounterType::InGame)); unsafe fn _was_in_hitstun(module_accessor: *mut app::BattleObjectModuleAccessor) -> bool { let prev_status = StatusModule::prev_status_kind(module_accessor, 0); @@ -105,7 +102,7 @@ pub unsafe fn is_enable_transition_term( .any(|actionable_transition| *actionable_transition == transition_term)) || (CancelModule::is_enable_cancel(module_accessor))) { - PLAYER_ACTIVE_FRAME = frame_counter::get_frame_count(FRAME_COUNTER_INDEX); + PLAYER_ACTIVE_FRAME = frame_counter::get_frame_count(*FRAME_COUNTER_INDEX); PLAYER_ACTIONABLE = true; // if both are now active @@ -117,7 +114,7 @@ pub unsafe fn is_enable_transition_term( ); } - frame_counter::stop_counting(FRAME_COUNTER_INDEX); + frame_counter::stop_counting(*FRAME_COUNTER_INDEX); FRAME_ADVANTAGE_CHECK = false; } } @@ -141,11 +138,11 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModule // the frame the fighter *becomes* actionable if !CPU_ACTIONABLE && is_actionable(cpu_module_accessor) { - CPU_ACTIVE_FRAME = frame_counter::get_frame_count(FRAME_COUNTER_INDEX); + CPU_ACTIVE_FRAME = frame_counter::get_frame_count(*FRAME_COUNTER_INDEX); } if !PLAYER_ACTIONABLE && is_actionable(player_module_accessor) { - PLAYER_ACTIVE_FRAME = frame_counter::get_frame_count(FRAME_COUNTER_INDEX); + PLAYER_ACTIVE_FRAME = frame_counter::get_frame_count(*FRAME_COUNTER_INDEX); } CPU_ACTIONABLE = is_actionable(cpu_module_accessor); @@ -154,8 +151,8 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModule // if neither are active if !CPU_ACTIONABLE && !PLAYER_ACTIONABLE { if !FRAME_ADVANTAGE_CHECK { - frame_counter::reset_frame_count(FRAME_COUNTER_INDEX); - frame_counter::start_counting(FRAME_COUNTER_INDEX); + frame_counter::reset_frame_count(*FRAME_COUNTER_INDEX); + frame_counter::start_counting(*FRAME_COUNTER_INDEX); } FRAME_ADVANTAGE_CHECK = true; } @@ -166,7 +163,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModule update_frame_advantage((CPU_ACTIVE_FRAME as i64 - PLAYER_ACTIVE_FRAME as i64) as i32); } - frame_counter::stop_counting(FRAME_COUNTER_INDEX); + frame_counter::stop_counting(*FRAME_COUNTER_INDEX); FRAME_ADVANTAGE_CHECK = false; } } diff --git a/src/training/fast_fall.rs b/src/training/fast_fall.rs index c8f3a4a..fd90437 100644 --- a/src/training/fast_fall.rs +++ b/src/training/fast_fall.rs @@ -5,7 +5,7 @@ use smash::phx::{Hash40, Vector3f}; use crate::common::*; use crate::training::{frame_counter, input_record}; -static mut FRAME_COUNTER: usize = 0; +use once_cell::sync::Lazy; // The current fastfall delay static mut DELAY: u32 = 0; @@ -22,11 +22,8 @@ pub fn roll_fast_fall() { } } -pub fn init() { - unsafe { - FRAME_COUNTER = frame_counter::register_counter(); - } -} +static FRAME_COUNTER_INDEX: Lazy = + Lazy::new(|| frame_counter::register_counter(frame_counter::FrameCounterType::InGame)); pub fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModuleAccessor) { if !should_fast_fall() { @@ -46,7 +43,7 @@ pub fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModuleAccesso if !is_falling(module_accessor) { // Roll FF delay DELAY = MENU.fast_fall_delay.get_random().into_delay(); - frame_counter::full_reset(FRAME_COUNTER); + frame_counter::full_reset(*FRAME_COUNTER_INDEX); return; } @@ -60,7 +57,7 @@ pub fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModuleAccesso } // Check delay - if frame_counter::should_delay(DELAY, FRAME_COUNTER) { + if frame_counter::should_delay(DELAY, *FRAME_COUNTER_INDEX) { return; } diff --git a/src/training/frame_counter.rs b/src/training/frame_counter.rs index ca80e7c..a34ba6d 100644 --- a/src/training/frame_counter.rs +++ b/src/training/frame_counter.rs @@ -1,42 +1,49 @@ -static mut SHOULD_COUNT: Vec = vec![]; -static mut NO_RESET: Vec = vec![]; -static mut COUNTERS: Vec = vec![]; +#[derive(PartialEq, Eq)] +pub enum FrameCounterType { + InGame, + // "Reset" occurs when we enter training mode and when we run L+R+A or save state load + // Some frame counters need in-game frames that do not reset when this occurs + InGameNoReset, + Real, +} -fn _register_counter(no_reset: bool) -> usize { +pub struct FrameCounter { + count: u32, + should_count: bool, + counter_type: FrameCounterType, +} + +static mut COUNTERS: Vec = vec![]; + +pub fn register_counter(counter_type: FrameCounterType) -> usize { unsafe { let index = COUNTERS.len(); - COUNTERS.push(0); - SHOULD_COUNT.push(false); - NO_RESET.push(no_reset); + COUNTERS.push(FrameCounter { + count: 0, + should_count: false, + counter_type, + }); index } } -pub fn _register_counter_no_reset() -> usize { - _register_counter(true) -} - -pub fn register_counter() -> usize { - _register_counter(false) -} - pub fn start_counting(index: usize) { unsafe { - SHOULD_COUNT[index] = true; + COUNTERS[index].should_count = true; } } pub fn stop_counting(index: usize) { unsafe { - SHOULD_COUNT[index] = false; + COUNTERS[index].should_count = false; } } pub fn reset_frame_count(index: usize) { unsafe { - COUNTERS[index] = 0; + COUNTERS[index].count = 0; } } @@ -68,19 +75,33 @@ pub fn should_delay(delay: u32, index: usize) -> bool { } pub fn get_frame_count(index: usize) -> u32 { - unsafe { COUNTERS[index] } + unsafe { COUNTERS[index].count } } pub fn tick_idx(index: usize) { unsafe { - COUNTERS[index] += 1; + COUNTERS[index].count += 1; } } -pub fn tick() { +pub fn tick_ingame() { unsafe { - for (index, _frame) in COUNTERS.iter().enumerate() { - if !SHOULD_COUNT[index] { + for (index, counter) in COUNTERS.iter().enumerate() { + if !counter.should_count || counter.counter_type == FrameCounterType::Real { + continue; + } + tick_idx(index); + } + } +} + +pub fn tick_real() { + unsafe { + for (index, counter) in COUNTERS.iter().enumerate() { + if !counter.should_count + || (counter.counter_type == FrameCounterType::InGame + || counter.counter_type == FrameCounterType::InGameNoReset) + { continue; } tick_idx(index); @@ -90,8 +111,8 @@ pub fn tick() { pub fn reset_all() { unsafe { - for (index, _frame) in COUNTERS.iter().enumerate() { - if NO_RESET[index] { + for (index, counter) in COUNTERS.iter().enumerate() { + if counter.counter_type != FrameCounterType::InGame { continue; } full_reset(index); diff --git a/src/training/ledge.rs b/src/training/ledge.rs index 1b7a565..af61b7c 100644 --- a/src/training/ledge.rs +++ b/src/training/ledge.rs @@ -5,22 +5,20 @@ use crate::common::consts::*; use crate::common::*; use crate::training::{frame_counter, input_record, mash}; +use once_cell::sync::Lazy; + const NOT_SET: u32 = 9001; static mut LEDGE_DELAY: u32 = NOT_SET; -static mut LEDGE_DELAY_COUNTER: usize = 0; static mut LEDGE_CASE: LedgeOption = LedgeOption::empty(); -pub fn init() { - unsafe { - LEDGE_DELAY_COUNTER = frame_counter::register_counter(); - } -} +static LEDGE_DELAY_COUNTER: Lazy = + Lazy::new(|| frame_counter::register_counter(frame_counter::FrameCounterType::InGame)); pub fn reset_ledge_delay() { unsafe { if LEDGE_DELAY != NOT_SET { LEDGE_DELAY = NOT_SET; - frame_counter::full_reset(LEDGE_DELAY_COUNTER); + frame_counter::full_reset(*LEDGE_DELAY_COUNTER); } } } @@ -154,7 +152,7 @@ pub unsafe fn force_option(module_accessor: &mut app::BattleObjectModuleAccessor return; } - if frame_counter::should_delay(LEDGE_DELAY, LEDGE_DELAY_COUNTER) { + if frame_counter::should_delay(LEDGE_DELAY, *LEDGE_DELAY_COUNTER) { // Not yet time to perform the ledge action return; } @@ -189,7 +187,7 @@ pub unsafe fn is_enable_transition_term( // Disallow the default cliff-climb if we are waiting or we didn't get up during a recording if term == *FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_CLIFF_CLIMB && ((LEDGE_CASE == LedgeOption::WAIT - || frame_counter::get_frame_count(LEDGE_DELAY_COUNTER) < LEDGE_DELAY) + || frame_counter::get_frame_count(*LEDGE_DELAY_COUNTER) < LEDGE_DELAY) || (LEDGE_CASE.is_playback() && !input_record::is_playback())) { return Some(false); diff --git a/src/training/mash.rs b/src/training/mash.rs index 6f3c116..d1d63b0 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 once_cell::sync::Lazy; + const DISTANCE_CLOSE_THRESHOLD: f32 = 16.0; const DISTANCE_MID_THRESHOLD: f32 = 37.0; const DISTANCE_FAR_THRESHOLD: f32 = 64.0; @@ -20,9 +22,11 @@ static mut QUEUE: Vec = vec![]; static mut FALLING_AERIAL: bool = false; -static mut AERIAL_DELAY_COUNTER: usize = 0; static mut AERIAL_DELAY: u32 = 0; +static AERIAL_DELAY_COUNTER: Lazy = + Lazy::new(|| frame_counter::register_counter(frame_counter::FrameCounterType::InGame)); + // Track if we're about to do another command flag cat run in the same frame for a dash or dash attack static mut IS_TRANSITIONING_DASH: bool = false; @@ -138,7 +142,7 @@ pub fn reset() { shield::suspend_shield(get_current_buffer()); unsafe { - frame_counter::full_reset(AERIAL_DELAY_COUNTER); + frame_counter::full_reset(*AERIAL_DELAY_COUNTER); AERIAL_DELAY = 0; } } @@ -577,12 +581,6 @@ unsafe fn get_aerial_flag( flag } -pub fn init() { - unsafe { - AERIAL_DELAY_COUNTER = frame_counter::register_counter(); - } -} - fn roll_aerial_delay(action: Action) { if !shield::is_aerial(action) { return; @@ -609,7 +607,7 @@ fn should_delay_aerial(module_accessor: &mut app::BattleObjectModuleAccessor) -> return true; } - frame_counter::should_delay(AERIAL_DELAY, AERIAL_DELAY_COUNTER) + frame_counter::should_delay(AERIAL_DELAY, *AERIAL_DELAY_COUNTER) } } diff --git a/src/training/mod.rs b/src/training/mod.rs index 783f1d7..955e6da 100644 --- a/src/training/mod.rs +++ b/src/training/mod.rs @@ -676,7 +676,7 @@ static OPCF_OFFSET: usize = 0x06b7fdc; // One instruction after the CPU Control function completes #[skyline::hook(offset = OPCF_OFFSET, inline)] unsafe fn handle_once_per_cpu_frame(_ctx: &mut InlineCtx) { - frame_counter::tick(); + frame_counter::tick_ingame(); // Tick notifications let queue = &mut ui::notifications::QUEUE; let notification = queue.first(); @@ -806,15 +806,7 @@ pub fn training_mods() { handle_final_input_mapping ); - combo::init(); - shield::init(); - fast_fall::init(); - mash::init(); - ledge::init(); - throw::init(); - buff::init(); items::init(); - tech::init(); input_record::init(); ui::init(); } diff --git a/src/training/shield.rs b/src/training/shield.rs index 1d906ea..5aec36a 100644 --- a/src/training/shield.rs +++ b/src/training/shield.rs @@ -10,6 +10,8 @@ use crate::common::consts::*; use crate::common::*; use crate::training::{frame_counter, input_record, mash, save_states}; +use once_cell::sync::Lazy; + // How many hits to hold shield until picking an Out Of Shield option static mut MULTI_HIT_OFFSET: u32 = 0; @@ -19,16 +21,11 @@ static mut SHIELD_DELAY: u32 = 0; // Used to only decrease once per shieldstun change static mut WAS_IN_SHIELDSTUN: bool = false; -static mut REACTION_INDEX: usize = 0; - // For how many frames should the shield hold be overwritten static mut SUSPEND_SHIELD: bool = false; -pub fn init() { - unsafe { - REACTION_INDEX = frame_counter::register_counter(); - } -} +static REACTION_COUNTER_INDEX: Lazy = + Lazy::new(|| frame_counter::register_counter(frame_counter::FrameCounterType::InGame)); // Toggle for shield decay static mut SHIELD_DECAY: bool = false; @@ -236,11 +233,11 @@ unsafe fn mod_handle_sub_guard_cont(fighter: &mut L2CFighterCommon) { } if !is_shielding(module_accessor) { - frame_counter::full_reset(REACTION_INDEX); + frame_counter::full_reset(*REACTION_COUNTER_INDEX); return; } - if frame_counter::should_delay(SHIELD_DELAY, REACTION_INDEX) { + if frame_counter::should_delay(SHIELD_DELAY, *REACTION_COUNTER_INDEX) { return; } diff --git a/src/training/tech.rs b/src/training/tech.rs index 3ec39f2..0185181 100644 --- a/src/training/tech.rs +++ b/src/training/tech.rs @@ -8,15 +8,13 @@ use crate::common::consts::*; use crate::common::*; use crate::training::{frame_counter, mash}; +use once_cell::sync::Lazy; + static mut TECH_ROLL_DIRECTION: Direction = Direction::empty(); static mut MISS_TECH_ROLL_DIRECTION: Direction = Direction::empty(); -static mut FRAME_COUNTER: usize = 0; -pub fn init() { - unsafe { - FRAME_COUNTER = frame_counter::register_counter(); - } -} +static FRAME_COUNTER: Lazy = + Lazy::new(|| frame_counter::register_counter(frame_counter::FrameCounterType::InGame)); unsafe fn is_enable_passive(module_accessor: &mut BattleObjectModuleAccessor) -> bool { let fighter = get_fighter_common_from_accessor(module_accessor); @@ -237,7 +235,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces } else if status == *FIGHTER_STATUS_KIND_LAY_DOWN { // Snake down throw let lockout_time = get_snake_laydown_lockout_time(module_accessor); - if frame_counter::should_delay(lockout_time, FRAME_COUNTER) { + if frame_counter::should_delay(lockout_time, *FRAME_COUNTER) { return; }; requested_status = match MENU.miss_tech_state.get_random() { @@ -264,7 +262,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAcces }; } else { // Not in a tech situation, make sure the snake dthrow counter is fully reset. - frame_counter::full_reset(FRAME_COUNTER); + frame_counter::full_reset(*FRAME_COUNTER); }; if requested_status != 0 { diff --git a/src/training/throw.rs b/src/training/throw.rs index c5e09bb..159fb5c 100644 --- a/src/training/throw.rs +++ b/src/training/throw.rs @@ -6,20 +6,17 @@ use crate::common::*; use crate::training::frame_counter; use crate::training::mash; +use once_cell::sync::Lazy; + const NOT_SET: u32 = 9001; static mut THROW_DELAY: u32 = NOT_SET; -static mut THROW_DELAY_COUNTER: usize = 0; +static mut PUMMEL_DELAY: u32 = NOT_SET; static mut THROW_CASE: ThrowOption = ThrowOption::empty(); -static mut PUMMEL_DELAY: u32 = NOT_SET; -static mut PUMMEL_DELAY_COUNTER: usize = 0; - -pub fn init() { - unsafe { - THROW_DELAY_COUNTER = frame_counter::register_counter(); - PUMMEL_DELAY_COUNTER = frame_counter::register_counter(); - } -} +static THROW_DELAY_COUNTER: Lazy = + Lazy::new(|| frame_counter::register_counter(frame_counter::FrameCounterType::InGame)); +static PUMMEL_DELAY_COUNTER: Lazy = + Lazy::new(|| frame_counter::register_counter(frame_counter::FrameCounterType::InGame)); // Rolling Throw Delays and Pummel Delays separately @@ -27,7 +24,7 @@ pub fn reset_throw_delay() { unsafe { if THROW_DELAY != NOT_SET { THROW_DELAY = NOT_SET; - frame_counter::full_reset(THROW_DELAY_COUNTER); + frame_counter::full_reset(*THROW_DELAY_COUNTER); } } } @@ -36,7 +33,7 @@ pub fn reset_pummel_delay() { unsafe { if PUMMEL_DELAY != NOT_SET { PUMMEL_DELAY = NOT_SET; - frame_counter::full_reset(PUMMEL_DELAY_COUNTER); + frame_counter::full_reset(*PUMMEL_DELAY_COUNTER); } } } @@ -120,9 +117,9 @@ pub unsafe fn get_command_flag_throw_direction( return 0; } - if frame_counter::should_delay(THROW_DELAY, THROW_DELAY_COUNTER) { + if frame_counter::should_delay(THROW_DELAY, *THROW_DELAY_COUNTER) { // Not yet time to perform the throw action - if frame_counter::should_delay(PUMMEL_DELAY, PUMMEL_DELAY_COUNTER) { + if frame_counter::should_delay(PUMMEL_DELAY, *PUMMEL_DELAY_COUNTER) { // And not yet time to pummel either, so don't do anything return 0; } diff --git a/src/training/ui/menu.rs b/src/training/ui/menu.rs index b04d191..22a2d69 100644 --- a/src/training/ui/menu.rs +++ b/src/training/ui/menu.rs @@ -6,9 +6,8 @@ use smash::ui2d::{SmashPane, SmashTextBox}; use training_mod_tui::gauge::GaugeState; use training_mod_tui::{App, AppPage, NUM_LISTS}; -use crate::common::menu::{ - MENU_CLOSE_WAIT_FRAMES, VISUAL_FRAME_COUNTER, VISUAL_FRAME_COUNTER_SHOULD_COUNT, -}; +use crate::common::menu::{MENU_CLOSE_FRAME_COUNTER, MENU_CLOSE_WAIT_FRAMES}; +use crate::training::frame_counter; use crate::{common, common::menu::QUICK_MENU_ACTIVE, input::*}; use super::fade_out; @@ -353,12 +352,6 @@ unsafe fn render_slider_page(app: &App, root_pane: &Pane) { } pub unsafe fn draw(root_pane: &Pane) { - if *VISUAL_FRAME_COUNTER_SHOULD_COUNT.data_ptr() { - *VISUAL_FRAME_COUNTER.lock() += 1; - } else { - *VISUAL_FRAME_COUNTER.lock() = 0; - } - // Determine if we're in the menu by seeing if the "help" footer has // begun moving upward. It starts at -80 and moves to 0 over 10 frames // in info_training_in_menu.bflan @@ -381,7 +374,7 @@ pub unsafe fn draw(root_pane: &Pane) { let overall_parent_pane = root_pane.find_pane_by_name_recursive("TrModMenu").unwrap(); overall_parent_pane.set_visible(true); - let menu_close_wait_frame = *VISUAL_FRAME_COUNTER.data_ptr(); + let menu_close_wait_frame = frame_counter::get_frame_count(*MENU_CLOSE_FRAME_COUNTER); if QUICK_MENU_ACTIVE { overall_parent_pane.alpha = 255; overall_parent_pane.global_alpha = 255; diff --git a/src/training/ui/mod.rs b/src/training/ui/mod.rs index 7a8414f..b00e413 100644 --- a/src/training/ui/mod.rs +++ b/src/training/ui/mod.rs @@ -4,9 +4,12 @@ use sarc::SarcFile; use skyline::nn::ui2d::*; use training_mod_consts::{OnOff, MENU}; -use crate::common::{is_ready_go, is_training_mode, menu::QUICK_MENU_ACTIVE}; #[cfg(feature = "layout_arc_from_file")] use crate::consts::LAYOUT_ARC_PATH; +use crate::{ + common::{is_ready_go, is_training_mode, menu::QUICK_MENU_ACTIVE}, + training::frame_counter, +}; mod damage; mod display; @@ -56,6 +59,7 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) damage::draw(root_pane, &layout_name); if layout_name == "info_training" { + frame_counter::tick_real(); display::draw(root_pane); menu::draw(root_pane); }