Officialy, how to Add Fighter newcomer mod for SSBU using Arcropolis and Smashline 2 https://github.com/HDR-Development/smashline https://github.com/HDR-Development/smashline/blob/master/src/cloning/fighters.rs use std::sync::atomic::{AtomicUsize, Ordering}; use locks::RwLock; use skyline::hooks::InlineCtx; use smashline::Hash40; static FIGHTER_CLONES: RwLock<[Option<Hash40>; 8]> = RwLock::new([None; 8]); pub static NEW_FIGHTERS: RwLock<Vec<NewFighter>> = RwLock::new(Vec::new()); #[repr(C)] pub struct FighterLinkedListNode { pub next: *mut FighterLinkedListNode, pub prev: *mut FighterLinkedListNode, pub info: FighterSelectionInfo, pub fighter_data_ptr: *mut u8, pub bigger_fighter_data_ptr: *mut u8, } #[repr(C)] pub struct FighterSelectionInfo { pub fighter_kind: i32, pub costume_slot: i32, pub css_entry: i32, pub mii_related: [i32; 4], pub flags: [u8; 4], } // Very important structure ! #[repr(C)] pub struct SelectedFighterInfo {} pub struct NewFighter { pub base_id: i32, pub fighter_kind_hash: Hash40, pub name: String, pub name_ffi: String, pub hash: Hash40, } pub static CURRENT_PLAYER_ID: AtomicUsize = AtomicUsize::new(usize::MAX); #[skyline::from_offset(0x3262130)] fn lookup_fighter_kind_from_ui_hash(database: u64, hash: u64) -> i32; #[skyline::hook(offset = 0x2310d04, inline)] unsafe fn set_current_player_id(ctx: &mut InlineCtx) { CURRENT_PLAYER_ID.store(*ctx.registers[21].x.as_ref() as usize, Ordering::Relaxed); let result = lookup_fighter_kind_from_ui_hash( *ctx.registers[0].x.as_ref(), *ctx.registers[1].x.as_ref(), ); CURRENT_PLAYER_ID.store(usize::MAX, Ordering::Relaxed); *ctx.registers[0].x.as_mut() = result as u64; } #[skyline::hook(offset = 0x66cd40)] unsafe fn lookup_fighter_kind_hash(hash: Hash40) -> i32 { let id = CURRENT_PLAYER_ID.load(Ordering::Relaxed); let mut players = FIGHTER_CLONES.write(); for fighter in NEW_FIGHTERS.read().iter() { if fighter.fighter_kind_hash == hash { if id != usize::MAX { players[id] = Some(Hash40::new(&fighter.name)); } return fighter.base_id; } } if id != usize::MAX { players[id] = None; } call_original!(hash) } // #[skyline::hook(offset = 0x66ded0)] // unsafe fn select_fighter(manager: *const u64, info: &FighterSelectionInfo) { //     CURRENT_PLAYER_ID.store(info.css_entry as usize, Ordering::Relaxed); //     call_original!(manager, info); //     CURRENT_PLAYER_ID.store(usize::MAX, Ordering::Relaxed); // } #[skyline::hook(offset = 0x3311190)] unsafe fn update_selected_fighter(arg: u64, id: u32, info: *const u32) { CURRENT_PLAYER_ID.store(*info as usize - 1, Ordering::Relaxed); call_original!(arg, id, info); CURRENT_PLAYER_ID.store(usize::MAX, Ordering::Relaxed); } #[skyline::hook(offset = 0x64f8a4, inline)] unsafe fn initialize_ai(ctx: &InlineCtx) { let fighter = *ctx.registers[21].x.as_ref() as *const i32; let _kind = *fighter.add(0x74 / 4); let entry_id = *fighter.add(0x2); CURRENT_PLAYER_ID.store(entry_id as usize, Ordering::Relaxed); } #[skyline::hook(offset = 0x64f8b4, inline)] unsafe fn finish_ai(_ctx: &InlineCtx) { CURRENT_PLAYER_ID.store(usize::MAX, Ordering::Relaxed); } macro_rules! decl_hooks { ($install_fn:ident => $func:expr; $($name:ident($offset:expr, $dst:expr));*) => { $( #[skyline::hook(offset = $offset, inline)] unsafe fn $name(ctx: &mut InlineCtx) { $func(ctx, $dst); } )* fn $install_fn() { skyline::install_hooks!( $( $name, )* ); } } } unsafe fn handle_fighter_name(ctx: &mut InlineCtx, dst: usize) { let current_player = CURRENT_PLAYER_ID.load(Ordering::Relaxed); if current_player == usize::MAX { return; } let clones = FIGHTER_CLONES.read(); let Some(clone) = clones[current_player] else { return; }; for new_fighter in NEW_FIGHTERS.read().iter() { if new_fighter.hash == clone { *ctx.registers[dst].x.as_mut() = new_fighter.name_ffi.as_ptr() as u64; } } } decl_hooks! { install_fighter_name_hooks => handle_fighter_name; kirby_copy_fit(0xba448c, 2); kirby_copy_fit2(0xba4e90, 2); get_fighter_path1(0x17df4a8, 2); get_fighter_path2(0x17df7c8, 2); get_fighter_path3(0x17df694, 2); get_fighter_path20(0x17dfcf0, 2); get_fighter_path21(0x17e0334, 2); get_fighter_path22(0x17e03f8, 2); // get_fighter_path23(0x17e4bc0, 22); // This one is for the loading fighter module get_fighter_path24(0x17e74d8, 2); get_fighter_path25(0x17e8bf0, 2); get_fighter_path26(0x17e8c10, 2); get_fighter_path27(0x17e8d38, 2); get_fighter_path28(0x17e8d58, 2); get_fighter_path29(0x17e8de4, 2); get_fighter_path30(0x17e8e04, 2); get_fighter_path31(0x17e8fe8, 2); get_fighter_path32(0x17e91ac, 2); get_fighter_path35(0x17e9d4c, 2); get_fighter_path36(0x17f0048, 2); get_motion_list_name(0x60c178, 2); get_fighter_path4(0x17df780, 2); get_fighter_path5(0x17df794, 2); get_fighter_path6(0x17df6b8, 2); get_fighter_path7(0x17df7b0, 2); get_fighter_path8(0x17df7c8, 2); get_fighter_path9(0x17df7dc, 2); get_fighter_path10(0x17df7f8, 2); get_fighter_path11(0x17df6d0, 2); get_fighter_path12(0x17df6e8, 2); get_fighter_path13(0x17df700, 2); get_fighter_path14(0x17df834, 2); get_fighter_path15(0x17df84c, 2); get_fighter_path16(0x17df860, 2); get_fighter_path17(0x17df724, 2); get_fighter_path18(0x17df73c, 2); get_fighter_path19(0x17df87c, 2); model_path(0x17e9a60, 2); model_path2(0x17e9b88, 2) } pub fn install() { skyline::patching::Patch::in_text(0x2310d04).nop().unwrap(); skyline::install_hooks!( set_current_player_id, lookup_fighter_kind_hash, update_selected_fighter, initialize_ai, finish_ai ); install_fighter_name_hooks(); }