From 271121c01e32764304eda64af23a2d049547cef1 Mon Sep 17 00:00:00 2001 From: asimon-1 <40246417+asimon-1@users.noreply.github.com> Date: Thu, 23 Oct 2025 18:01:36 -0400 Subject: [PATCH 1/8] Don't unwrap on try_get_module_accessor --- src/common/menu.rs | 3 ++- src/common/mod.rs | 13 ++++++------- src/lib.rs | 2 +- src/training/character_specific/items.rs | 12 ++++++++---- src/training/charge.rs | 8 +++++--- src/training/combo.rs | 8 +++++--- src/training/directional_influence.rs | 6 ++++-- src/training/input_record.rs | 19 +++++++++++-------- src/training/mod.rs | 8 +++++--- src/training/save_states.rs | 11 +++++++---- src/training/tech.rs | 3 ++- 11 files changed, 56 insertions(+), 37 deletions(-) diff --git a/src/common/menu.rs b/src/common/menu.rs index ecb5e6e30..1ccdaeca3 100644 --- a/src/common/menu.rs +++ b/src/common/menu.rs @@ -67,7 +67,8 @@ pub fn set_menu_from_json(message: &str) { std::thread::spawn(move || { fs::write( MENU_OPTIONS_PATH, - serde_json::to_string_pretty(&message_json).unwrap(), + serde_json::to_string_pretty(&message_json) + .expect("Could not serialize menu settings"), ) .expect("Failed to write menu settings file"); }); diff --git a/src/common/mod.rs b/src/common/mod.rs index 1d855a26a..fe6ac91ef 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -63,10 +63,6 @@ pub unsafe fn try_get_battle_object(battle_object_id: u32) -> Option<&'static ap battle_object_ptr.as_ref() } -pub fn get_module_accessor(fighter_id: FighterId) -> *mut app::BattleObjectModuleAccessor { - try_get_module_accessor(fighter_id).unwrap() -} - pub fn try_get_module_accessor( fighter_id: FighterId, ) -> Option<*mut app::BattleObjectModuleAccessor> { @@ -278,7 +274,8 @@ pub unsafe fn entry_count() -> i32 { } pub unsafe fn get_player_dmg_digits(p: FighterId) -> (u8, u8, u8, u8) { - let module_accessor = get_module_accessor(p); + let module_accessor = + try_get_module_accessor(p).expect("Could not get module accessor in get_player_dmg_digits"); let dmg = DamageModule::damage(module_accessor, 0); let hundreds = dmg as u16 / 100; let tens = (dmg as u16 - hundreds * 100) / 10; @@ -288,11 +285,13 @@ pub unsafe fn get_player_dmg_digits(p: FighterId) -> (u8, u8, u8, u8) { } pub unsafe fn get_fighter_distance() -> f32 { - let player_module_accessor = get_module_accessor(FighterId::Player); + let player_module_accessor = try_get_module_accessor(FighterId::Player) + .expect("Could not get player_module_accessor in get_fighter_distance"); if StatusModule::status_kind(player_module_accessor) == *FIGHTER_STATUS_KIND_NONE { return f32::MAX; } - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module_accessor in get_fighter_distance"); let player_pos = *PostureModule::pos(player_module_accessor); let cpu_pos = *PostureModule::pos(cpu_module_accessor); app::sv_math::vec3_distance( diff --git a/src/lib.rs b/src/lib.rs index d24478438..253d281dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,7 +81,7 @@ pub fn main() { &complete_error_message, ); })); - init_logger().unwrap(); + init_logger().expect("Could not initialize logger"); info!("Initialized."); diff --git a/src/training/character_specific/items.rs b/src/training/character_specific/items.rs index 9cce1da25..f5636cd59 100644 --- a/src/training/character_specific/items.rs +++ b/src/training/character_specific/items.rs @@ -331,8 +331,10 @@ pub const ALL_CHAR_ITEMS: [CharItem; 45] = [ ]; unsafe fn apply_single_item(player_fighter_kind: i32, item: &CharItem) { - let player_module_accessor = get_module_accessor(FighterId::Player); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let player_module_accessor = try_get_module_accessor(FighterId::Player) + .expect("Could not get player module accessor in apply_single_item"); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in apply_single_item"); // Now we make sure the module_accessor we use to generate the item/article is the correct character let generator_module_accessor = if item.fighter_kind == player_fighter_kind { player_module_accessor @@ -446,8 +448,10 @@ unsafe fn apply_single_item(player_fighter_kind: i32, item: &CharItem) { } pub unsafe fn apply_item(character_item: CharacterItem) { - let player_module_accessor = get_module_accessor(FighterId::Player); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let player_module_accessor = try_get_module_accessor(FighterId::Player) + .expect("Could not get player module accessor in apply_item"); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in apply_item"); let player_fighter_kind = app::utility::get_kind(&mut *player_module_accessor); let cpu_fighter_kind = app::utility::get_kind(&mut *cpu_module_accessor); let character_item_num = character_item.as_idx(); diff --git a/src/training/charge.rs b/src/training/charge.rs index bcb6b624d..9d5e79f97 100644 --- a/src/training/charge.rs +++ b/src/training/charge.rs @@ -1,6 +1,6 @@ use crate::common::consts::FighterId; use crate::common::offsets::OFFSET_COPY_SETUP; -use crate::common::{get_module_accessor, try_get_battle_object}; +use crate::common::{try_get_battle_object, try_get_module_accessor}; use crate::training::character_specific::{kirby, pikmin}; use serde::{Deserialize, Serialize}; use smash::app::{self, lua_bind::*, ArticleOperationTarget, FighterFacial, FighterUtil}; @@ -497,8 +497,10 @@ pub unsafe fn handle_charge( // Kirby Copy Abilities else if fighter_kind == FIGHTER_KIND_KIRBY { charge.has_charge.map(|_has_copy_ability| { - let cpu_module_accessor = &mut *get_module_accessor(FighterId::CPU); - let player_module_accessor = &mut *get_module_accessor(FighterId::Player); + let cpu_module_accessor = &mut *try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor for Kirby copy ability charge setup"); + let player_module_accessor = &mut *try_get_module_accessor(FighterId::Player) + .expect("Could not get Player module accessor for Kirby copy ability charge setup"); let opponent_module_accessor: &mut app::BattleObjectModuleAccessor = if ptr::eq(module_accessor, player_module_accessor) { cpu_module_accessor diff --git a/src/training/combo.rs b/src/training/combo.rs index 7b5c8e877..3819b7761 100644 --- a/src/training/combo.rs +++ b/src/training/combo.rs @@ -4,9 +4,9 @@ use smash::app::BattleObjectModuleAccessor; use smash::lib::lua_const::*; use crate::consts::Action; -use crate::get_module_accessor; use crate::training::frame_counter; use crate::training::ui::notifications; +use crate::try_get_module_accessor; use training_mod_consts::{FighterId, OnOff, MENU}; use training_mod_sync::*; @@ -91,8 +91,10 @@ pub unsafe fn once_per_frame(module_accessor: &mut BattleObjectModuleAccessor) { if entry_id_int != (FighterId::Player as i32) { return; } - let player_module_accessor = get_module_accessor(FighterId::Player); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let player_module_accessor = try_get_module_accessor(FighterId::Player) + .expect("Could not get player module accessor in once_per_frame"); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in once_per_frame"); let player_is_actionable = is_actionable(player_module_accessor); let player_was_actionable = read(&PLAYER_WAS_ACTIONABLE); let player_just_actionable = !player_was_actionable && player_is_actionable; diff --git a/src/training/directional_influence.rs b/src/training/directional_influence.rs index 1c0322314..740399c35 100644 --- a/src/training/directional_influence.rs +++ b/src/training/directional_influence.rs @@ -69,8 +69,10 @@ unsafe fn mod_handle_di(fighter: &L2CFighterCommon, _arg1: L2CValue) { } pub fn should_reverse_angle(direction: Direction) -> bool { - let cpu_module_accessor = get_module_accessor(FighterId::CPU); - let player_module_accessor = get_module_accessor(FighterId::Player); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in should_reverse_angle"); + let player_module_accessor = try_get_module_accessor(FighterId::Player) + .expect("Could not get player module accessor in should_reverse_angle"); unsafe { PostureModule::pos_x(player_module_accessor) > PostureModule::pos_x(cpu_module_accessor) && ![Direction::LEFT, Direction::RIGHT].contains(&direction) diff --git a/src/training/input_record.rs b/src/training/input_record.rs index b056a7bd9..201278c73 100644 --- a/src/training/input_record.rs +++ b/src/training/input_record.rs @@ -11,9 +11,7 @@ use crate::common::consts::{FighterId, HitstunPlayback, OnOff, RecordTrigger}; use crate::common::input::*; use crate::common::offsets::OFFSET_SET_CPU_CONTROLS; use crate::common::{button_config, is_training_mode}; -use crate::common::{ - get_module_accessor, is_in_hitstun, is_in_shieldstun, try_get_module_accessor, MENU, -}; +use crate::common::{is_in_hitstun, is_in_shieldstun, try_get_module_accessor, MENU}; use crate::training::mash; use crate::training::ui::notifications::{clear_notification, color_notification}; use crate::{error, warn}; @@ -93,7 +91,8 @@ unsafe fn should_mash_playback() { return; } let mut should_playback = false; - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in should_mash_playback"); // depending on our current status, we want to wait for different timings to begin playback // TODO: This isn't the best way to write this I'm sure, want to rewrite @@ -330,7 +329,8 @@ unsafe fn handle_recording_for_fighter(module_accessor: &mut BattleObjectModuleA } pub unsafe fn lockout_record() { - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in lockout_record"); let recording_duration = read(&MENU).recording_duration.into_frames(); let current_record_slot = read(&CURRENT_RECORD_SLOT); let mut p1_final_mapping = lock_write(&P1_FINAL_MAPPING); @@ -361,7 +361,8 @@ pub unsafe fn playback(slot: Option) -> bool { return false; } let slot = slot.unwrap(); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in playback"); let frame_length = read(&P1_FRAME_LENGTH_MAPPING)[slot]; assign(&CURRENT_FRAME_LENGTH, frame_length); assign(&CURRENT_PLAYBACK_SLOT, slot); @@ -381,7 +382,8 @@ pub unsafe fn playback_ledge(slot: Option) { *buffer_frame = 5; // So we can make sure the option is buffered and won't get ledge trumped if delay is 0 // drop down from ledge can't be buffered on the same frame as jump/attack/roll/ngu so we have to do this // Need to buffer 1 less frame for non-lassos - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in playback_ledge"); let status_kind = StatusModule::status_kind(cpu_module_accessor); if status_kind == *FIGHTER_STATUS_KIND_CLIFF_CATCH { *buffer_frame -= 1; @@ -435,7 +437,8 @@ pub unsafe fn handle_final_input_mapping(player_idx: i32, out: *mut MappedInputs if *input_record_frame == 1 { // We're on the second frame of recording, grabbing the status should give us the status that resulted from the first frame of input // We'll want to save this status so that we use the correct TRANSITION TERM for hitstun cancelling out of damage fly - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in handle_final_input_mapping"); assign( &STARTING_STATUS, StatusModule::status_kind(cpu_module_accessor), diff --git a/src/training/mod.rs b/src/training/mod.rs index edcd22892..50707888a 100644 --- a/src/training/mod.rs +++ b/src/training/mod.rs @@ -4,7 +4,7 @@ use crate::common::button_config; use crate::common::consts::{BuffOption, FighterId, MENU}; use crate::common::offsets::*; use crate::common::{ - dev_config, get_module_accessor, is_operation_cpu, is_training_mode, menu, PauseMenu, + dev_config, is_operation_cpu, is_training_mode, menu, try_get_module_accessor, PauseMenu, FIGHTER_MANAGER_ADDR, ITEM_MANAGER_ADDR, STAGE_MANAGER_ADDR, TRAINING_MENU_ADDR, }; use crate::hitbox_visualizer; @@ -757,8 +757,10 @@ pub unsafe fn handle_reused_ui( } if save_states::is_loading() { - let player_module_accessor = &mut *get_module_accessor(FighterId::Player); - let cpu_module_accessor = &mut *get_module_accessor(FighterId::CPU); + let player_module_accessor = &mut *try_get_module_accessor(FighterId::Player) + .expect("Could not get player module accessor in reused_ui"); + let cpu_module_accessor = &mut *try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in reused_ui"); let player_fighter_kind = utility::get_kind(player_module_accessor); let cpu_fighter_kind = utility::get_kind(cpu_module_accessor); // If Little Mac is in the game and we're buffing him, set the meter to 100 diff --git a/src/training/save_states.rs b/src/training/save_states.rs index c5fa51bd8..3c8db6f46 100644 --- a/src/training/save_states.rs +++ b/src/training/save_states.rs @@ -23,8 +23,8 @@ use crate::common::consts::RecordTrigger; use crate::common::consts::SaveStateMirroring; //TODO: Cleanup above use crate::common::consts::SAVE_STATES_TOML_PATH; -use crate::common::get_module_accessor; use crate::common::is_dead; +use crate::common::try_get_module_accessor; use crate::common::MENU; use crate::is_operation_cpu; use crate::training::buff; @@ -192,7 +192,8 @@ pub unsafe fn get_state_pokemon( ) -> u32 { let selected_slot = get_slot(); let pokemon_module_accessor = ptrainer::get_pokemon_module_accessor(ptrainer_module_accessor); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in get_state_pokemon"); let fighter_kind = if !ptr::eq(pokemon_module_accessor, cpu_module_accessor) { save_state_player(selected_slot).fighter_kind } else { @@ -205,7 +206,8 @@ pub unsafe fn get_charge_state( module_accessor: *mut app::BattleObjectModuleAccessor, ) -> ChargeState { let selected_slot = get_slot(); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in get_charge_state"); if !ptr::eq(module_accessor, cpu_module_accessor) { save_state_player(selected_slot).charge } else { @@ -215,7 +217,8 @@ pub unsafe fn get_charge_state( pub unsafe fn end_copy_ability(module_accessor: *mut app::BattleObjectModuleAccessor) { let selected_slot = get_slot(); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in end_copy_ability"); let save_state = if !ptr::eq(module_accessor, cpu_module_accessor) { save_state_player(selected_slot) } else { diff --git a/src/training/tech.rs b/src/training/tech.rs index d2e18f34a..bdae30835 100644 --- a/src/training/tech.rs +++ b/src/training/tech.rs @@ -352,7 +352,8 @@ pub unsafe fn hide_tech() { if !is_training_mode() || read(&MENU).tech_hide == OnOff::OFF { return; } - let module_accessor = get_module_accessor(FighterId::CPU); + let module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in hide_tech"); // Handle invisible tech animations let status = StatusModule::status_kind(module_accessor); let teching_statuses = [ From dce2ecc8b9012e7771e63540262527611d9184db Mon Sep 17 00:00:00 2001 From: asimon-1 <40246417+asimon-1@users.noreply.github.com> Date: Thu, 23 Oct 2025 18:33:48 -0400 Subject: [PATCH 2/8] find_pane_by_name_recursive --- src/training/ui/display.rs | 12 ++- src/training/ui/input_log.rs | 33 +++----- src/training/ui/menu.rs | 150 +++++++++++++---------------------- src/training/ui/mod.rs | 18 ++++- 4 files changed, 85 insertions(+), 128 deletions(-) diff --git a/src/training/ui/display.rs b/src/training/ui/display.rs index 6a2b39725..087e616f5 100644 --- a/src/training/ui/display.rs +++ b/src/training/ui/display.rs @@ -1,9 +1,10 @@ use skyline::nn::ui2d::*; -use smash::ui2d::{SmashPane, SmashTextBox}; +use smash::ui2d::SmashTextBox; use crate::common::menu::QUICK_MENU_ACTIVE; use crate::common::TRAINING_MENU_ADDR; use crate::training::ui::notifications::*; +use crate::training::ui::PaneExt; use training_mod_sync::*; macro_rules! display_parent_fmt { @@ -38,8 +39,7 @@ pub unsafe fn draw(root_pane: &Pane) { let notification = (*queue_lock).first_mut(); root_pane - .find_pane_by_name_recursive(display_parent_fmt!(notification_idx)) - .unwrap() + .find_pane_by_name_recursive_expect(display_parent_fmt!(notification_idx)) .set_visible(notification.is_some() && !read(&QUICK_MENU_ACTIVE)); if notification.is_none() { @@ -53,14 +53,12 @@ pub unsafe fn draw(root_pane: &Pane) { if !notification.has_drawn() { notification.set_drawn(); root_pane - .find_pane_by_name_recursive(display_header_fmt!(notification_idx)) - .unwrap() + .find_pane_by_name_recursive_expect(display_header_fmt!(notification_idx)) .as_textbox() .set_text_string(¬ification.header); let text = root_pane - .find_pane_by_name_recursive(display_txt_fmt!(notification_idx)) - .unwrap() + .find_pane_by_name_recursive_expect(display_txt_fmt!(notification_idx)) .as_textbox(); text.set_text_string(¬ification.message); text.set_default_material_colors(); diff --git a/src/training/ui/input_log.rs b/src/training/ui/input_log.rs index 3c0662d4d..b78a0b6ac 100644 --- a/src/training/ui/input_log.rs +++ b/src/training/ui/input_log.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; use skyline::nn::ui2d::*; -use smash::ui2d::{SmashPane, SmashTextBox}; +use smash::ui2d::SmashTextBox; use training_mod_consts::{InputDisplay, MENU}; use crate::common::consts::status_display_name; @@ -9,8 +9,8 @@ use crate::menu::QUICK_MENU_ACTIVE; 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 crate::training::ui::{fade_out, PaneExt}; use training_mod_sync::*; macro_rules! log_parent_fmt { @@ -70,9 +70,7 @@ fn get_input_icons(log: &InputLog) -> VecDeque<(&str, ResColor)> { unsafe fn draw_log(root_pane: &Pane, log_idx: usize, log: &InputLog) { let draw_log_base_idx = read(&DRAW_LOG_BASE_IDX); let draw_log_idx = (log_idx + (NUM_LOGS - draw_log_base_idx)) % NUM_LOGS; - let log_pane = root_pane - .find_pane_by_name_recursive(log_parent_fmt!(draw_log_idx)) - .unwrap(); + let log_pane = root_pane.find_pane_by_name_recursive_expect(log_parent_fmt!(draw_log_idx)); // Handle visibility and alpha log_pane.set_visible(true); @@ -136,13 +134,12 @@ unsafe fn draw_log(root_pane: &Pane, log_idx: usize, log: &InputLog) { ]; for idx in 0..NUM_ICON_SLOTS { - let input_pane = log_pane - .find_pane_by_name_recursive(format!("Input{}", idx).as_str()) - .unwrap(); + let input_pane = + log_pane.find_pane_by_name_recursive_expect(format!("Input{}", idx).as_str()); available_icons .iter() - .map(|name| input_pane.find_pane_by_name_recursive(name).unwrap()) + .map(|name| input_pane.find_pane_by_name_recursive_expect(name)) .for_each(|icon_pane| { icon_pane.set_visible(false); }); @@ -156,13 +153,11 @@ unsafe fn draw_log(root_pane: &Pane, log_idx: usize, log: &InputLog) { continue; } - let input_pane = log_pane - .find_pane_by_name_recursive(format!("Input{}", index).as_str()) - .unwrap(); + let input_pane = + log_pane.find_pane_by_name_recursive_expect(format!("Input{}", index).as_str()); let icon_pane = input_pane - .find_pane_by_name_recursive(icon_name) - .unwrap() + .find_pane_by_name_recursive_expect(icon_name) .as_picture(); icon_pane.set_visible(true); @@ -171,8 +166,7 @@ unsafe fn draw_log(root_pane: &Pane, log_idx: usize, log: &InputLog) { let frame_text = format!("{}", log.frames); log_pane - .find_pane_by_name_recursive("Frame") - .unwrap() + .find_pane_by_name_recursive_expect("Frame") .as_textbox() .set_text_string(frame_text.as_str()); @@ -182,16 +176,13 @@ unsafe fn draw_log(root_pane: &Pane, log_idx: usize, log: &InputLog) { "".to_string() }; log_pane - .find_pane_by_name_recursive("Status") - .unwrap() + .find_pane_by_name_recursive_expect("Status") .as_textbox() .set_text_string(status_text.as_str()); } pub unsafe fn draw(root_pane: &Pane) { - let logs_pane = root_pane - .find_pane_by_name_recursive("TrModInputLog") - .unwrap(); + let logs_pane = root_pane.find_pane_by_name_recursive_expect("TrModInputLog"); logs_pane.set_visible( !read(&QUICK_MENU_ACTIVE) && !read(&VANILLA_MENU_ACTIVE) diff --git a/src/training/ui/menu.rs b/src/training/ui/menu.rs index d8ce8f0cb..6279e03d0 100644 --- a/src/training/ui/menu.rs +++ b/src/training/ui/menu.rs @@ -12,6 +12,7 @@ use crate::common::menu::{ }; use crate::input::*; use crate::training::frame_counter; +use crate::training::ui::PaneExt; use training_mod_consts::TOGGLE_MAX; use training_mod_sync::*; @@ -87,22 +88,18 @@ unsafe fn render_submenu_page(app: &mut App, root_pane: &Pane) { let tab = app.selected_tab(); for row in 0..NX_SUBMENU_ROWS { let menu_button_row = root_pane - .find_pane_by_name_recursive(format!("TrModMenuButtonRow{row}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("TrModMenuButtonRow{row}").as_str()); menu_button_row.set_visible(true); for col in 0..NX_SUBMENU_COLUMNS { if let Some(submenu) = tab.submenus.get(row, col) { // Find all the panes we need to modify let menu_button = menu_button_row - .find_pane_by_name_recursive(format!("Button{col}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("Button{col}").as_str()); let title_text = menu_button - .find_pane_by_name_recursive("TitleTxt") - .unwrap() + .find_pane_by_name_recursive_expect("TitleTxt") .as_textbox(); let title_bg = menu_button - .find_pane_by_name_recursive("TitleBg") - .unwrap() + .find_pane_by_name_recursive_expect("TitleBg") .as_picture(); let title_bg_material = &mut *title_bg.material; let is_selected = row == tab.submenus.state.selected_row().unwrap() @@ -126,8 +123,7 @@ unsafe fn render_submenu_page(app: &mut App, root_pane: &Pane) { } menu_button - .find_pane_by_name_recursive("check") - .unwrap() + .find_pane_by_name_recursive_expect("check") .set_visible(false); for value in 1..=TOGGLE_MAX { @@ -143,8 +139,7 @@ unsafe fn render_submenu_page(app: &mut App, root_pane: &Pane) { if is_selected { // Help text root_pane - .find_pane_by_name_recursive("FooterTxt") - .unwrap() + .find_pane_by_name_recursive_expect("FooterTxt") .as_textbox() .set_text_string(submenu.help_text); @@ -162,8 +157,7 @@ unsafe fn render_submenu_page(app: &mut App, root_pane: &Pane) { } menu_button.set_visible(true); menu_button - .find_pane_by_name_recursive("Icon") - .unwrap() + .find_pane_by_name_recursive_expect("Icon") .set_visible(true); } } @@ -178,22 +172,18 @@ unsafe fn render_toggle_page(app: &mut App, root_pane: &Pane) { let use_check_icon = submenu.toggles.get(0, 0).unwrap().max == 1; for row in 0..NX_SUBMENU_ROWS { let menu_button_row = root_pane - .find_pane_by_name_recursive(format!("TrModMenuButtonRow{row}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("TrModMenuButtonRow{row}").as_str()); menu_button_row.set_visible(true); for col in 0..NX_SUBMENU_COLUMNS { if let Some(toggle) = submenu.toggles.get(row, col) { let menu_button = menu_button_row - .find_pane_by_name_recursive(format!("Button{col}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("Button{col}").as_str()); menu_button.set_visible(true); let title_text = menu_button - .find_pane_by_name_recursive("TitleTxt") - .unwrap() + .find_pane_by_name_recursive_expect("TitleTxt") .as_textbox(); let title_bg = menu_button - .find_pane_by_name_recursive("TitleBg") - .unwrap() + .find_pane_by_name_recursive_expect("TitleBg") .as_picture(); let title_bg_material = &mut *title_bg.material; let is_selected = row == submenu.toggles.state.selected_row().unwrap() @@ -227,22 +217,18 @@ unsafe fn render_toggle_page(app: &mut App, root_pane: &Pane) { if use_check_icon { menu_button - .find_pane_by_name_recursive("check") - .unwrap() + .find_pane_by_name_recursive_expect("check") .set_visible(true); menu_button - .find_pane_by_name_recursive("Icon") - .unwrap() + .find_pane_by_name_recursive_expect("Icon") .set_visible(toggle.value > 0); } else { menu_button - .find_pane_by_name_recursive("check") - .unwrap() + .find_pane_by_name_recursive_expect("check") .set_visible(false); menu_button - .find_pane_by_name_recursive("Icon") - .unwrap() + .find_pane_by_name_recursive_expect("Icon") .set_visible(toggle.value > 0); // Note there's no pane for 0 @@ -265,51 +251,39 @@ unsafe fn render_slider_page(app: &mut App, root_pane: &Pane) { let selected_min = slider.lower; let selected_max = slider.upper; - let slider_pane = root_pane - .find_pane_by_name_recursive("TrModSlider") - .unwrap(); + let slider_pane = root_pane.find_pane_by_name_recursive_expect("TrModSlider"); slider_pane.set_visible(true); let _background = slider_pane - .find_pane_by_name_recursive("Background") - .unwrap() + .find_pane_by_name_recursive_expect("Background") .as_picture(); let header = slider_pane - .find_pane_by_name_recursive("Header") - .unwrap() + .find_pane_by_name_recursive_expect("Header") .as_textbox(); header.set_text_string(submenu.title); let min_button = slider_pane - .find_pane_by_name_recursive("MinButton") - .unwrap() + .find_pane_by_name_recursive_expect("MinButton") .as_picture(); let max_button = slider_pane - .find_pane_by_name_recursive("MaxButton") - .unwrap() + .find_pane_by_name_recursive_expect("MaxButton") .as_picture(); let min_title_text = min_button - .find_pane_by_name_recursive("TitleTxt") - .unwrap() + .find_pane_by_name_recursive_expect("TitleTxt") .as_textbox(); let min_title_bg = min_button - .find_pane_by_name_recursive("TitleBg") - .unwrap() + .find_pane_by_name_recursive_expect("TitleBg") .as_picture(); let min_value_text = min_button - .find_pane_by_name_recursive("ValueTxt") - .unwrap() + .find_pane_by_name_recursive_expect("ValueTxt") .as_textbox(); let max_title_text = max_button - .find_pane_by_name_recursive("TitleTxt") - .unwrap() + .find_pane_by_name_recursive_expect("TitleTxt") .as_textbox(); let max_title_bg = max_button - .find_pane_by_name_recursive("TitleBg") - .unwrap() + .find_pane_by_name_recursive_expect("TitleBg") .as_picture(); let max_value_text = max_button - .find_pane_by_name_recursive("ValueTxt") - .unwrap() + .find_pane_by_name_recursive_expect("ValueTxt") .as_textbox(); min_title_text.set_text_string("Min"); @@ -368,7 +342,7 @@ unsafe fn render_slider_page(app: &mut App, root_pane: &Pane) { // Hide the Icon pane for MinButton and MaxButton [min_button, max_button].iter().for_each(|button| { - let icon = button.find_pane_by_name_recursive("Icon").unwrap(); + let icon = button.find_pane_by_name_recursive_expect("Icon"); icon.set_visible(false); }); } @@ -388,8 +362,7 @@ unsafe fn render_confirmation_page(app: &mut App, root_pane: &Pane) { // Set help text root_pane - .find_pane_by_name_recursive("FooterTxt") - .unwrap() + .find_pane_by_name_recursive_expect("FooterTxt") .as_textbox() .set_text_string(help_text); @@ -397,24 +370,20 @@ unsafe fn render_confirmation_page(app: &mut App, root_pane: &Pane) { for row in 0..NX_SUBMENU_ROWS { let should_show_row = row == show_row; let menu_button_row = root_pane - .find_pane_by_name_recursive(format!("TrModMenuButtonRow{row}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("TrModMenuButtonRow{row}").as_str()); menu_button_row.set_visible(should_show_row); if should_show_row { for col in 0..NX_SUBMENU_COLUMNS { let should_show_col = show_cols.contains(&col); let menu_button = menu_button_row - .find_pane_by_name_recursive(format!("Button{col}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("Button{col}").as_str()); menu_button.set_visible(should_show_col); if should_show_col { let title_text = menu_button - .find_pane_by_name_recursive("TitleTxt") - .unwrap() + .find_pane_by_name_recursive_expect("TitleTxt") .as_textbox(); let title_bg = menu_button - .find_pane_by_name_recursive("TitleBg") - .unwrap() + .find_pane_by_name_recursive_expect("TitleBg") .as_picture(); let title_bg_material = &mut *title_bg.material; @@ -465,13 +434,12 @@ pub unsafe fn draw(root_pane: &Pane) { assign( &VANILLA_MENU_ACTIVE, root_pane - .find_pane_by_name_recursive("L_staying_help") - .unwrap() + .find_pane_by_name_recursive_expect("L_staying_help") .pos_y != -80.0, ); - let overall_parent_pane = root_pane.find_pane_by_name_recursive("TrModMenu").unwrap(); + let overall_parent_pane = root_pane.find_pane_by_name_recursive_expect("TrModMenu"); overall_parent_pane.set_visible(read(&QUICK_MENU_ACTIVE) && !read(&VANILLA_MENU_ACTIVE)); let menu_close_wait_frame = frame_counter::get_frame_count(*MENU_CLOSE_FRAME_COUNTER); fade_out( @@ -499,19 +467,17 @@ pub unsafe fn draw(root_pane: &Pane) { // Make all invisible first for row_idx in 0..NX_SUBMENU_ROWS { for col_idx in 0..NX_SUBMENU_COLUMNS { - let menu_button_row = root_pane - .find_pane_by_name_recursive(format!("TrModMenuButtonRow{row_idx}").as_str()) - .unwrap(); + let menu_button_row = root_pane.find_pane_by_name_recursive_expect( + format!("TrModMenuButtonRow{row_idx}").as_str(), + ); menu_button_row.set_visible(false); let menu_button = menu_button_row - .find_pane_by_name_recursive(format!("Button{col_idx}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("Button{col_idx}").as_str()); menu_button.set_visible(false); menu_button - .find_pane_by_name_recursive("ValueTxt") - .unwrap() + .find_pane_by_name_recursive_expect("ValueTxt") .set_visible(false); } } @@ -525,8 +491,7 @@ pub unsafe fn draw(root_pane: &Pane) { status_r_pane.set_visible(!read(&QUICK_MENU_ACTIVE)); root_pane - .find_pane_by_name_recursive("TrModSlider") - .unwrap() + .find_pane_by_name_recursive_expect("TrModSlider") .set_visible(false); // Update menu display @@ -577,15 +542,13 @@ pub unsafe fn draw(root_pane: &Pane) { .iter() .enumerate() .for_each(|(idx, (key, name))| { - let key_help_pane = root_pane.find_pane_by_name_recursive(name).unwrap(); + let key_help_pane = root_pane.find_pane_by_name_recursive_expect(name); let icon_pane = key_help_pane - .find_pane_by_name_recursive("set_txt_icon") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_icon") .as_textbox(); let help_pane = key_help_pane - .find_pane_by_name_recursive("set_txt_help") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_help") .as_textbox(); icon_pane.set_text_string(""); @@ -607,15 +570,13 @@ pub unsafe fn draw(root_pane: &Pane) { let name = "SaveDefaults"; let key = save_defaults_key; let title = "Save Defaults"; - let key_help_pane = root_pane.find_pane_by_name_recursive(name).unwrap(); + let key_help_pane = root_pane.find_pane_by_name_recursive_expect(name); let icon_pane = key_help_pane - .find_pane_by_name_recursive("set_txt_icon") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_icon") .as_textbox(); set_icon_text(icon_pane, &[*key.unwrap()]); key_help_pane - .find_pane_by_name_recursive("set_txt_help") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_help") .as_textbox() .set_text_string(title); @@ -630,33 +591,28 @@ pub unsafe fn draw(root_pane: &Pane) { AppPage::CLOSE => "", }; if !title.is_empty() { - let key_help_pane = root_pane.find_pane_by_name_recursive(name).unwrap(); + let key_help_pane = root_pane.find_pane_by_name_recursive_expect(name); let icon_pane = key_help_pane - .find_pane_by_name_recursive("set_txt_icon") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_icon") .as_textbox(); set_icon_text(icon_pane, &[*key.unwrap()]); key_help_pane - .find_pane_by_name_recursive("set_txt_help") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_help") .as_textbox() .set_text_string(title); } // Clear Toggle Keyhelp let name = "ClearToggle"; - let key_help_pane = root_pane.find_pane_by_name_recursive(name).unwrap(); - let icon_pane = key_help_pane - .find_pane_by_name_recursive("set_txt_icon") - .unwrap(); + let key_help_pane = root_pane.find_pane_by_name_recursive_expect(name); + let icon_pane = key_help_pane.find_pane_by_name_recursive_expect("set_txt_icon"); if app.should_show_clear_keyhelp() { // This is only displayed when you're in a multiple selection toggle menu w/ toggle.max > 1 let key = clear_toggle_key; let title = "Clear Toggle"; set_icon_text(icon_pane.as_textbox(), &[*key.unwrap()]); key_help_pane - .find_pane_by_name_recursive("set_txt_help") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_help") .as_textbox() .set_text_string(title); icon_pane.set_visible(true); diff --git a/src/training/ui/mod.rs b/src/training/ui/mod.rs index 69a3bd59f..fe8b3ddd7 100644 --- a/src/training/ui/mod.rs +++ b/src/training/ui/mod.rs @@ -2,7 +2,7 @@ use byte_unit::MEBIBYTE; use sarc::SarcFile; use skyline::nn::ui2d::*; -use smash::ui2d::SmashTextBox; +use smash::ui2d::{SmashPane, SmashTextBox}; use training_mod_consts::{OnOff, MENU}; use crate::common::menu::QUICK_MENU_ACTIVE; @@ -142,7 +142,7 @@ unsafe fn handle_layout_arc_malloc(ctx: &mut skyline::hooks::InlineCtx) { decompressed_file, decompressed_size, )) - .unwrap(); + .expect("Could not read layout.arc SarcFile!"); let training_layout = layout_arc.files.iter().find(|f| { f.name.is_some() && f.name.as_ref().unwrap() == &String::from("blyt/info_training.bflyt") }); @@ -156,7 +156,8 @@ unsafe fn handle_layout_arc_malloc(ctx: &mut skyline::hooks::InlineCtx) { #[cfg(feature = "layout_arc_from_file")] #[allow(static_mut_refs)] { - let inject_arc_from_file = std::fs::read(LAYOUT_ARC_PATH).unwrap(); + let inject_arc_from_file = + std::fs::read(LAYOUT_ARC_PATH).expect("Could not read layout.arc from file!"); inject_arc_size = inject_arc_from_file.len() as u64; // Copy read file to global @@ -185,6 +186,17 @@ unsafe fn handle_layout_arc_malloc(ctx: &mut skyline::hooks::InlineCtx) { ctx.registers[24].set_x(inject_arc_size); } +pub trait PaneExt { + unsafe fn find_pane_by_name_recursive_expect(&self, name: &str) -> &mut Pane; +} + +impl PaneExt for Pane { + unsafe fn find_pane_by_name_recursive_expect(&self, name: &str) -> &mut Pane { + self.find_pane_by_name_recursive(name) + .expect(&format!("Could not find pane {name}")) + } +} + pub fn init() { skyline::install_hooks!(handle_draw, handle_layout_arc_malloc); } From dd43db146335cdb91481e2be12cc1d96abe5a461 Mon Sep 17 00:00:00 2001 From: asimon-1 <40246417+asimon-1@users.noreply.github.com> Date: Thu, 23 Oct 2025 18:38:10 -0400 Subject: [PATCH 3/8] Additional expects --- src/lib.rs | 4 ++-- src/training/buff.rs | 13 ++++++++++--- src/training/ui/damage.rs | 5 ++++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 253d281dd..80dde90bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,7 +119,7 @@ pub fn main() { .spawn(move || { menu::load_from_file(); }) - .unwrap(); + .expect("Couldn't create data loader thread"); let _result = data_loader.join(); if !is_emulator() { @@ -129,7 +129,7 @@ pub fn main() { .spawn(move || { release::perform_version_check(); }) - .unwrap(); + .expect("Couldn't create version check thread"); let _result = _updater.join(); } else { info!("Skipping version check because we are using an emulator"); diff --git a/src/training/buff.rs b/src/training/buff.rs index 90e4848a3..3ac4a6953 100644 --- a/src/training/buff.rs +++ b/src/training/buff.rs @@ -140,7 +140,10 @@ unsafe fn buff_hero_single( // There are no spells selected, or something went wrong with making the vector return; } - let real_spell_value = spell_option.unwrap().into_int().unwrap(); + let real_spell_value = spell_option + .unwrap() + .into_int() + .expect("Invalid option for spell_option"); if status != FIGHTER_BRAVE_STATUS_KIND_SPECIAL_LW_START { WorkModule::set_int( module_accessor, @@ -267,7 +270,9 @@ unsafe fn buff_wario(module_accessor: &mut app::BattleObjectModuleAccessor) -> b ); WorkModule::set_int( module_accessor, - waft_level.into_int().unwrap(), + waft_level + .into_int() + .expect("Invalid option for waft_level"), *FIGHTER_WARIO_INSTANCE_WORK_ID_INT_GASS_LEVEL, ); } @@ -293,7 +298,9 @@ unsafe fn buff_shulk(module_accessor: &mut app::BattleObjectModuleAccessor, stat if status != FIGHTER_SHULK_STATUS_KIND_SPECIAL_N_ACTION { WorkModule::set_int( module_accessor, - current_art.into_int().unwrap(), + current_art + .into_int() + .expect("Invalid option for current_art"), *FIGHTER_SHULK_INSTANCE_WORK_ID_INT_SPECIAL_N_TYPE_SELECT, ); WorkModule::set_int( diff --git a/src/training/ui/damage.rs b/src/training/ui/damage.rs index e54a4ae91..bd41cb49c 100644 --- a/src/training/ui/damage.rs +++ b/src/training/ui/damage.rs @@ -15,7 +15,10 @@ pub unsafe fn iterate_anim_list( if curr != (*curr).next { let anim_transform = (curr as *mut u64).add(2) as *mut AnimTransform; - parse_anim_transform(anim_transform.as_mut().unwrap(), layout_name); + parse_anim_transform( + anim_transform.as_mut().expect("Invalid anim_transform"), + layout_name, + ); } curr = (*curr).next; From 2bf5d994c1081cca6197d9960912390e1e3f6c84 Mon Sep 17 00:00:00 2001 From: asimon-1 <40246417+asimon-1@users.noreply.github.com> Date: Thu, 23 Oct 2025 18:01:36 -0400 Subject: [PATCH 4/8] Don't unwrap on try_get_module_accessor --- src/common/menu.rs | 3 ++- src/common/mod.rs | 13 ++++++------- src/lib.rs | 2 +- src/training/character_specific/items.rs | 12 ++++++++---- src/training/charge.rs | 8 +++++--- src/training/combo.rs | 8 +++++--- src/training/directional_influence.rs | 6 ++++-- src/training/input_record.rs | 19 +++++++++++-------- src/training/mod.rs | 8 +++++--- src/training/save_states.rs | 11 +++++++---- src/training/tech.rs | 3 ++- 11 files changed, 56 insertions(+), 37 deletions(-) diff --git a/src/common/menu.rs b/src/common/menu.rs index ecb5e6e30..1ccdaeca3 100644 --- a/src/common/menu.rs +++ b/src/common/menu.rs @@ -67,7 +67,8 @@ pub fn set_menu_from_json(message: &str) { std::thread::spawn(move || { fs::write( MENU_OPTIONS_PATH, - serde_json::to_string_pretty(&message_json).unwrap(), + serde_json::to_string_pretty(&message_json) + .expect("Could not serialize menu settings"), ) .expect("Failed to write menu settings file"); }); diff --git a/src/common/mod.rs b/src/common/mod.rs index cd6abc264..1a574aef2 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -63,10 +63,6 @@ pub unsafe fn try_get_battle_object(battle_object_id: u32) -> Option<&'static ap battle_object_ptr.as_ref() } -pub fn get_module_accessor(fighter_id: FighterId) -> *mut app::BattleObjectModuleAccessor { - try_get_module_accessor(fighter_id).unwrap() -} - pub fn try_get_module_accessor( fighter_id: FighterId, ) -> Option<*mut app::BattleObjectModuleAccessor> { @@ -284,7 +280,8 @@ pub unsafe fn entry_count() -> i32 { } pub unsafe fn get_player_dmg_digits(p: FighterId) -> (u8, u8, u8, u8) { - let module_accessor = get_module_accessor(p); + let module_accessor = + try_get_module_accessor(p).expect("Could not get module accessor in get_player_dmg_digits"); let dmg = DamageModule::damage(module_accessor, 0); let hundreds = dmg as u16 / 100; let tens = (dmg as u16 - hundreds * 100) / 10; @@ -294,11 +291,13 @@ pub unsafe fn get_player_dmg_digits(p: FighterId) -> (u8, u8, u8, u8) { } pub unsafe fn get_fighter_distance() -> f32 { - let player_module_accessor = get_module_accessor(FighterId::Player); + let player_module_accessor = try_get_module_accessor(FighterId::Player) + .expect("Could not get player_module_accessor in get_fighter_distance"); if StatusModule::status_kind(player_module_accessor) == *FIGHTER_STATUS_KIND_NONE { return f32::MAX; } - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module_accessor in get_fighter_distance"); let player_pos = *PostureModule::pos(player_module_accessor); let cpu_pos = *PostureModule::pos(cpu_module_accessor); app::sv_math::vec3_distance( diff --git a/src/lib.rs b/src/lib.rs index d24478438..253d281dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,7 +81,7 @@ pub fn main() { &complete_error_message, ); })); - init_logger().unwrap(); + init_logger().expect("Could not initialize logger"); info!("Initialized."); diff --git a/src/training/character_specific/items.rs b/src/training/character_specific/items.rs index 9cce1da25..f5636cd59 100644 --- a/src/training/character_specific/items.rs +++ b/src/training/character_specific/items.rs @@ -331,8 +331,10 @@ pub const ALL_CHAR_ITEMS: [CharItem; 45] = [ ]; unsafe fn apply_single_item(player_fighter_kind: i32, item: &CharItem) { - let player_module_accessor = get_module_accessor(FighterId::Player); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let player_module_accessor = try_get_module_accessor(FighterId::Player) + .expect("Could not get player module accessor in apply_single_item"); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in apply_single_item"); // Now we make sure the module_accessor we use to generate the item/article is the correct character let generator_module_accessor = if item.fighter_kind == player_fighter_kind { player_module_accessor @@ -446,8 +448,10 @@ unsafe fn apply_single_item(player_fighter_kind: i32, item: &CharItem) { } pub unsafe fn apply_item(character_item: CharacterItem) { - let player_module_accessor = get_module_accessor(FighterId::Player); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let player_module_accessor = try_get_module_accessor(FighterId::Player) + .expect("Could not get player module accessor in apply_item"); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in apply_item"); let player_fighter_kind = app::utility::get_kind(&mut *player_module_accessor); let cpu_fighter_kind = app::utility::get_kind(&mut *cpu_module_accessor); let character_item_num = character_item.as_idx(); diff --git a/src/training/charge.rs b/src/training/charge.rs index bcb6b624d..9d5e79f97 100644 --- a/src/training/charge.rs +++ b/src/training/charge.rs @@ -1,6 +1,6 @@ use crate::common::consts::FighterId; use crate::common::offsets::OFFSET_COPY_SETUP; -use crate::common::{get_module_accessor, try_get_battle_object}; +use crate::common::{try_get_battle_object, try_get_module_accessor}; use crate::training::character_specific::{kirby, pikmin}; use serde::{Deserialize, Serialize}; use smash::app::{self, lua_bind::*, ArticleOperationTarget, FighterFacial, FighterUtil}; @@ -497,8 +497,10 @@ pub unsafe fn handle_charge( // Kirby Copy Abilities else if fighter_kind == FIGHTER_KIND_KIRBY { charge.has_charge.map(|_has_copy_ability| { - let cpu_module_accessor = &mut *get_module_accessor(FighterId::CPU); - let player_module_accessor = &mut *get_module_accessor(FighterId::Player); + let cpu_module_accessor = &mut *try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor for Kirby copy ability charge setup"); + let player_module_accessor = &mut *try_get_module_accessor(FighterId::Player) + .expect("Could not get Player module accessor for Kirby copy ability charge setup"); let opponent_module_accessor: &mut app::BattleObjectModuleAccessor = if ptr::eq(module_accessor, player_module_accessor) { cpu_module_accessor diff --git a/src/training/combo.rs b/src/training/combo.rs index 7b5c8e877..3819b7761 100644 --- a/src/training/combo.rs +++ b/src/training/combo.rs @@ -4,9 +4,9 @@ use smash::app::BattleObjectModuleAccessor; use smash::lib::lua_const::*; use crate::consts::Action; -use crate::get_module_accessor; use crate::training::frame_counter; use crate::training::ui::notifications; +use crate::try_get_module_accessor; use training_mod_consts::{FighterId, OnOff, MENU}; use training_mod_sync::*; @@ -91,8 +91,10 @@ pub unsafe fn once_per_frame(module_accessor: &mut BattleObjectModuleAccessor) { if entry_id_int != (FighterId::Player as i32) { return; } - let player_module_accessor = get_module_accessor(FighterId::Player); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let player_module_accessor = try_get_module_accessor(FighterId::Player) + .expect("Could not get player module accessor in once_per_frame"); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in once_per_frame"); let player_is_actionable = is_actionable(player_module_accessor); let player_was_actionable = read(&PLAYER_WAS_ACTIONABLE); let player_just_actionable = !player_was_actionable && player_is_actionable; diff --git a/src/training/directional_influence.rs b/src/training/directional_influence.rs index 1c0322314..740399c35 100644 --- a/src/training/directional_influence.rs +++ b/src/training/directional_influence.rs @@ -69,8 +69,10 @@ unsafe fn mod_handle_di(fighter: &L2CFighterCommon, _arg1: L2CValue) { } pub fn should_reverse_angle(direction: Direction) -> bool { - let cpu_module_accessor = get_module_accessor(FighterId::CPU); - let player_module_accessor = get_module_accessor(FighterId::Player); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in should_reverse_angle"); + let player_module_accessor = try_get_module_accessor(FighterId::Player) + .expect("Could not get player module accessor in should_reverse_angle"); unsafe { PostureModule::pos_x(player_module_accessor) > PostureModule::pos_x(cpu_module_accessor) && ![Direction::LEFT, Direction::RIGHT].contains(&direction) diff --git a/src/training/input_record.rs b/src/training/input_record.rs index b056a7bd9..201278c73 100644 --- a/src/training/input_record.rs +++ b/src/training/input_record.rs @@ -11,9 +11,7 @@ use crate::common::consts::{FighterId, HitstunPlayback, OnOff, RecordTrigger}; use crate::common::input::*; use crate::common::offsets::OFFSET_SET_CPU_CONTROLS; use crate::common::{button_config, is_training_mode}; -use crate::common::{ - get_module_accessor, is_in_hitstun, is_in_shieldstun, try_get_module_accessor, MENU, -}; +use crate::common::{is_in_hitstun, is_in_shieldstun, try_get_module_accessor, MENU}; use crate::training::mash; use crate::training::ui::notifications::{clear_notification, color_notification}; use crate::{error, warn}; @@ -93,7 +91,8 @@ unsafe fn should_mash_playback() { return; } let mut should_playback = false; - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in should_mash_playback"); // depending on our current status, we want to wait for different timings to begin playback // TODO: This isn't the best way to write this I'm sure, want to rewrite @@ -330,7 +329,8 @@ unsafe fn handle_recording_for_fighter(module_accessor: &mut BattleObjectModuleA } pub unsafe fn lockout_record() { - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in lockout_record"); let recording_duration = read(&MENU).recording_duration.into_frames(); let current_record_slot = read(&CURRENT_RECORD_SLOT); let mut p1_final_mapping = lock_write(&P1_FINAL_MAPPING); @@ -361,7 +361,8 @@ pub unsafe fn playback(slot: Option) -> bool { return false; } let slot = slot.unwrap(); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in playback"); let frame_length = read(&P1_FRAME_LENGTH_MAPPING)[slot]; assign(&CURRENT_FRAME_LENGTH, frame_length); assign(&CURRENT_PLAYBACK_SLOT, slot); @@ -381,7 +382,8 @@ pub unsafe fn playback_ledge(slot: Option) { *buffer_frame = 5; // So we can make sure the option is buffered and won't get ledge trumped if delay is 0 // drop down from ledge can't be buffered on the same frame as jump/attack/roll/ngu so we have to do this // Need to buffer 1 less frame for non-lassos - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in playback_ledge"); let status_kind = StatusModule::status_kind(cpu_module_accessor); if status_kind == *FIGHTER_STATUS_KIND_CLIFF_CATCH { *buffer_frame -= 1; @@ -435,7 +437,8 @@ pub unsafe fn handle_final_input_mapping(player_idx: i32, out: *mut MappedInputs if *input_record_frame == 1 { // We're on the second frame of recording, grabbing the status should give us the status that resulted from the first frame of input // We'll want to save this status so that we use the correct TRANSITION TERM for hitstun cancelling out of damage fly - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in handle_final_input_mapping"); assign( &STARTING_STATUS, StatusModule::status_kind(cpu_module_accessor), diff --git a/src/training/mod.rs b/src/training/mod.rs index 6a18f5401..548cb70c3 100644 --- a/src/training/mod.rs +++ b/src/training/mod.rs @@ -4,7 +4,7 @@ use crate::common::button_config; use crate::common::consts::{BuffOption, FighterId, MENU}; use crate::common::offsets::*; use crate::common::{ - dev_config, get_module_accessor, is_operation_cpu, is_training_mode, menu, PauseMenu, + dev_config, is_operation_cpu, is_training_mode, menu, try_get_module_accessor, PauseMenu, FIGHTER_MANAGER_ADDR, ITEM_MANAGER_ADDR, STAGE_MANAGER_ADDR, TRAINING_MENU_ADDR, }; use crate::hitbox_visualizer; @@ -756,8 +756,10 @@ pub unsafe fn handle_reused_ui( } if save_states::is_loading() { - let player_module_accessor = &mut *get_module_accessor(FighterId::Player); - let cpu_module_accessor = &mut *get_module_accessor(FighterId::CPU); + let player_module_accessor = &mut *try_get_module_accessor(FighterId::Player) + .expect("Could not get player module accessor in reused_ui"); + let cpu_module_accessor = &mut *try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in reused_ui"); let player_fighter_kind = utility::get_kind(player_module_accessor); let cpu_fighter_kind = utility::get_kind(cpu_module_accessor); // If Little Mac is in the game and we're buffing him, set the meter to 100 diff --git a/src/training/save_states.rs b/src/training/save_states.rs index c5fa51bd8..3c8db6f46 100644 --- a/src/training/save_states.rs +++ b/src/training/save_states.rs @@ -23,8 +23,8 @@ use crate::common::consts::RecordTrigger; use crate::common::consts::SaveStateMirroring; //TODO: Cleanup above use crate::common::consts::SAVE_STATES_TOML_PATH; -use crate::common::get_module_accessor; use crate::common::is_dead; +use crate::common::try_get_module_accessor; use crate::common::MENU; use crate::is_operation_cpu; use crate::training::buff; @@ -192,7 +192,8 @@ pub unsafe fn get_state_pokemon( ) -> u32 { let selected_slot = get_slot(); let pokemon_module_accessor = ptrainer::get_pokemon_module_accessor(ptrainer_module_accessor); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in get_state_pokemon"); let fighter_kind = if !ptr::eq(pokemon_module_accessor, cpu_module_accessor) { save_state_player(selected_slot).fighter_kind } else { @@ -205,7 +206,8 @@ pub unsafe fn get_charge_state( module_accessor: *mut app::BattleObjectModuleAccessor, ) -> ChargeState { let selected_slot = get_slot(); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in get_charge_state"); if !ptr::eq(module_accessor, cpu_module_accessor) { save_state_player(selected_slot).charge } else { @@ -215,7 +217,8 @@ pub unsafe fn get_charge_state( pub unsafe fn end_copy_ability(module_accessor: *mut app::BattleObjectModuleAccessor) { let selected_slot = get_slot(); - let cpu_module_accessor = get_module_accessor(FighterId::CPU); + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in end_copy_ability"); let save_state = if !ptr::eq(module_accessor, cpu_module_accessor) { save_state_player(selected_slot) } else { diff --git a/src/training/tech.rs b/src/training/tech.rs index d2e18f34a..bdae30835 100644 --- a/src/training/tech.rs +++ b/src/training/tech.rs @@ -352,7 +352,8 @@ pub unsafe fn hide_tech() { if !is_training_mode() || read(&MENU).tech_hide == OnOff::OFF { return; } - let module_accessor = get_module_accessor(FighterId::CPU); + let module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in hide_tech"); // Handle invisible tech animations let status = StatusModule::status_kind(module_accessor); let teching_statuses = [ From d0d18c57755fbd837605135739a957f523b49836 Mon Sep 17 00:00:00 2001 From: asimon-1 <40246417+asimon-1@users.noreply.github.com> Date: Thu, 23 Oct 2025 18:33:48 -0400 Subject: [PATCH 5/8] find_pane_by_name_recursive --- src/training/ui/display.rs | 12 ++- src/training/ui/input_log.rs | 33 +++----- src/training/ui/menu.rs | 150 +++++++++++++---------------------- src/training/ui/mod.rs | 18 ++++- 4 files changed, 85 insertions(+), 128 deletions(-) diff --git a/src/training/ui/display.rs b/src/training/ui/display.rs index 6a2b39725..087e616f5 100644 --- a/src/training/ui/display.rs +++ b/src/training/ui/display.rs @@ -1,9 +1,10 @@ use skyline::nn::ui2d::*; -use smash::ui2d::{SmashPane, SmashTextBox}; +use smash::ui2d::SmashTextBox; use crate::common::menu::QUICK_MENU_ACTIVE; use crate::common::TRAINING_MENU_ADDR; use crate::training::ui::notifications::*; +use crate::training::ui::PaneExt; use training_mod_sync::*; macro_rules! display_parent_fmt { @@ -38,8 +39,7 @@ pub unsafe fn draw(root_pane: &Pane) { let notification = (*queue_lock).first_mut(); root_pane - .find_pane_by_name_recursive(display_parent_fmt!(notification_idx)) - .unwrap() + .find_pane_by_name_recursive_expect(display_parent_fmt!(notification_idx)) .set_visible(notification.is_some() && !read(&QUICK_MENU_ACTIVE)); if notification.is_none() { @@ -53,14 +53,12 @@ pub unsafe fn draw(root_pane: &Pane) { if !notification.has_drawn() { notification.set_drawn(); root_pane - .find_pane_by_name_recursive(display_header_fmt!(notification_idx)) - .unwrap() + .find_pane_by_name_recursive_expect(display_header_fmt!(notification_idx)) .as_textbox() .set_text_string(¬ification.header); let text = root_pane - .find_pane_by_name_recursive(display_txt_fmt!(notification_idx)) - .unwrap() + .find_pane_by_name_recursive_expect(display_txt_fmt!(notification_idx)) .as_textbox(); text.set_text_string(¬ification.message); text.set_default_material_colors(); diff --git a/src/training/ui/input_log.rs b/src/training/ui/input_log.rs index 3c0662d4d..b78a0b6ac 100644 --- a/src/training/ui/input_log.rs +++ b/src/training/ui/input_log.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; use skyline::nn::ui2d::*; -use smash::ui2d::{SmashPane, SmashTextBox}; +use smash::ui2d::SmashTextBox; use training_mod_consts::{InputDisplay, MENU}; use crate::common::consts::status_display_name; @@ -9,8 +9,8 @@ use crate::menu::QUICK_MENU_ACTIVE; 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 crate::training::ui::{fade_out, PaneExt}; use training_mod_sync::*; macro_rules! log_parent_fmt { @@ -70,9 +70,7 @@ fn get_input_icons(log: &InputLog) -> VecDeque<(&str, ResColor)> { unsafe fn draw_log(root_pane: &Pane, log_idx: usize, log: &InputLog) { let draw_log_base_idx = read(&DRAW_LOG_BASE_IDX); let draw_log_idx = (log_idx + (NUM_LOGS - draw_log_base_idx)) % NUM_LOGS; - let log_pane = root_pane - .find_pane_by_name_recursive(log_parent_fmt!(draw_log_idx)) - .unwrap(); + let log_pane = root_pane.find_pane_by_name_recursive_expect(log_parent_fmt!(draw_log_idx)); // Handle visibility and alpha log_pane.set_visible(true); @@ -136,13 +134,12 @@ unsafe fn draw_log(root_pane: &Pane, log_idx: usize, log: &InputLog) { ]; for idx in 0..NUM_ICON_SLOTS { - let input_pane = log_pane - .find_pane_by_name_recursive(format!("Input{}", idx).as_str()) - .unwrap(); + let input_pane = + log_pane.find_pane_by_name_recursive_expect(format!("Input{}", idx).as_str()); available_icons .iter() - .map(|name| input_pane.find_pane_by_name_recursive(name).unwrap()) + .map(|name| input_pane.find_pane_by_name_recursive_expect(name)) .for_each(|icon_pane| { icon_pane.set_visible(false); }); @@ -156,13 +153,11 @@ unsafe fn draw_log(root_pane: &Pane, log_idx: usize, log: &InputLog) { continue; } - let input_pane = log_pane - .find_pane_by_name_recursive(format!("Input{}", index).as_str()) - .unwrap(); + let input_pane = + log_pane.find_pane_by_name_recursive_expect(format!("Input{}", index).as_str()); let icon_pane = input_pane - .find_pane_by_name_recursive(icon_name) - .unwrap() + .find_pane_by_name_recursive_expect(icon_name) .as_picture(); icon_pane.set_visible(true); @@ -171,8 +166,7 @@ unsafe fn draw_log(root_pane: &Pane, log_idx: usize, log: &InputLog) { let frame_text = format!("{}", log.frames); log_pane - .find_pane_by_name_recursive("Frame") - .unwrap() + .find_pane_by_name_recursive_expect("Frame") .as_textbox() .set_text_string(frame_text.as_str()); @@ -182,16 +176,13 @@ unsafe fn draw_log(root_pane: &Pane, log_idx: usize, log: &InputLog) { "".to_string() }; log_pane - .find_pane_by_name_recursive("Status") - .unwrap() + .find_pane_by_name_recursive_expect("Status") .as_textbox() .set_text_string(status_text.as_str()); } pub unsafe fn draw(root_pane: &Pane) { - let logs_pane = root_pane - .find_pane_by_name_recursive("TrModInputLog") - .unwrap(); + let logs_pane = root_pane.find_pane_by_name_recursive_expect("TrModInputLog"); logs_pane.set_visible( !read(&QUICK_MENU_ACTIVE) && !read(&VANILLA_MENU_ACTIVE) diff --git a/src/training/ui/menu.rs b/src/training/ui/menu.rs index d8ce8f0cb..6279e03d0 100644 --- a/src/training/ui/menu.rs +++ b/src/training/ui/menu.rs @@ -12,6 +12,7 @@ use crate::common::menu::{ }; use crate::input::*; use crate::training::frame_counter; +use crate::training::ui::PaneExt; use training_mod_consts::TOGGLE_MAX; use training_mod_sync::*; @@ -87,22 +88,18 @@ unsafe fn render_submenu_page(app: &mut App, root_pane: &Pane) { let tab = app.selected_tab(); for row in 0..NX_SUBMENU_ROWS { let menu_button_row = root_pane - .find_pane_by_name_recursive(format!("TrModMenuButtonRow{row}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("TrModMenuButtonRow{row}").as_str()); menu_button_row.set_visible(true); for col in 0..NX_SUBMENU_COLUMNS { if let Some(submenu) = tab.submenus.get(row, col) { // Find all the panes we need to modify let menu_button = menu_button_row - .find_pane_by_name_recursive(format!("Button{col}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("Button{col}").as_str()); let title_text = menu_button - .find_pane_by_name_recursive("TitleTxt") - .unwrap() + .find_pane_by_name_recursive_expect("TitleTxt") .as_textbox(); let title_bg = menu_button - .find_pane_by_name_recursive("TitleBg") - .unwrap() + .find_pane_by_name_recursive_expect("TitleBg") .as_picture(); let title_bg_material = &mut *title_bg.material; let is_selected = row == tab.submenus.state.selected_row().unwrap() @@ -126,8 +123,7 @@ unsafe fn render_submenu_page(app: &mut App, root_pane: &Pane) { } menu_button - .find_pane_by_name_recursive("check") - .unwrap() + .find_pane_by_name_recursive_expect("check") .set_visible(false); for value in 1..=TOGGLE_MAX { @@ -143,8 +139,7 @@ unsafe fn render_submenu_page(app: &mut App, root_pane: &Pane) { if is_selected { // Help text root_pane - .find_pane_by_name_recursive("FooterTxt") - .unwrap() + .find_pane_by_name_recursive_expect("FooterTxt") .as_textbox() .set_text_string(submenu.help_text); @@ -162,8 +157,7 @@ unsafe fn render_submenu_page(app: &mut App, root_pane: &Pane) { } menu_button.set_visible(true); menu_button - .find_pane_by_name_recursive("Icon") - .unwrap() + .find_pane_by_name_recursive_expect("Icon") .set_visible(true); } } @@ -178,22 +172,18 @@ unsafe fn render_toggle_page(app: &mut App, root_pane: &Pane) { let use_check_icon = submenu.toggles.get(0, 0).unwrap().max == 1; for row in 0..NX_SUBMENU_ROWS { let menu_button_row = root_pane - .find_pane_by_name_recursive(format!("TrModMenuButtonRow{row}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("TrModMenuButtonRow{row}").as_str()); menu_button_row.set_visible(true); for col in 0..NX_SUBMENU_COLUMNS { if let Some(toggle) = submenu.toggles.get(row, col) { let menu_button = menu_button_row - .find_pane_by_name_recursive(format!("Button{col}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("Button{col}").as_str()); menu_button.set_visible(true); let title_text = menu_button - .find_pane_by_name_recursive("TitleTxt") - .unwrap() + .find_pane_by_name_recursive_expect("TitleTxt") .as_textbox(); let title_bg = menu_button - .find_pane_by_name_recursive("TitleBg") - .unwrap() + .find_pane_by_name_recursive_expect("TitleBg") .as_picture(); let title_bg_material = &mut *title_bg.material; let is_selected = row == submenu.toggles.state.selected_row().unwrap() @@ -227,22 +217,18 @@ unsafe fn render_toggle_page(app: &mut App, root_pane: &Pane) { if use_check_icon { menu_button - .find_pane_by_name_recursive("check") - .unwrap() + .find_pane_by_name_recursive_expect("check") .set_visible(true); menu_button - .find_pane_by_name_recursive("Icon") - .unwrap() + .find_pane_by_name_recursive_expect("Icon") .set_visible(toggle.value > 0); } else { menu_button - .find_pane_by_name_recursive("check") - .unwrap() + .find_pane_by_name_recursive_expect("check") .set_visible(false); menu_button - .find_pane_by_name_recursive("Icon") - .unwrap() + .find_pane_by_name_recursive_expect("Icon") .set_visible(toggle.value > 0); // Note there's no pane for 0 @@ -265,51 +251,39 @@ unsafe fn render_slider_page(app: &mut App, root_pane: &Pane) { let selected_min = slider.lower; let selected_max = slider.upper; - let slider_pane = root_pane - .find_pane_by_name_recursive("TrModSlider") - .unwrap(); + let slider_pane = root_pane.find_pane_by_name_recursive_expect("TrModSlider"); slider_pane.set_visible(true); let _background = slider_pane - .find_pane_by_name_recursive("Background") - .unwrap() + .find_pane_by_name_recursive_expect("Background") .as_picture(); let header = slider_pane - .find_pane_by_name_recursive("Header") - .unwrap() + .find_pane_by_name_recursive_expect("Header") .as_textbox(); header.set_text_string(submenu.title); let min_button = slider_pane - .find_pane_by_name_recursive("MinButton") - .unwrap() + .find_pane_by_name_recursive_expect("MinButton") .as_picture(); let max_button = slider_pane - .find_pane_by_name_recursive("MaxButton") - .unwrap() + .find_pane_by_name_recursive_expect("MaxButton") .as_picture(); let min_title_text = min_button - .find_pane_by_name_recursive("TitleTxt") - .unwrap() + .find_pane_by_name_recursive_expect("TitleTxt") .as_textbox(); let min_title_bg = min_button - .find_pane_by_name_recursive("TitleBg") - .unwrap() + .find_pane_by_name_recursive_expect("TitleBg") .as_picture(); let min_value_text = min_button - .find_pane_by_name_recursive("ValueTxt") - .unwrap() + .find_pane_by_name_recursive_expect("ValueTxt") .as_textbox(); let max_title_text = max_button - .find_pane_by_name_recursive("TitleTxt") - .unwrap() + .find_pane_by_name_recursive_expect("TitleTxt") .as_textbox(); let max_title_bg = max_button - .find_pane_by_name_recursive("TitleBg") - .unwrap() + .find_pane_by_name_recursive_expect("TitleBg") .as_picture(); let max_value_text = max_button - .find_pane_by_name_recursive("ValueTxt") - .unwrap() + .find_pane_by_name_recursive_expect("ValueTxt") .as_textbox(); min_title_text.set_text_string("Min"); @@ -368,7 +342,7 @@ unsafe fn render_slider_page(app: &mut App, root_pane: &Pane) { // Hide the Icon pane for MinButton and MaxButton [min_button, max_button].iter().for_each(|button| { - let icon = button.find_pane_by_name_recursive("Icon").unwrap(); + let icon = button.find_pane_by_name_recursive_expect("Icon"); icon.set_visible(false); }); } @@ -388,8 +362,7 @@ unsafe fn render_confirmation_page(app: &mut App, root_pane: &Pane) { // Set help text root_pane - .find_pane_by_name_recursive("FooterTxt") - .unwrap() + .find_pane_by_name_recursive_expect("FooterTxt") .as_textbox() .set_text_string(help_text); @@ -397,24 +370,20 @@ unsafe fn render_confirmation_page(app: &mut App, root_pane: &Pane) { for row in 0..NX_SUBMENU_ROWS { let should_show_row = row == show_row; let menu_button_row = root_pane - .find_pane_by_name_recursive(format!("TrModMenuButtonRow{row}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("TrModMenuButtonRow{row}").as_str()); menu_button_row.set_visible(should_show_row); if should_show_row { for col in 0..NX_SUBMENU_COLUMNS { let should_show_col = show_cols.contains(&col); let menu_button = menu_button_row - .find_pane_by_name_recursive(format!("Button{col}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("Button{col}").as_str()); menu_button.set_visible(should_show_col); if should_show_col { let title_text = menu_button - .find_pane_by_name_recursive("TitleTxt") - .unwrap() + .find_pane_by_name_recursive_expect("TitleTxt") .as_textbox(); let title_bg = menu_button - .find_pane_by_name_recursive("TitleBg") - .unwrap() + .find_pane_by_name_recursive_expect("TitleBg") .as_picture(); let title_bg_material = &mut *title_bg.material; @@ -465,13 +434,12 @@ pub unsafe fn draw(root_pane: &Pane) { assign( &VANILLA_MENU_ACTIVE, root_pane - .find_pane_by_name_recursive("L_staying_help") - .unwrap() + .find_pane_by_name_recursive_expect("L_staying_help") .pos_y != -80.0, ); - let overall_parent_pane = root_pane.find_pane_by_name_recursive("TrModMenu").unwrap(); + let overall_parent_pane = root_pane.find_pane_by_name_recursive_expect("TrModMenu"); overall_parent_pane.set_visible(read(&QUICK_MENU_ACTIVE) && !read(&VANILLA_MENU_ACTIVE)); let menu_close_wait_frame = frame_counter::get_frame_count(*MENU_CLOSE_FRAME_COUNTER); fade_out( @@ -499,19 +467,17 @@ pub unsafe fn draw(root_pane: &Pane) { // Make all invisible first for row_idx in 0..NX_SUBMENU_ROWS { for col_idx in 0..NX_SUBMENU_COLUMNS { - let menu_button_row = root_pane - .find_pane_by_name_recursive(format!("TrModMenuButtonRow{row_idx}").as_str()) - .unwrap(); + let menu_button_row = root_pane.find_pane_by_name_recursive_expect( + format!("TrModMenuButtonRow{row_idx}").as_str(), + ); menu_button_row.set_visible(false); let menu_button = menu_button_row - .find_pane_by_name_recursive(format!("Button{col_idx}").as_str()) - .unwrap(); + .find_pane_by_name_recursive_expect(format!("Button{col_idx}").as_str()); menu_button.set_visible(false); menu_button - .find_pane_by_name_recursive("ValueTxt") - .unwrap() + .find_pane_by_name_recursive_expect("ValueTxt") .set_visible(false); } } @@ -525,8 +491,7 @@ pub unsafe fn draw(root_pane: &Pane) { status_r_pane.set_visible(!read(&QUICK_MENU_ACTIVE)); root_pane - .find_pane_by_name_recursive("TrModSlider") - .unwrap() + .find_pane_by_name_recursive_expect("TrModSlider") .set_visible(false); // Update menu display @@ -577,15 +542,13 @@ pub unsafe fn draw(root_pane: &Pane) { .iter() .enumerate() .for_each(|(idx, (key, name))| { - let key_help_pane = root_pane.find_pane_by_name_recursive(name).unwrap(); + let key_help_pane = root_pane.find_pane_by_name_recursive_expect(name); let icon_pane = key_help_pane - .find_pane_by_name_recursive("set_txt_icon") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_icon") .as_textbox(); let help_pane = key_help_pane - .find_pane_by_name_recursive("set_txt_help") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_help") .as_textbox(); icon_pane.set_text_string(""); @@ -607,15 +570,13 @@ pub unsafe fn draw(root_pane: &Pane) { let name = "SaveDefaults"; let key = save_defaults_key; let title = "Save Defaults"; - let key_help_pane = root_pane.find_pane_by_name_recursive(name).unwrap(); + let key_help_pane = root_pane.find_pane_by_name_recursive_expect(name); let icon_pane = key_help_pane - .find_pane_by_name_recursive("set_txt_icon") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_icon") .as_textbox(); set_icon_text(icon_pane, &[*key.unwrap()]); key_help_pane - .find_pane_by_name_recursive("set_txt_help") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_help") .as_textbox() .set_text_string(title); @@ -630,33 +591,28 @@ pub unsafe fn draw(root_pane: &Pane) { AppPage::CLOSE => "", }; if !title.is_empty() { - let key_help_pane = root_pane.find_pane_by_name_recursive(name).unwrap(); + let key_help_pane = root_pane.find_pane_by_name_recursive_expect(name); let icon_pane = key_help_pane - .find_pane_by_name_recursive("set_txt_icon") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_icon") .as_textbox(); set_icon_text(icon_pane, &[*key.unwrap()]); key_help_pane - .find_pane_by_name_recursive("set_txt_help") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_help") .as_textbox() .set_text_string(title); } // Clear Toggle Keyhelp let name = "ClearToggle"; - let key_help_pane = root_pane.find_pane_by_name_recursive(name).unwrap(); - let icon_pane = key_help_pane - .find_pane_by_name_recursive("set_txt_icon") - .unwrap(); + let key_help_pane = root_pane.find_pane_by_name_recursive_expect(name); + let icon_pane = key_help_pane.find_pane_by_name_recursive_expect("set_txt_icon"); if app.should_show_clear_keyhelp() { // This is only displayed when you're in a multiple selection toggle menu w/ toggle.max > 1 let key = clear_toggle_key; let title = "Clear Toggle"; set_icon_text(icon_pane.as_textbox(), &[*key.unwrap()]); key_help_pane - .find_pane_by_name_recursive("set_txt_help") - .unwrap() + .find_pane_by_name_recursive_expect("set_txt_help") .as_textbox() .set_text_string(title); icon_pane.set_visible(true); diff --git a/src/training/ui/mod.rs b/src/training/ui/mod.rs index a163ce2c8..f912fe198 100644 --- a/src/training/ui/mod.rs +++ b/src/training/ui/mod.rs @@ -2,7 +2,7 @@ use byte_unit::MEBIBYTE; use sarc::SarcFile; use skyline::nn::ui2d::*; -use smash::ui2d::SmashTextBox; +use smash::ui2d::{SmashPane, SmashTextBox}; use training_mod_consts::{OnOff, MENU}; use crate::common::menu::QUICK_MENU_ACTIVE; @@ -142,7 +142,7 @@ unsafe fn handle_layout_arc_malloc(ctx: &mut skyline::hooks::InlineCtx) { decompressed_file, decompressed_size, )) - .unwrap(); + .expect("Could not read layout.arc SarcFile!"); let training_layout = layout_arc.files.iter().find(|f| { f.name.is_some() && f.name.as_ref().unwrap() == &String::from("blyt/info_training.bflyt") }); @@ -156,7 +156,8 @@ unsafe fn handle_layout_arc_malloc(ctx: &mut skyline::hooks::InlineCtx) { #[cfg(feature = "layout_arc_from_file")] #[allow(static_mut_refs)] { - let inject_arc_from_file = std::fs::read(LAYOUT_ARC_PATH).unwrap(); + let inject_arc_from_file = + std::fs::read(LAYOUT_ARC_PATH).expect("Could not read layout.arc from file!"); inject_arc_size = inject_arc_from_file.len() as u64; // Copy read file to global @@ -184,6 +185,17 @@ unsafe fn handle_layout_arc_malloc(ctx: &mut skyline::hooks::InlineCtx) { ctx.registers[24].set_x(inject_arc_size); } +pub trait PaneExt { + unsafe fn find_pane_by_name_recursive_expect(&self, name: &str) -> &mut Pane; +} + +impl PaneExt for Pane { + unsafe fn find_pane_by_name_recursive_expect(&self, name: &str) -> &mut Pane { + self.find_pane_by_name_recursive(name) + .expect(&format!("Could not find pane {name}")) + } +} + pub fn init() { skyline::install_hooks!(handle_draw, handle_layout_arc_malloc); } From 034ce48161e7c47963d80dbb2976450b500822c2 Mon Sep 17 00:00:00 2001 From: asimon-1 <40246417+asimon-1@users.noreply.github.com> Date: Thu, 23 Oct 2025 18:38:10 -0400 Subject: [PATCH 6/8] Additional expects --- src/lib.rs | 4 ++-- src/training/buff.rs | 13 ++++++++++--- src/training/ui/damage.rs | 5 ++++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 253d281dd..80dde90bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,7 +119,7 @@ pub fn main() { .spawn(move || { menu::load_from_file(); }) - .unwrap(); + .expect("Couldn't create data loader thread"); let _result = data_loader.join(); if !is_emulator() { @@ -129,7 +129,7 @@ pub fn main() { .spawn(move || { release::perform_version_check(); }) - .unwrap(); + .expect("Couldn't create version check thread"); let _result = _updater.join(); } else { info!("Skipping version check because we are using an emulator"); diff --git a/src/training/buff.rs b/src/training/buff.rs index 90e4848a3..3ac4a6953 100644 --- a/src/training/buff.rs +++ b/src/training/buff.rs @@ -140,7 +140,10 @@ unsafe fn buff_hero_single( // There are no spells selected, or something went wrong with making the vector return; } - let real_spell_value = spell_option.unwrap().into_int().unwrap(); + let real_spell_value = spell_option + .unwrap() + .into_int() + .expect("Invalid option for spell_option"); if status != FIGHTER_BRAVE_STATUS_KIND_SPECIAL_LW_START { WorkModule::set_int( module_accessor, @@ -267,7 +270,9 @@ unsafe fn buff_wario(module_accessor: &mut app::BattleObjectModuleAccessor) -> b ); WorkModule::set_int( module_accessor, - waft_level.into_int().unwrap(), + waft_level + .into_int() + .expect("Invalid option for waft_level"), *FIGHTER_WARIO_INSTANCE_WORK_ID_INT_GASS_LEVEL, ); } @@ -293,7 +298,9 @@ unsafe fn buff_shulk(module_accessor: &mut app::BattleObjectModuleAccessor, stat if status != FIGHTER_SHULK_STATUS_KIND_SPECIAL_N_ACTION { WorkModule::set_int( module_accessor, - current_art.into_int().unwrap(), + current_art + .into_int() + .expect("Invalid option for current_art"), *FIGHTER_SHULK_INSTANCE_WORK_ID_INT_SPECIAL_N_TYPE_SELECT, ); WorkModule::set_int( diff --git a/src/training/ui/damage.rs b/src/training/ui/damage.rs index e54a4ae91..bd41cb49c 100644 --- a/src/training/ui/damage.rs +++ b/src/training/ui/damage.rs @@ -15,7 +15,10 @@ pub unsafe fn iterate_anim_list( if curr != (*curr).next { let anim_transform = (curr as *mut u64).add(2) as *mut AnimTransform; - parse_anim_transform(anim_transform.as_mut().unwrap(), layout_name); + parse_anim_transform( + anim_transform.as_mut().expect("Invalid anim_transform"), + layout_name, + ); } curr = (*curr).next; From ac86150be625eb2a9383ece0f26c27690a5a1f77 Mon Sep 17 00:00:00 2001 From: asimon-1 <40246417+asimon-1@users.noreply.github.com> Date: Sun, 26 Oct 2025 15:53:33 -0400 Subject: [PATCH 7/8] More unwraps to expects --- src/common/events.rs | 2 +- src/common/release.rs | 6 +- src/lib.rs | 8 +- src/training/buff.rs | 44 +- src/training/charge.rs | 10 +- src/training/input_log.rs | 755 +++++++++++++++--------------- src/training/input_record.rs | 49 +- src/training/mod.rs | 7 +- src/training/shield.rs | 4 +- src/training/ui/display.rs | 2 +- training_mod_consts/src/config.rs | 2 +- training_mod_sync/src/lib.rs | 10 +- 12 files changed, 451 insertions(+), 448 deletions(-) diff --git a/src/common/events.rs b/src/common/events.rs index c1a5965e1..e3208c6eb 100644 --- a/src/common/events.rs +++ b/src/common/events.rs @@ -26,7 +26,7 @@ static SESSION_ID: LazyLock = LazyLock::new(|| unsafe { let session_id_bytes: [u8; 32] = [event_time_bytes, device_uuid.data] .concat() .try_into() - .unwrap(); + .expect("Session_id_bytes not the correct length"); GenerateSha256Hash( &mut session_id_hash as *mut _ as *mut c_void, diff --git a/src/common/release.rs b/src/common/release.rs index 49e7b9c1a..b4257929a 100644 --- a/src/common/release.rs +++ b/src/common/release.rs @@ -185,11 +185,11 @@ pub fn perform_version_check() { } _ => panic!("Invalid value in perform_version_check: {}", update_policy), }; - if release_to_apply.is_ok() { - let published_at = release_to_apply.as_ref().unwrap().published_at.clone(); + if let Ok(release) = release_to_apply.as_ref() { + let published_at = release.published_at.clone(); info!("Current version: {}", *CURRENT_VERSION); info!("Github version: {}", published_at); - if release_to_apply.as_ref().unwrap().is_older_than_installed() { + if release.is_older_than_installed() { release_to_apply = Err(anyhow!( "Github version is not newer than the current installed version.", )) diff --git a/src/lib.rs b/src/lib.rs index 80dde90bf..3288ba831 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,15 +93,17 @@ pub fn main() { hitbox_visualizer::hitbox_visualization(); hazard_manager::hazard_manager(); training::training_mods(); - nro::add_hook(nro_main).unwrap(); + nro::add_hook(nro_main).expect("Did not find nro_hook plugin!"); fs::create_dir_all(TRAINING_MODPACK_ROOT) .expect("Could not create Training Modpack root folder!"); // Migrate legacy if exists if fs::metadata(LEGACY_TRAINING_MODPACK_ROOT).is_ok() { - for entry in fs::read_dir(LEGACY_TRAINING_MODPACK_ROOT).unwrap() { - let entry = entry.unwrap(); + for entry in + fs::read_dir(LEGACY_TRAINING_MODPACK_ROOT).expect("Couldn't read legacy folder") + { + let entry = entry.expect("Couldn't read legacy file during migration"); let src_path = &entry.path(); let dest_path = &PathBuf::from(TRAINING_MODPACK_ROOT).join(entry.file_name()); fs::rename(src_path, dest_path).unwrap_or_else(|e| { diff --git a/src/training/buff.rs b/src/training/buff.rs index 3ac4a6953..bdbd688a6 100644 --- a/src/training/buff.rs +++ b/src/training/buff.rs @@ -135,30 +135,26 @@ unsafe fn buff_hero_single( } let spell_index = get_buff_rem(module_accessor) - 1; // Used to get spell from our vector - let spell_option = buff_vec.get(spell_index); - if spell_option.is_none() { - // There are no spells selected, or something went wrong with making the vector - return; - } - let real_spell_value = spell_option - .unwrap() - .into_int() - .expect("Invalid option for spell_option"); - if status != FIGHTER_BRAVE_STATUS_KIND_SPECIAL_LW_START { - WorkModule::set_int( - module_accessor, - real_spell_value, - *FIGHTER_BRAVE_INSTANCE_WORK_ID_INT_SPECIAL_LW_DECIDE_COMMAND, - ); - StatusModule::change_status_force( - module_accessor, - *FIGHTER_BRAVE_STATUS_KIND_SPECIAL_LW_START, - true, - // True to prevent Shielding over the spells - ); - } - if status == FIGHTER_BRAVE_STATUS_KIND_SPECIAL_LW_START { - MotionModule::set_rate(module_accessor, 50.0); + if let Some(spell_option) = buff_vec.get(spell_index) { + let real_spell_value = spell_option + .into_int() + .expect("Invalid option for spell_option"); + if status != FIGHTER_BRAVE_STATUS_KIND_SPECIAL_LW_START { + WorkModule::set_int( + module_accessor, + real_spell_value, + *FIGHTER_BRAVE_INSTANCE_WORK_ID_INT_SPECIAL_LW_DECIDE_COMMAND, + ); + StatusModule::change_status_force( + module_accessor, + *FIGHTER_BRAVE_STATUS_KIND_SPECIAL_LW_START, + true, + // True to prevent Shielding over the spells + ); + } + if status == FIGHTER_BRAVE_STATUS_KIND_SPECIAL_LW_START { + MotionModule::set_rate(module_accessor, 50.0); + } } } diff --git a/src/training/charge.rs b/src/training/charge.rs index 9d5e79f97..a172ca267 100644 --- a/src/training/charge.rs +++ b/src/training/charge.rs @@ -511,7 +511,15 @@ pub unsafe fn handle_charge( let opponent_matches_fighter = kirby::is_kirby_hat_okay(opponent_module_accessor, charge.int_z); if opponent_matches_fighter == Some(true) { - copy_setup(module_accessor, 1, charge.int_z.unwrap(), true, false); + copy_setup( + module_accessor, + 1, + charge + .int_z + .expect("charge.int_z is None in handle_charge::Kirby"), + true, + false, + ); //kirby::handle_kirby_hat_charge(module_accessor, charge.int_z.unwrap(), charge); } }); diff --git a/src/training/input_log.rs b/src/training/input_log.rs index 484e1ece2..f1ea89458 100644 --- a/src/training/input_log.rs +++ b/src/training/input_log.rs @@ -1,378 +1,377 @@ -use itertools::Itertools; -use std::collections::VecDeque; - -use crate::common::input::*; -use crate::menu::QUICK_MENU_ACTIVE; -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}; - -const GREEN: ResColor = ResColor { - r: 22, - g: 156, - b: 0, - a: 0, -}; - -const RED: ResColor = ResColor { - r: 153, - g: 10, - b: 10, - a: 0, -}; - -const CYAN: ResColor = ResColor { - r: 0, - g: 255, - b: 255, - a: 0, -}; - -const BLUE: ResColor = ResColor { - r: 0, - g: 40, - b: 108, - a: 0, -}; - -const PURPLE: ResColor = ResColor { - r: 100, - g: 66, - b: 202, - a: 0, -}; - -pub const YELLOW: ResColor = ResColor { - r: 230, - g: 180, - b: 14, - a: 0, -}; - -pub const WHITE: ResColor = ResColor { - r: 255, - g: 255, - b: 255, - a: 0, -}; - -pub static PER_LOG_FRAME_COUNTER: LazyLock = LazyLock::new(|| { - frame_counter::register_counter(frame_counter::FrameCounterType::InGameNoReset) -}); -pub static OVERALL_FRAME_COUNTER: LazyLock = LazyLock::new(|| { - frame_counter::register_counter(frame_counter::FrameCounterType::InGameNoReset) -}); - -pub const NUM_LOGS: usize = 15; -pub static DRAW_LOG_BASE_IDX: RwLock = RwLock::new(0); - -#[derive(PartialEq, Eq, Debug, Copy, Clone)] -pub enum DirectionStrength { - None, - Weak, - // Strong, -} - -#[derive(Copy, Clone, Default)] -pub struct InputLog { - pub ttl: u32, - pub frames: u32, - pub overall_frame: u32, - pub raw_inputs: Controller, - pub smash_inputs: MappedInputs, - pub status: i32, - pub fighter_kind: i32, -} - -impl PartialEq for InputLog { - fn eq(&self, other: &Self) -> bool { - self.frames == other.frames && !self.is_different(other) - } -} -impl Eq for InputLog {} - -const WALK_THRESHOLD_X: i8 = 20; -const _DASH_THRESHOLD_X: i8 = 102; -const DEADZONE_THRESHOLD_Y: i8 = 30; -const _TAP_JUMP_THRESHOLD_Y: i8 = 90; - -fn bin_stick_values(x: i8, y: i8) -> (DirectionStrength, f32) { - ( - // TODO - DirectionStrength::Weak, - match (x, y) { - // X only - (x, y) if y.abs() < DEADZONE_THRESHOLD_Y => match x { - x if x > WALK_THRESHOLD_X => 0.0, - x if x < -WALK_THRESHOLD_X => 180.0, - _ => return (DirectionStrength::None, 0.0), - }, - // Y only - (x, y) if x.abs() < WALK_THRESHOLD_X => match y { - y if y > DEADZONE_THRESHOLD_Y => 90.0, - y if y < -DEADZONE_THRESHOLD_Y => 270.0, - _ => return (DirectionStrength::None, 0.0), - }, - // Positive Y - (x, y) if y > DEADZONE_THRESHOLD_Y => match x { - x if x > WALK_THRESHOLD_X => 45.0, - x if x < -WALK_THRESHOLD_X => 135.0, - _ => return (DirectionStrength::Weak, 90.0), - }, - // Negative Y - (x, y) if y < DEADZONE_THRESHOLD_Y => match x { - x if x > WALK_THRESHOLD_X => 315.0, - x if x < -WALK_THRESHOLD_X => 225.0, - _ => return (DirectionStrength::Weak, 270.0), - }, - _ => return (DirectionStrength::None, 0.0), - }, - ) -} - -impl InputLog { - pub fn is_different(&self, other: &InputLog) -> bool { - match read(&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: {}", - read(&MENU).input_display - ), - } - } - - pub fn binned_lstick(&self) -> (DirectionStrength, f32) { - match read(&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: {}", - read(&MENU).input_display - ), - } - } - - pub fn binned_rstick(&self) -> (DirectionStrength, f32) { - match read(&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: {}", - read(&MENU).input_display - ), - } - } - - pub fn button_icons(&self) -> VecDeque<(&str, ResColor)> { - match read(&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!(), - } - } - - fn smash_button_icons(&self) -> VecDeque<(&str, ResColor)> { - self.smash_inputs - .buttons - .to_vec() - .iter() - .filter_map(|button| { - Some(match *button { - Buttons::ATTACK | Buttons::ATTACK_RAW => ("a", GREEN), - Buttons::SPECIAL | Buttons::SPECIAL_RAW2 => ("b", RED), - Buttons::JUMP => ("x", CYAN), - Buttons::GUARD | Buttons::GUARD_HOLD => ("lb", BLUE), - Buttons::CATCH => ("zr", PURPLE), - Buttons::STOCK_SHARE => ("plus", WHITE), - Buttons::APPEAL_HI => ("dpad_up", WHITE), - Buttons::APPEAL_LW => ("dpad_down", WHITE), - Buttons::APPEAL_SL => ("dpad_right", WHITE), - Buttons::APPEAL_SR => ("dpad_left", WHITE), - _ => return None, - }) - }) - .unique_by(|(s, _)| *s) - .collect::>() - } - - fn raw_button_icons(&self) -> VecDeque<(&str, ResColor)> { - let buttons = self.raw_inputs.current_buttons; - let mut icons = VecDeque::new(); - if buttons.a() { - icons.push_front(("a", GREEN)); - } - if buttons.b() { - icons.push_front(("b", RED)); - } - if buttons.x() { - icons.push_front(("x", CYAN)); - } - if buttons.y() { - icons.push_front(("y", CYAN)); - } - if buttons.l() || buttons.real_digital_l() { - icons.push_front(("lb", BLUE)); - } - if buttons.r() || buttons.real_digital_r() { - icons.push_front(("rb", BLUE)); - } - if buttons.zl() { - icons.push_front(("zl", PURPLE)); - } - if buttons.zr() { - icons.push_front(("zr", PURPLE)); - } - if buttons.plus() { - icons.push_front(("plus", WHITE)); - } - if buttons.minus() { - icons.push_front(("minus", WHITE)); - } - if buttons.dpad_up() { - icons.push_front(("dpad_up", WHITE)); - } - if buttons.dpad_down() { - icons.push_front(("dpad_down", WHITE)); - } - if buttons.dpad_left() { - icons.push_front(("dpad_left", WHITE)); - } - if buttons.dpad_right() { - icons.push_front(("dpad_right", WHITE)); - } - - icons - } - - fn is_smash_different(&self, other: &InputLog) -> bool { - self.smash_inputs.buttons != other.smash_inputs.buttons - || self.smash_binned_lstick() != other.smash_binned_lstick() - || self.smash_binned_rstick() != other.smash_binned_rstick() - || (read(&MENU).input_display_status.as_bool() && self.status != other.status) - } - - fn is_status_different(&self, other: &InputLog) -> bool { - let input_display_status = read(&MENU).input_display_status.as_bool(); - input_display_status && (self.status != other.status) - } - - fn smash_binned_lstick(&self) -> (DirectionStrength, f32) { - bin_stick_values(self.smash_inputs.lstick_x, self.smash_inputs.lstick_y) - } - - fn smash_binned_rstick(&self) -> (DirectionStrength, f32) { - bin_stick_values(self.smash_inputs.rstick_x, self.smash_inputs.rstick_y) - } - - fn is_raw_different(&self, other: &InputLog) -> bool { - 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() - || (read(&MENU).input_display_status.as_bool() && self.status != other.status) - } - - fn raw_binned_lstick(&self) -> (DirectionStrength, f32) { - let x = (self.raw_inputs.left_stick_x / STICK_CLAMP_MULTIPLIER) as i8; - let y = (self.raw_inputs.left_stick_y / STICK_CLAMP_MULTIPLIER) as i8; - bin_stick_values(x, y) - } - - fn raw_binned_rstick(&self) -> (DirectionStrength, f32) { - let x = (self.raw_inputs.right_stick_x / STICK_CLAMP_MULTIPLIER) as i8; - let y = (self.raw_inputs.right_stick_y / STICK_CLAMP_MULTIPLIER) as i8; - bin_stick_values(x, y) - } -} - -fn insert_in_place(array: &mut [T], value: T, index: usize) { - array[index..].rotate_right(1); - array[index] = value; -} - -fn insert_in_front(array: &mut [T], value: T) { - insert_in_place(array, value, 0); -} - -pub static P1_INPUT_LOGS: LazyLock> = - LazyLock::new(|| RwLock::new([InputLog::default(); NUM_LOGS])); - -pub fn handle_final_input_mapping( - player_idx: i32, - controller_struct: &SomeControllerStruct, - out: *mut MappedInputs, -) { - unsafe { - if read(&MENU).input_display == InputDisplay::NONE { - return; - } - - if read(&QUICK_MENU_ACTIVE) { - return; - } - - if player_idx == 0 { - let module_accessor = try_get_module_accessor(FighterId::Player); - if module_accessor.is_none() { - return; - } - let module_accessor = module_accessor.unwrap(); - - let current_frame = frame_counter::get_frame_count(*PER_LOG_FRAME_COUNTER); - let current_overall_frame = frame_counter::get_frame_count(*OVERALL_FRAME_COUNTER); - // We should always be counting - frame_counter::start_counting(*PER_LOG_FRAME_COUNTER); - frame_counter::start_counting(*OVERALL_FRAME_COUNTER); - - let potential_input_log = InputLog { - ttl: 600, - frames: 1, - overall_frame: current_overall_frame, - raw_inputs: *controller_struct.controller, - smash_inputs: *out, - status: StatusModule::status_kind(module_accessor), - fighter_kind: utility::get_kind(&mut *module_accessor), - }; - - let mut input_logs_lock = lock_write(&(*P1_INPUT_LOGS)); - let input_logs = &mut *input_logs_lock; - let latest_input_log = input_logs.first_mut().unwrap(); - let prev_overall_frames = latest_input_log.overall_frame; - let prev_ttl = latest_input_log.ttl; - // Only update if we are on a new frame according to the latest log - let is_new_frame = prev_overall_frames != current_overall_frame; - if is_new_frame && latest_input_log.is_different(&potential_input_log) { - frame_counter::reset_frame_count(*PER_LOG_FRAME_COUNTER); - // We should count this frame already - frame_counter::tick_idx(*PER_LOG_FRAME_COUNTER); - insert_in_front(input_logs, potential_input_log); - let mut draw_log_base_idx_lock = lock_write(&DRAW_LOG_BASE_IDX); - *draw_log_base_idx_lock = (*draw_log_base_idx_lock + 1) % NUM_LOGS; - drop(draw_log_base_idx_lock); - } else if is_new_frame { - *latest_input_log = potential_input_log; - latest_input_log.frames = std::cmp::min(current_frame, 99); - latest_input_log.ttl = prev_ttl; - } - - // Decrease TTL - for input_log in input_logs.iter_mut() { - if input_log.ttl > 0 && is_new_frame { - input_log.ttl -= 1; - } - } - } - } -} +use itertools::Itertools; +use std::collections::VecDeque; + +use crate::common::input::*; +use crate::menu::QUICK_MENU_ACTIVE; +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}; + +const GREEN: ResColor = ResColor { + r: 22, + g: 156, + b: 0, + a: 0, +}; + +const RED: ResColor = ResColor { + r: 153, + g: 10, + b: 10, + a: 0, +}; + +const CYAN: ResColor = ResColor { + r: 0, + g: 255, + b: 255, + a: 0, +}; + +const BLUE: ResColor = ResColor { + r: 0, + g: 40, + b: 108, + a: 0, +}; + +const PURPLE: ResColor = ResColor { + r: 100, + g: 66, + b: 202, + a: 0, +}; + +pub const YELLOW: ResColor = ResColor { + r: 230, + g: 180, + b: 14, + a: 0, +}; + +pub const WHITE: ResColor = ResColor { + r: 255, + g: 255, + b: 255, + a: 0, +}; + +pub static PER_LOG_FRAME_COUNTER: LazyLock = LazyLock::new(|| { + frame_counter::register_counter(frame_counter::FrameCounterType::InGameNoReset) +}); +pub static OVERALL_FRAME_COUNTER: LazyLock = LazyLock::new(|| { + frame_counter::register_counter(frame_counter::FrameCounterType::InGameNoReset) +}); + +pub const NUM_LOGS: usize = 15; +pub static DRAW_LOG_BASE_IDX: RwLock = RwLock::new(0); + +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum DirectionStrength { + None, + Weak, + // Strong, +} + +#[derive(Copy, Clone, Default)] +pub struct InputLog { + pub ttl: u32, + pub frames: u32, + pub overall_frame: u32, + pub raw_inputs: Controller, + pub smash_inputs: MappedInputs, + pub status: i32, + pub fighter_kind: i32, +} + +impl PartialEq for InputLog { + fn eq(&self, other: &Self) -> bool { + self.frames == other.frames && !self.is_different(other) + } +} +impl Eq for InputLog {} + +const WALK_THRESHOLD_X: i8 = 20; +const _DASH_THRESHOLD_X: i8 = 102; +const DEADZONE_THRESHOLD_Y: i8 = 30; +const _TAP_JUMP_THRESHOLD_Y: i8 = 90; + +fn bin_stick_values(x: i8, y: i8) -> (DirectionStrength, f32) { + ( + // TODO + DirectionStrength::Weak, + match (x, y) { + // X only + (x, y) if y.abs() < DEADZONE_THRESHOLD_Y => match x { + x if x > WALK_THRESHOLD_X => 0.0, + x if x < -WALK_THRESHOLD_X => 180.0, + _ => return (DirectionStrength::None, 0.0), + }, + // Y only + (x, y) if x.abs() < WALK_THRESHOLD_X => match y { + y if y > DEADZONE_THRESHOLD_Y => 90.0, + y if y < -DEADZONE_THRESHOLD_Y => 270.0, + _ => return (DirectionStrength::None, 0.0), + }, + // Positive Y + (x, y) if y > DEADZONE_THRESHOLD_Y => match x { + x if x > WALK_THRESHOLD_X => 45.0, + x if x < -WALK_THRESHOLD_X => 135.0, + _ => return (DirectionStrength::Weak, 90.0), + }, + // Negative Y + (x, y) if y < DEADZONE_THRESHOLD_Y => match x { + x if x > WALK_THRESHOLD_X => 315.0, + x if x < -WALK_THRESHOLD_X => 225.0, + _ => return (DirectionStrength::Weak, 270.0), + }, + _ => return (DirectionStrength::None, 0.0), + }, + ) +} + +impl InputLog { + pub fn is_different(&self, other: &InputLog) -> bool { + match read(&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: {}", + read(&MENU).input_display + ), + } + } + + pub fn binned_lstick(&self) -> (DirectionStrength, f32) { + match read(&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: {}", + read(&MENU).input_display + ), + } + } + + pub fn binned_rstick(&self) -> (DirectionStrength, f32) { + match read(&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: {}", + read(&MENU).input_display + ), + } + } + + pub fn button_icons(&self) -> VecDeque<(&str, ResColor)> { + match read(&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!(), + } + } + + fn smash_button_icons(&self) -> VecDeque<(&str, ResColor)> { + self.smash_inputs + .buttons + .to_vec() + .iter() + .filter_map(|button| { + Some(match *button { + Buttons::ATTACK | Buttons::ATTACK_RAW => ("a", GREEN), + Buttons::SPECIAL | Buttons::SPECIAL_RAW2 => ("b", RED), + Buttons::JUMP => ("x", CYAN), + Buttons::GUARD | Buttons::GUARD_HOLD => ("lb", BLUE), + Buttons::CATCH => ("zr", PURPLE), + Buttons::STOCK_SHARE => ("plus", WHITE), + Buttons::APPEAL_HI => ("dpad_up", WHITE), + Buttons::APPEAL_LW => ("dpad_down", WHITE), + Buttons::APPEAL_SL => ("dpad_right", WHITE), + Buttons::APPEAL_SR => ("dpad_left", WHITE), + _ => return None, + }) + }) + .unique_by(|(s, _)| *s) + .collect::>() + } + + fn raw_button_icons(&self) -> VecDeque<(&str, ResColor)> { + let buttons = self.raw_inputs.current_buttons; + let mut icons = VecDeque::new(); + if buttons.a() { + icons.push_front(("a", GREEN)); + } + if buttons.b() { + icons.push_front(("b", RED)); + } + if buttons.x() { + icons.push_front(("x", CYAN)); + } + if buttons.y() { + icons.push_front(("y", CYAN)); + } + if buttons.l() || buttons.real_digital_l() { + icons.push_front(("lb", BLUE)); + } + if buttons.r() || buttons.real_digital_r() { + icons.push_front(("rb", BLUE)); + } + if buttons.zl() { + icons.push_front(("zl", PURPLE)); + } + if buttons.zr() { + icons.push_front(("zr", PURPLE)); + } + if buttons.plus() { + icons.push_front(("plus", WHITE)); + } + if buttons.minus() { + icons.push_front(("minus", WHITE)); + } + if buttons.dpad_up() { + icons.push_front(("dpad_up", WHITE)); + } + if buttons.dpad_down() { + icons.push_front(("dpad_down", WHITE)); + } + if buttons.dpad_left() { + icons.push_front(("dpad_left", WHITE)); + } + if buttons.dpad_right() { + icons.push_front(("dpad_right", WHITE)); + } + + icons + } + + fn is_smash_different(&self, other: &InputLog) -> bool { + self.smash_inputs.buttons != other.smash_inputs.buttons + || self.smash_binned_lstick() != other.smash_binned_lstick() + || self.smash_binned_rstick() != other.smash_binned_rstick() + || (read(&MENU).input_display_status.as_bool() && self.status != other.status) + } + + fn is_status_different(&self, other: &InputLog) -> bool { + let input_display_status = read(&MENU).input_display_status.as_bool(); + input_display_status && (self.status != other.status) + } + + fn smash_binned_lstick(&self) -> (DirectionStrength, f32) { + bin_stick_values(self.smash_inputs.lstick_x, self.smash_inputs.lstick_y) + } + + fn smash_binned_rstick(&self) -> (DirectionStrength, f32) { + bin_stick_values(self.smash_inputs.rstick_x, self.smash_inputs.rstick_y) + } + + fn is_raw_different(&self, other: &InputLog) -> bool { + 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() + || (read(&MENU).input_display_status.as_bool() && self.status != other.status) + } + + fn raw_binned_lstick(&self) -> (DirectionStrength, f32) { + let x = (self.raw_inputs.left_stick_x / STICK_CLAMP_MULTIPLIER) as i8; + let y = (self.raw_inputs.left_stick_y / STICK_CLAMP_MULTIPLIER) as i8; + bin_stick_values(x, y) + } + + fn raw_binned_rstick(&self) -> (DirectionStrength, f32) { + let x = (self.raw_inputs.right_stick_x / STICK_CLAMP_MULTIPLIER) as i8; + let y = (self.raw_inputs.right_stick_y / STICK_CLAMP_MULTIPLIER) as i8; + bin_stick_values(x, y) + } +} + +fn insert_in_place(array: &mut [T], value: T, index: usize) { + array[index..].rotate_right(1); + array[index] = value; +} + +fn insert_in_front(array: &mut [T], value: T) { + insert_in_place(array, value, 0); +} + +pub static P1_INPUT_LOGS: LazyLock> = + LazyLock::new(|| RwLock::new([InputLog::default(); NUM_LOGS])); + +pub fn handle_final_input_mapping( + player_idx: i32, + controller_struct: &SomeControllerStruct, + out: *mut MappedInputs, +) { + unsafe { + if read(&MENU).input_display == InputDisplay::NONE { + return; + } + + if read(&QUICK_MENU_ACTIVE) { + return; + } + + if player_idx == 0 { + let module_accessor = try_get_module_accessor(FighterId::Player); + if let Some(module_accessor) = module_accessor { + let current_frame = frame_counter::get_frame_count(*PER_LOG_FRAME_COUNTER); + let current_overall_frame = frame_counter::get_frame_count(*OVERALL_FRAME_COUNTER); + // We should always be counting + frame_counter::start_counting(*PER_LOG_FRAME_COUNTER); + frame_counter::start_counting(*OVERALL_FRAME_COUNTER); + + let potential_input_log = InputLog { + ttl: 600, + frames: 1, + overall_frame: current_overall_frame, + raw_inputs: *controller_struct.controller, + smash_inputs: *out, + status: StatusModule::status_kind(module_accessor), + fighter_kind: utility::get_kind(&mut *module_accessor), + }; + + let mut input_logs_lock = lock_write(&(*P1_INPUT_LOGS)); + let input_logs = &mut *input_logs_lock; + let latest_input_log = input_logs + .first_mut() + .expect("input_logs is empty in handle_final_input_mapping"); + let prev_overall_frames = latest_input_log.overall_frame; + let prev_ttl = latest_input_log.ttl; + // Only update if we are on a new frame according to the latest log + let is_new_frame = prev_overall_frames != current_overall_frame; + if is_new_frame && latest_input_log.is_different(&potential_input_log) { + frame_counter::reset_frame_count(*PER_LOG_FRAME_COUNTER); + // We should count this frame already + frame_counter::tick_idx(*PER_LOG_FRAME_COUNTER); + insert_in_front(input_logs, potential_input_log); + let mut draw_log_base_idx_lock = lock_write(&DRAW_LOG_BASE_IDX); + *draw_log_base_idx_lock = (*draw_log_base_idx_lock + 1) % NUM_LOGS; + drop(draw_log_base_idx_lock); + } else if is_new_frame { + *latest_input_log = potential_input_log; + latest_input_log.frames = std::cmp::min(current_frame, 99); + latest_input_log.ttl = prev_ttl; + } + + // Decrease TTL + for input_log in input_logs.iter_mut() { + if input_log.ttl > 0 && is_new_frame { + input_log.ttl -= 1; + } + } + } + } + } +} diff --git a/src/training/input_record.rs b/src/training/input_record.rs index 201278c73..c8a139050 100644 --- a/src/training/input_record.rs +++ b/src/training/input_record.rs @@ -170,13 +170,12 @@ fn into_transition_term(starting_status: StartingStatus) -> i32 { } } -#[allow(clippy::unnecessary_unwrap)] pub unsafe fn handle_recording() { - let player_module_accessor = try_get_module_accessor(FighterId::Player); - let cpu_module_accessor = try_get_module_accessor(FighterId::CPU); - if player_module_accessor.is_some() && cpu_module_accessor.is_some() { - handle_recording_for_fighter(&mut *player_module_accessor.unwrap()); - handle_recording_for_fighter(&mut *cpu_module_accessor.unwrap()); + if let Some(player_module_accessor) = try_get_module_accessor(FighterId::Player) { + if let Some(cpu_module_accessor) = try_get_module_accessor(FighterId::CPU) { + handle_recording_for_fighter(&mut *player_module_accessor); + handle_recording_for_fighter(&mut *cpu_module_accessor); + } } } @@ -356,23 +355,22 @@ pub unsafe fn playback(slot: Option) -> bool { warn!("Tried to playback during lockout!"); return false; } - if slot.is_none() { + if let Some(slot) = slot { + let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) + .expect("Could not get CPU module accessor in playback"); + let frame_length = read(&P1_FRAME_LENGTH_MAPPING)[slot]; + assign(&CURRENT_FRAME_LENGTH, frame_length); + assign(&CURRENT_PLAYBACK_SLOT, slot); + assign(&INPUT_RECORD, Playback); + assign(&POSSESSION, Player); + assign(&INPUT_RECORD_FRAME, 0); + assign(&BUFFER_FRAME, 0); + assign(&CURRENT_LR, PostureModule::lr(cpu_module_accessor)); + true + } else { warn!("Tried to playback without a slot selected!"); - return false; + false } - let slot = slot.unwrap(); - let cpu_module_accessor = try_get_module_accessor(FighterId::CPU) - .expect("Could not get CPU module accessor in playback"); - let frame_length = read(&P1_FRAME_LENGTH_MAPPING)[slot]; - assign(&CURRENT_FRAME_LENGTH, frame_length); - assign(&CURRENT_PLAYBACK_SLOT, slot); - assign(&INPUT_RECORD, Playback); - assign(&POSSESSION, Player); - assign(&INPUT_RECORD_FRAME, 0); - assign(&BUFFER_FRAME, 0); - assign(&CURRENT_LR, PostureModule::lr(cpu_module_accessor)); - - true } pub unsafe fn playback_ledge(slot: Option) { @@ -480,13 +478,10 @@ unsafe fn set_cpu_controls(p_data: *mut *mut u8) { should_mash_playback(); } - let cpu_module_accessor = try_get_module_accessor(FighterId::CPU); - - // Sometimes we can try to grab their module accessor before they are valid? - if cpu_module_accessor.is_none() { + let Some(cpu_module_accessor) = try_get_module_accessor(FighterId::CPU) else { + // Sometimes we can try to grab their module accessor before they are valid? return; - } - let cpu_module_accessor = cpu_module_accessor.unwrap(); + }; if read(&INPUT_RECORD) == Pause { let lockout_frame = read(&LOCKOUT_FRAME); diff --git a/src/training/mod.rs b/src/training/mod.rs index 548cb70c3..acf846dc7 100644 --- a/src/training/mod.rs +++ b/src/training/mod.rs @@ -427,8 +427,9 @@ pub unsafe fn handle_add_damage( // This function already checks for training mode, so we don't need to check for training mode here #[skyline::hook(offset = *OFFSET_TRAINING_RESET_CHECK, inline)] unsafe fn lra_handle(ctx: &mut InlineCtx) { + let x8 = ctx.registers[8].x() as *mut u64; if !(read(&MENU).lra_reset.as_bool()) { - ctx.registers[8].set_x(0); + *x8 = 0; } } @@ -864,7 +865,7 @@ pub fn training_mods() { ); drop(item_manager_addr_lock); - add_hook(params_main).unwrap(); + add_hook(params_main).expect("Could not find the params_hook plugin"); } // Enable Custom Stages for Training Mode @@ -872,7 +873,7 @@ pub fn training_mods() { // from being set to false when we load the SSS in Training Mode skyline::patching::Patch::in_text(*OFFSET_SSS_TRAINING) .nop() - .unwrap(); + .expect("Failed to nop OFFSET_SSS_TRAINING"); println!( "Searching for STALE_MENU offset first! : {}", diff --git a/src/training/shield.rs b/src/training/shield.rs index 709ab25f4..e967dfd12 100644 --- a/src/training/shield.rs +++ b/src/training/shield.rs @@ -170,7 +170,9 @@ pub unsafe fn param_installer() { } else { // reset the game's shield_damage_mul back to what // it originally was at game boot. - common_params.shield_damage_mul = (*cached_shield_damage_mul_lock).unwrap(); + common_params.shield_damage_mul = (*cached_shield_damage_mul_lock).expect( + "Something went wrong with the cached_shield_damage_mul in param_installer", + ); } } } diff --git a/src/training/ui/display.rs b/src/training/ui/display.rs index 087e616f5..e42a239e6 100644 --- a/src/training/ui/display.rs +++ b/src/training/ui/display.rs @@ -46,7 +46,7 @@ pub unsafe fn draw(root_pane: &Pane) { return; } - let notification = notification.unwrap(); + let notification = notification.expect("notification not none in draw()"); notification.tick(); let color = notification.color; diff --git a/training_mod_consts/src/config.rs b/training_mod_consts/src/config.rs index f0462d781..0ce0d00cc 100644 --- a/training_mod_consts/src/config.rs +++ b/training_mod_consts/src/config.rs @@ -40,7 +40,7 @@ impl TrainingModpackConfig { Ok(c) => Ok(c), Err(e) => { if e.is::() - && e.downcast_ref::().unwrap().kind() == io::ErrorKind::NotFound + && e.downcast_ref::().expect("Couldn't convert error in load_or_create()").kind() == io::ErrorKind::NotFound { // No config file exists already TrainingModpackConfig::create_default()?; diff --git a/training_mod_sync/src/lib.rs b/training_mod_sync/src/lib.rs index a582d06d8..c385b8f06 100644 --- a/training_mod_sync/src/lib.rs +++ b/training_mod_sync/src/lib.rs @@ -6,31 +6,31 @@ use std::sync::{RwLockReadGuard, RwLockWriteGuard}; /// /// Requires such as a bool or usize pub fn read(rwlock: &RwLock) -> T { - *rwlock.read().unwrap() + *rwlock.read().expect("Read lock is poisoned") } /// Gets a clone of a value inside a RwLock and immediately unlocks /// /// Can be used if is not Copy, such as Vec pub fn read_clone(rwlock: &RwLock) -> T { - rwlock.read().unwrap().clone() + rwlock.read().expect("Read_Clone lock is poisoned").clone() } /// Assigns a new value to a RwLock and immediately unlocks pub fn assign(rwlock: &RwLock, new_val: T) { - *rwlock.write().unwrap() = new_val + *rwlock.write().expect("Assign lock is poisoned") = new_val } /// Locks a RwLock for writing and returns the guard /// /// Don't forget to drop the guard as soon as you're finished with it pub fn lock_write(rwlock: &RwLock) -> RwLockWriteGuard<'_, T> { - rwlock.write().unwrap() + rwlock.write().expect("Lock_Write lock is poisoned") } /// Locks a RwLock for reading and returns the guard /// /// Don't forget to drop the guard as soon as you're finished with it pub fn lock_read(rwlock: &RwLock) -> RwLockReadGuard<'_, T> { - rwlock.read().unwrap() + rwlock.read().expect("Lock_Read lock is poisoned") } From d5be2f6006c8b926f6313dbfd9ac4fedeb8e1f24 Mon Sep 17 00:00:00 2001 From: asimon-1 <40246417+asimon-1@users.noreply.github.com> Date: Sun, 26 Oct 2025 15:54:31 -0400 Subject: [PATCH 8/8] Fix fmt --- training_mod_consts/src/config.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/training_mod_consts/src/config.rs b/training_mod_consts/src/config.rs index 0ce0d00cc..11814c5e2 100644 --- a/training_mod_consts/src/config.rs +++ b/training_mod_consts/src/config.rs @@ -40,7 +40,10 @@ impl TrainingModpackConfig { Ok(c) => Ok(c), Err(e) => { if e.is::() - && e.downcast_ref::().expect("Couldn't convert error in load_or_create()").kind() == io::ErrorKind::NotFound + && e.downcast_ref::() + .expect("Couldn't convert error in load_or_create()") + .kind() + == io::ErrorKind::NotFound { // No config file exists already TrainingModpackConfig::create_default()?;