diff --git a/Cargo.toml b/Cargo.toml index 5167240..360ef3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,6 @@ skyline = { git = "https://github.com/ultimate-research/skyline-rs.git" } skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git", branch = "no-cache" } skyline-web = { git = "https://github.com/skyline-rs/skyline-web.git" } bitflags = "1.2.1" -bitfield-struct = "0.1.8" parking_lot = { version = "0.12.0", features = ["nightly"] } lazy_static = "1.4.0" owo-colors = "2.1.0" @@ -35,6 +34,7 @@ native-tls = { version = "0.2.11", features = ["vendored"] } [patch.crates-io] native-tls = { git = "https://github.com/skyline-rs/rust-native-tls", rev = "f202fca" } +nnsdk = { git = "https://github.com/ultimate-research/nnsdk-rs" } [profile.dev] panic = "abort" diff --git a/src/training/mod.rs b/src/training/mod.rs index 0fe86cc..7dbcd7d 100644 --- a/src/training/mod.rs +++ b/src/training/mod.rs @@ -23,7 +23,6 @@ pub mod sdi; pub mod shield; pub mod tech; pub mod throw; -pub mod ui; pub mod ui_hacks; mod air_dodge_direction; diff --git a/src/training/ui/mod.rs b/src/training/ui/mod.rs deleted file mode 100644 index be572f8..0000000 --- a/src/training/ui/mod.rs +++ /dev/null @@ -1,565 +0,0 @@ -#![allow(dead_code)] - -use std::ops::{Deref, DerefMut}; - -use bitfield_struct::bitfield; - -mod resources; -pub use resources::*; - -use crate::common::get_player_dmg_digits; -use crate::consts::FighterId; - -macro_rules! c_str { - ($l:tt) => { - [$l.as_bytes(), "\u{0}".as_bytes()].concat().as_ptr() - }; -} - -#[repr(C)] -#[derive(Debug)] -pub struct ResAnimationContent { - name: [skyline::libc::c_char; 28], - count: u8, - anim_content_type: u8, - padding: [skyline::libc::c_char; 2], -} - -/** - * Block Header Kind - * - * ANIM_TAG: pat1 - * ANIM_SHARE: pah1 - * ANIM_INFO: pai1 - */ - -#[repr(C)] -#[derive(Debug)] -pub struct ResAnimationBlock { - block_header_kind: u32, - block_header_size: u32, - num_frames: u16, - is_loop: bool, - pad: [skyline::libc::c_char; 1], - file_count: u16, - anim_cont_count: u16, - anim_cont_offsets_offset: u32, -} - -#[repr(C)] -pub struct AnimTransform { - res_animation_block: *mut ResAnimationBlock, - frame: f32, - enabled: bool, -} - -impl AnimTransform { - pub unsafe fn parse_anim_transform(&mut self, layout_name: Option<&str>) { - let res_animation_block_data_start = self.res_animation_block as u64; - let res_animation_block = &*self.res_animation_block; - let mut anim_cont_offsets = (res_animation_block_data_start - + res_animation_block.anim_cont_offsets_offset as u64) - as *const u32; - for _anim_cont_idx in 0..res_animation_block.anim_cont_count { - let anim_cont_offset = *anim_cont_offsets; - let res_animation_cont = (res_animation_block_data_start + anim_cont_offset as u64) - as *const ResAnimationContent; - - let name = skyline::try_from_c_str((*res_animation_cont).name.as_ptr()) - .unwrap_or("UNKNOWN".to_string()); - let anim_type = (*res_animation_cont).anim_content_type; - - // AnimContentType 1 == MATERIAL - if name.starts_with("set_dmg_num") && anim_type == 1 { - if let Some(layout_name) = layout_name { - let (hundreds, tens, ones, dec) = get_player_dmg_digits(match layout_name { - "p1" => FighterId::Player, - "p2" => FighterId::CPU, - _ => panic!("Unknown layout name: {}", layout_name), - }); - - if name == "set_dmg_num_3" { - self.frame = hundreds as f32; - } - if name == "set_dmg_num_2" { - self.frame = tens as f32; - } - if name == "set_dmg_num_1" { - self.frame = ones as f32; - } - if name == "set_dmg_num_dec" { - self.frame = dec as f32; - } - } - } - - anim_cont_offsets = anim_cont_offsets.add(1); - } - } -} - -#[repr(C)] -#[derive(Debug)] -pub struct AnimTransformNode { - prev: *mut AnimTransformNode, - next: *mut AnimTransformNode, -} - -impl AnimTransformNode { - pub unsafe fn iterate_anim_list(&mut self, layout_name: Option<&str>) { - let mut curr = self as *mut AnimTransformNode; - let mut _anim_idx = 0; - while !curr.is_null() { - // Only if valid - if curr != (*curr).next { - let anim_transform = (curr as *mut u64).add(2) as *mut AnimTransform; - anim_transform - .as_mut() - .unwrap() - .parse_anim_transform(layout_name); - } - - curr = (*curr).next; - _anim_idx += 1; - if curr == self as *mut AnimTransformNode || curr == (*curr).next { - break; - } - } - } -} - -#[repr(C)] -pub struct AnimTransformList { - root: AnimTransformNode, -} - -#[repr(C, align(8))] -#[derive(Debug, Copy, Clone)] -pub struct Pane { - vtable: u64, - pub link: PaneNode, - pub parent: *mut Pane, - pub children_list: PaneNode, - pub pos_x: f32, - pub pos_y: f32, - pos_z: f32, - rot_x: f32, - rot_y: f32, - rot_z: f32, - pub scale_x: f32, - pub scale_y: f32, - pub size_x: f32, - pub size_y: f32, - pub flags: u8, - pub alpha: u8, - pub global_alpha: u8, - base_position: u8, - flag_ex: u8, - // This is supposed to be 3 bytes padding + flags of 4 bytes + padding of 4 bytes - pad: [u8; 3 + 4 + 4 + 8], - global_matrix: [[f32; 3]; 4], - user_matrix: *const u64, - ext_user_data_list: *const u64, - pub name: [skyline::libc::c_char; 25], - user_data: [skyline::libc::c_char; 9], -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub enum PaneFlag { - Visible, - InfluencedAlpha, - LocationAdjust, - UserAllocated, - IsGlobalMatrixDirty, - UserMatrix, - UserGlobalMatrix, - IsConstantBufferReady, - Max, -} - -impl Pane { - pub unsafe fn find_pane_by_name_recursive(&self, s: &str) -> Option<&mut Pane> { - find_pane_by_name_recursive(self, c_str!(s)).as_mut() - } - - pub unsafe fn find_pane_by_name(&self, s: &str, recursive: bool) -> Option<&mut Pane> { - find_pane_by_name(self, c_str!(s), recursive).as_mut() - } - - pub unsafe fn set_text_string(&self, s: &str) { - pane_set_text_string(self, c_str!(s)); - } - - pub unsafe fn remove_child(&self, child: &Pane) { - pane_remove_child(self, child as *const Pane); - } - - pub unsafe fn append_child(&self, child: &Pane) { - pane_append_child(self, child as *const Pane); - } - - /// Detach from current parent pane - pub unsafe fn detach(&self) { - pane_remove_child(self.parent, self as *const Pane); - } - - pub unsafe fn as_parts(&mut self) -> *mut Parts { - self as *mut Pane as *mut Parts - } - - pub unsafe fn as_picture(&mut self) -> &mut Picture { - &mut *(self as *mut Pane as *mut Picture) - } - - pub unsafe fn as_textbox(&mut self) -> &mut TextBox { - &mut *(self as *mut Pane as *mut TextBox) - } - - pub unsafe fn set_visible(&mut self, visible: bool) { - if visible { - self.alpha = 255; - self.global_alpha = 255; - } else { - self.alpha = 0; - self.global_alpha = 0; - } - } - - pub fn get_name(&self) -> String { - self.name - .iter() - .take_while(|b| **b != 0) - .map(|b| *b as char) - .collect::() - } -} - -#[repr(C)] -#[derive(Debug)] -pub struct Parts { - pub pane: Pane, - // Some IntrusiveList - link: PaneNode, - pub layout: *mut Layout, -} - -impl Deref for Parts { - type Target = Pane; - - fn deref(&self) -> &Self::Target { - &self.pane - } -} - -impl DerefMut for Parts { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.pane - } -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Picture { - pub pane: Pane, - pub material: *mut Material, - pub vertex_colors: [[u8; 4]; 4], - shared_memory: *mut u8, -} - -impl Deref for Picture { - type Target = Pane; - - fn deref(&self) -> &Self::Target { - &self.pane - } -} - -impl DerefMut for Picture { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.pane - } -} - -#[bitfield(u16)] -pub struct TextBoxBits { - #[bits(2)] - text_alignment: u8, - #[bits(1)] - is_ptdirty: u8, - shadow_enabled: bool, - invisible_border_enabled: bool, - double_drawn_border_enabled: bool, - width_limit_enabled: bool, - per_character_transform_enabled: bool, - center_ceiling_enabled: bool, - per_character_transform_split_by_char_width: bool, - per_character_transform_auto_shadow_alpha: bool, - draw_from_right_to_left: bool, - per_character_transform_origin_to_center: bool, - per_character_transform_fix_space: bool, - linefeed_by_character_height_enabled: bool, - per_character_transform_split_by_char_width_insert_space_enabled: bool, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct TextBox { - pub pane: Pane, - // Actually a union - pub m_text_buf: *mut skyline::libc::c_char, - m_p_text_id: *const skyline::libc::c_char, - m_text_colors: [[u8; 4]; 2], - m_p_font: *const skyline::libc::c_void, - m_font_size_x: f32, - m_font_size_y: f32, - m_line_space: f32, - m_char_space: f32, - - // Actually a union - m_p_tag_processor: *const skyline::libc::c_char, - - m_text_buf_len: u16, - pub m_text_len: u16, - - m_bits: TextBoxBits, - m_text_position: u8, - - pub m_is_utf8: bool, - - m_italic_ratio: f32, - - m_shadow_offset_x: f32, - m_shadow_offset_y: f32, - m_shadow_scale_x: f32, - m_shadow_scale_y: f32, - m_shadow_top_color: [u8; 4], - m_shadow_bottom_color: [u8; 4], - m_shadow_italic_ratio: f32, - - m_p_line_width_offset: *const skyline::libc::c_void, - - pub m_p_material: *mut Material, - m_p_disp_string_buf: *const skyline::libc::c_void, - - m_p_per_character_transform: *const skyline::libc::c_void, -} - -impl TextBox { - pub fn set_color(&mut self, r: u8, g: u8, b: u8, a: u8) { - let input_color = [r, g, b, a]; - let mut dirty: bool = false; - self.m_text_colors - .iter_mut() - .for_each(|top_or_bottom_color| { - if *top_or_bottom_color != input_color { - dirty = true; - } - *top_or_bottom_color = input_color; - }); - - if dirty { - self.m_bits.set_is_ptdirty(1); - } - } - - pub unsafe fn set_material_white_color(&mut self, r: f32, g: f32, b: f32, a: f32) { - (*self.m_p_material).set_white_color(r, g, b, a); - } - - pub unsafe fn set_material_black_color(&mut self, r: f32, g: f32, b: f32, a: f32) { - (*self.m_p_material).set_black_color(r, g, b, a); - } - - pub unsafe fn set_default_material_colors(&mut self) { - self.set_material_white_color(255.0, 255.0, 255.0, 255.0); - self.set_material_black_color(0.0, 0.0, 0.0, 255.0); - } -} - -impl Deref for TextBox { - type Target = Pane; - - fn deref(&self) -> &Self::Target { - &self.pane - } -} - -impl DerefMut for TextBox { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.pane - } -} - -#[repr(C)] -pub union MaterialColor { - byte_color: [[u8; 4]; 2], - p_float_color: *mut *mut f32, -} - -use std::fmt; -impl fmt::Debug for MaterialColor { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - unsafe { - f.debug_struct("MaterialColor") - .field("byteColor", &self.byte_color) - .field("pFloatColor", &self.p_float_color) - .finish() - } - } -} - -#[repr(C)] -#[derive(Debug, PartialEq)] -pub enum MaterialColorType { - BlackColor, - WhiteColor, -} - -#[repr(C)] -#[derive(Debug, PartialEq)] -pub enum MaterialFlags { - UserAllocated, - TextureOnly, - ThresholdingAlphaInterpolation, - BlackColorFloat, - WhiteColorFloat, - DynamicAllocatedColorData, -} - -#[repr(C)] -#[derive(Debug)] -pub struct Material { - vtable: u64, - pub m_colors: MaterialColor, - // Actually a struct - m_mem_cap: u32, - // Actually a struct - m_mem_count: u32, - m_p_mem: *mut skyline::libc::c_void, - m_p_shader_info: *const skyline::libc::c_void, - pub m_p_name: *const skyline::libc::c_char, - m_vertex_shader_constant_buffer_offset: u32, - m_pixel_shader_constant_buffer_offset: u32, - m_p_user_shader_constant_buffer_information: *const skyline::libc::c_void, - m_p_blend_state: *const skyline::libc::c_void, - m_packed_values: u8, - m_flag: u8, - m_shader_variation: u16, -} - -impl Material { - pub fn set_color_int(&mut self, idx: usize, r: u8, g: u8, b: u8, a: u8) { - let input_color = [r, g, b, a]; - unsafe { - self.m_colors.byte_color[idx] = input_color; - } - } - - pub fn set_color_float(&mut self, idx: usize, r: f32, g: f32, b: f32, a: f32) { - unsafe { - *(*(self.m_colors.p_float_color.add(idx)).add(0)) = r; - *(*(self.m_colors.p_float_color.add(idx)).add(1)) = g; - *(*(self.m_colors.p_float_color.add(idx)).add(2)) = b; - *(*(self.m_colors.p_float_color.add(idx)).add(3)) = a; - } - } - - pub fn set_color(&mut self, color_type: MaterialColorType, r: f32, g: f32, b: f32, a: f32) { - let (is_float_flag, idx) = if color_type == MaterialColorType::BlackColor { - (MaterialFlags::BlackColorFloat as u8, 0) - } else { - (MaterialFlags::WhiteColorFloat as u8, 1) - }; - if self.m_flag & (0x1 << is_float_flag) != 0 { - self.set_color_float(idx, r, g, b, a); - } else { - self.set_color_int(idx, r as u8, g as u8, b as u8, a as u8); - } - } - - pub fn set_white_color(&mut self, r: f32, g: f32, b: f32, a: f32) { - self.set_color(MaterialColorType::WhiteColor, r, g, b, a); - } - - pub fn set_black_color(&mut self, r: f32, g: f32, b: f32, a: f32) { - self.set_color(MaterialColorType::BlackColor, r, g, b, a); - } -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Window { - pub pane: Pane, - // TODO -} - -impl Deref for Window { - type Target = Pane; - - fn deref(&self) -> &Self::Target { - &self.pane - } -} - -impl DerefMut for Window { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.pane - } -} - -#[derive(Debug, Copy, Clone)] -pub struct PaneNode { - pub prev: *mut PaneNode, - pub next: *mut PaneNode, -} - -#[repr(C)] -pub struct Group { - pane_list: PaneNode, - name: *const skyline::libc::c_char, -} - -#[repr(C)] -pub struct GroupContainer {} - -#[repr(C)] -#[derive(Debug)] -pub struct Layout { - vtable: u64, - pub anim_trans_list: AnimTransformNode, - pub root_pane: *mut Pane, - group_container: u64, - layout_size: f64, - pub layout_name: *const skyline::libc::c_char, -} - -#[skyline::from_offset(0x59970)] -pub unsafe fn find_pane_by_name_recursive( - pane: *const Pane, - s: *const skyline::libc::c_char, -) -> *mut Pane; - -#[skyline::from_offset(0x583c0)] -pub unsafe fn find_pane_by_name( - pane: *const Pane, - s: *const skyline::libc::c_char, - recursive: bool, -) -> *mut Pane; - -#[skyline::from_offset(0x37a1270)] -pub unsafe fn pane_set_text_string(pane: *const Pane, s: *const skyline::libc::c_char); - -#[skyline::from_offset(0x58290)] -pub unsafe fn pane_remove_child(pane: *const Pane, child: *const Pane); - -#[skyline::from_offset(0x58250)] -pub unsafe fn pane_append_child(pane: *const Pane, child: *const Pane); - -pub unsafe fn get_typeinfo_name(cls_vtable: u64) -> String { - let typeinfo_ptr_addr = (cls_vtable - 8) as *const u64; - let typeinfo_addr = *typeinfo_ptr_addr; - let typeinfo_name_ptr_addr = (typeinfo_addr + 8) as *const u64; - let type_info_name_addr = (*typeinfo_name_ptr_addr) as *const skyline::libc::c_char; - skyline::from_c_str(type_info_name_addr) -} diff --git a/src/training/ui/resources.rs b/src/training/ui/resources.rs deleted file mode 100644 index 54b7423..0000000 --- a/src/training/ui/resources.rs +++ /dev/null @@ -1,425 +0,0 @@ -use std::ops::{Deref, DerefMut}; - -// Maybe needs a vtable. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResVec2 { - x: f32, - y: f32, -} - -impl ResVec2 { - pub fn default() -> ResVec2 { - ResVec2 { x: 0.0, y: 0.0 } - } - - pub fn new(x: f32, y: f32) -> ResVec2 { - ResVec2 { x, y } - } -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResVec3 { - pub x: f32, - pub y: f32, - pub z: f32, -} - -impl ResVec3 { - pub fn default() -> ResVec3 { - ResVec3 { - x: 0.0, - y: 0.0, - z: 0.0, - } - } - - pub fn new(x: f32, y: f32, z: f32) -> ResVec3 { - ResVec3 { x, y, z } - } -} - -// Maybe needs a vtable. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResColor { - r: u8, - g: u8, - b: u8, - a: u8, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResPane { - block_header_kind: u32, - block_header_size: u32, - flag: u8, - base_position: u8, - alpha: u8, - flag_ex: u8, - pub name: [skyline::libc::c_char; 24], - pub user_data: [skyline::libc::c_char; 8], - pub pos: ResVec3, - rot_x: f32, - rot_y: f32, - rot_z: f32, - pub scale_x: f32, - pub scale_y: f32, - pub size_x: f32, - pub size_y: f32, -} - -impl ResPane { - // For null pane - pub fn new(name: &str) -> ResPane { - let mut pane = ResPane { - block_header_kind: u32::from_le_bytes([b'p', b'a', b'n', b'1']), - block_header_size: 84, - /// Visible | InfluencedAlpha - flag: 0x3, - base_position: 0, - alpha: 0xFF, - flag_ex: 0, - name: [0; 24], - user_data: [0; 8], - pos: ResVec3 { - x: 0.0, - y: 0.0, - z: 0.0, - }, - rot_x: 0.0, - rot_y: 0.0, - rot_z: 0.0, - scale_x: 1.0, - scale_y: 1.0, - size_x: 30.0, - size_y: 40.0, - }; - pane.set_name(name); - pane - } - - pub fn set_name(&mut self, name: &str) { - assert!( - name.len() <= 24, - "Name of pane must be at most 24 characters" - ); - unsafe { - std::ptr::copy_nonoverlapping(name.as_ptr(), self.name.as_mut_ptr(), name.len()); - } - } - - pub fn set_pos(&mut self, pos: ResVec3) { - self.pos = pos; - } - - pub fn set_size(&mut self, size: ResVec2) { - self.size_x = size.x; - self.size_y = size.y; - } - - pub fn get_name(&self) -> String { - self.name - .iter() - .take_while(|b| **b != 0) - .map(|b| *b as char) - .collect::() - } - - pub fn name_matches(&self, other: &str) -> bool { - self.get_name() == other - } -} - -#[repr(C)] -#[derive(Debug, PartialEq)] -enum TextBoxFlag { - ShadowEnabled, - ForceAssignTextLength, - InvisibleBorderEnabled, - DoubleDrawnBorderEnabled, - PerCharacterTransformEnabled, - CenterCeilingEnabled, - LineWidthOffsetEnabled, - ExtendedTagEnabled, - PerCharacterTransformSplitByCharWidth, - PerCharacterTransformAutoShadowAlpha, - DrawFromRightToLeft, - PerCharacterTransformOriginToCenter, - KeepingFontScaleEnabled, - PerCharacterTransformFixSpace, - PerCharacterTransformSplitByCharWidthInsertSpaceEnabled, - Max, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub enum TextAlignment { - Synchronous, - Left, - Center, - Right, - MaxTextAlignment, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResTextBox { - pub pane: ResPane, - text_buf_bytes: u16, - text_str_bytes: u16, - material_idx: u16, - pub font_idx: u16, - text_position: u8, - text_alignment: u8, - text_box_flag: u16, - italic_ratio: f32, - text_str_offset: u32, - text_cols: [ResColor; 2], - font_size: ResVec2, - char_space: f32, - line_space: f32, - text_id_offset: u32, - shadow_offset: ResVec2, - shadow_scale: ResVec2, - shadow_cols: [ResColor; 2], - shadow_italic_ratio: f32, - line_width_offset_offset: u32, - per_character_transform_offset: u32, - /* Additional Info - uint16_t text[]; // Text. - char textId[]; // The text ID. - u8 lineWidthOffsetCount; // The quantity of widths and offsets for each line. - float lineOffset[]; // The offset for each line. - float lineWidth[]; // The width of each line. - ResPerCharacterTransform perCharacterTransform // Information for per-character animation. - ResAnimationInfo perCharacterTransformAnimationInfo; // Animation information for per-character animation. - */ -} - -impl Deref for ResTextBox { - type Target = ResPane; - - fn deref(&self) -> &Self::Target { - &self.pane - } -} - -impl DerefMut for ResTextBox { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.pane - } -} - -impl ResTextBox { - pub fn enable_shadow(&mut self) { - self.text_box_flag |= 0x1 << TextBoxFlag::ShadowEnabled as u8; - } - - pub fn text_alignment(&mut self, align: TextAlignment) { - self.text_alignment = align as u8; - } -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResPicture { - pub pane: ResPane, - vtx_cols: [ResColor; 4], - material_idx: u16, - tex_coord_count: u8, - flags: u8, - /* Additional Info - ResVec2 texCoords[texCoordCount][VERTEX_MAX]; - uint32_t shapeBinaryIndex; - */ -} - -impl Deref for ResPicture { - type Target = ResPane; - - fn deref(&self) -> &Self::Target { - &self.pane - } -} - -impl DerefMut for ResPicture { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.pane - } -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResPictureWithTex { - pub picture: ResPicture, - tex_coords: [[ResVec2; TEX_COORD_COUNT]; 4], -} - -impl Deref for ResPictureWithTex { - type Target = ResPane; - - fn deref(&self) -> &Self::Target { - &self.picture - } -} - -impl DerefMut for ResPictureWithTex { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.picture - } -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResParts { - pub pane: ResPane, - pub property_count: u32, - magnify: ResVec2, -} - -impl Deref for ResParts { - type Target = ResPane; - - fn deref(&self) -> &Self::Target { - &self.pane - } -} - -impl DerefMut for ResParts { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.pane - } -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -struct ResPartsProperty { - name: [skyline::libc::c_char; 24], - usage_flag: u8, - basic_usage_flag: u8, - material_usage_flag: u8, - system_ext_user_data_override_flag: u8, - property_offset: u32, - ext_user_data_offset: u32, - pane_basic_info_offset: u32, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResPartsWithProperty { - pub parts: ResParts, - property_table: [ResPartsProperty; PROPERTY_COUNT], -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -struct ResWindowInflation { - left: i16, - right: i16, - top: i16, - bottom: i16, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResWindowFrameSize { - left: u16, - right: u16, - top: u16, - bottom: u16, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResWindowContent { - vtx_cols: [ResColor; 4], - material_idx: u16, - tex_coord_count: u8, - padding: [u8; 1], - /* Additional Info - nn::util::Float2 texCoords[texCoordCount][VERTEX_MAX]; - */ -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResWindowContentWithTexCoords { - pub window_content: ResWindowContent, - // This has to be wrong. - // Should be [[ResVec2; TEX_COORD_COUNT]; 4]? - tex_coords: [[ResVec3; TEX_COORD_COUNT]; 1], -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResWindowFrame { - material_idx: u16, - texture_flip: u8, - padding: [u8; 1], -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResWindow { - pub pane: ResPane, - inflation: ResWindowInflation, - frame_size: ResWindowFrameSize, - frame_count: u8, - window_flags: u8, - padding: [u8; 2], - content_offset: u32, - frame_offset_table_offset: u32, - content: ResWindowContent, - /* Additional Info - - ResWindowContent content; - - detail::uint32_t frameOffsetTable[frameCount]; - ResWindowFrame frames; - - */ -} - -impl Deref for ResWindow { - type Target = ResPane; - - fn deref(&self) -> &Self::Target { - &self.pane - } -} - -impl DerefMut for ResWindow { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.pane - } -} - -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ResWindowWithTexCoordsAndFrames { - pub window: ResWindow, - content: ResWindowContentWithTexCoords, - frame_offset_table: [u32; FRAME_COUNT], - frames: [ResWindowFrame; FRAME_COUNT], -} - -impl Deref - for ResWindowWithTexCoordsAndFrames -{ - type Target = ResPane; - - fn deref(&self) -> &Self::Target { - &self.window - } -} - -impl DerefMut - for ResWindowWithTexCoordsAndFrames -{ - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.window - } -} diff --git a/src/training/ui_hacks.rs b/src/training/ui_hacks.rs index 51bec7a..f3eb3fb 100644 --- a/src/training/ui_hacks.rs +++ b/src/training/ui_hacks.rs @@ -1,10 +1,76 @@ use crate::common::{get_player_dmg_digits, is_ready_go, is_training_mode}; use crate::consts::FighterId; -use crate::training::ui::*; use crate::{common::menu::QUICK_MENU_ACTIVE, training::combo::FRAME_ADVANTAGE}; +use skyline::nn::ui2d::*; +use smash::ui2d::{SmashPane, SmashTextBox}; use training_mod_consts::{OnOff, MENU}; use training_mod_tui::gauge::GaugeState; +pub unsafe fn iterate_anim_list( + anim_transform_node: &mut AnimTransformNode, + layout_name: Option<&str>, +) { + let mut curr = anim_transform_node as *mut AnimTransformNode; + let mut _anim_idx = 0; + while !curr.is_null() { + // Only if valid + 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); + } + + curr = (*curr).next; + _anim_idx += 1; + if curr == anim_transform_node as *mut AnimTransformNode || curr == (*curr).next { + break; + } + } +} + +pub unsafe fn parse_anim_transform(anim_transform: &mut AnimTransform, layout_name: Option<&str>) { + let res_animation_block_data_start = anim_transform.res_animation_block as u64; + let res_animation_block = &*anim_transform.res_animation_block; + let mut anim_cont_offsets = (res_animation_block_data_start + + res_animation_block.anim_cont_offsets_offset as u64) + as *const u32; + for _anim_cont_idx in 0..res_animation_block.anim_cont_count { + let anim_cont_offset = *anim_cont_offsets; + let res_animation_cont = (res_animation_block_data_start + anim_cont_offset as u64) + as *const ResAnimationContent; + + let name = skyline::try_from_c_str((*res_animation_cont).name.as_ptr()) + .unwrap_or("UNKNOWN".to_string()); + let anim_type = (*res_animation_cont).anim_content_type; + + // AnimContentType 1 == MATERIAL + if name.starts_with("set_dmg_num") && anim_type == 1 { + if let Some(layout_name) = layout_name { + let (hundreds, tens, ones, dec) = get_player_dmg_digits(match layout_name { + "p1" => FighterId::Player, + "p2" => FighterId::CPU, + _ => panic!("Unknown layout name: {}", layout_name), + }); + + if name == "set_dmg_num_3" { + anim_transform.frame = hundreds as f32; + } + if name == "set_dmg_num_2" { + anim_transform.frame = tens as f32; + } + if name == "set_dmg_num_1" { + anim_transform.frame = ones as f32; + } + if name == "set_dmg_num_dec" { + anim_transform.frame = dec as f32; + } + } + } + + anim_cont_offsets = anim_cont_offsets.add(1); + } +} + pub static NUM_DISPLAY_PANES: usize = 1; pub static NUM_MENU_TEXT_OPTIONS: usize = 27; pub static NUM_MENU_TEXT_SLIDERS: usize = 4; @@ -101,9 +167,8 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) if is_training_mode() && is_ready_go() && layout_name == "info_melee" { for player_name in &["p1", "p2"] { if let Some(parent) = root_pane.find_pane_by_name_recursive(player_name) { - let _p1_layout_name = - skyline::from_c_str((*(*parent.as_parts()).layout).layout_name); - let anim_list = &mut (*(*parent.as_parts()).layout).anim_trans_list; + let _p1_layout_name = skyline::from_c_str((*parent.as_parts().layout).layout_name); + let anim_list = &mut (*parent.as_parts().layout).anim_trans_list; let mut has_altered_anim_list = false; let (hundreds, tens, _, _) = get_player_dmg_digits(match *player_name { @@ -150,7 +215,7 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) if dmg_num.alpha != 255 || dmg_num.global_alpha != 255 { dmg_num.set_visible(true); if !has_altered_anim_list { - anim_list.iterate_anim_list(Some(player_name)); + iterate_anim_list(anim_list, Some(player_name)); has_altered_anim_list = true; } } @@ -181,12 +246,12 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) } if let Some(header) = root_pane.find_pane_by_name_recursive("trMod_disp_0_header") { - header.set_text_string("Frame Advantage"); + header.as_textbox().set_text_string("Frame Advantage"); } if let Some(text) = root_pane.find_pane_by_name_recursive("trMod_disp_0_txt") { - text.set_text_string(format!("{FRAME_ADVANTAGE}").as_str()); let text = text.as_textbox(); + text.set_text_string(format!("{FRAME_ADVANTAGE}").as_str()); match FRAME_ADVANTAGE { x if x < 0 => text.set_color(200, 8, 8, 255), x if x == 0 => text.set_color(0, 0, 0, 255), @@ -207,7 +272,7 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) for quit_txt_s in &["set_txt_00", "set_txt_01"] { if let Some(quit_txt) = quit_button.find_pane_by_name_recursive(quit_txt_s) { - quit_txt.set_text_string(if QUICK_MENU_ACTIVE { + quit_txt.as_textbox().set_text_string(if QUICK_MENU_ACTIVE { "Modpack Menu" } else { // Awkward. We should get the o.g. translation for non-english games @@ -270,7 +335,7 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) (0..NUM_MENU_TABS).for_each(|idx| { root_pane .find_pane_by_name_recursive(format!("trMod_menu_tab_{idx}").as_str()) - .map(|text| text.set_text_string(tab_titles[idx])); + .map(|text| text.as_textbox().set_text_string(tab_titles[idx])); }); if app.outer_list { @@ -308,15 +373,15 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) let list = &tab.lists[list_section]; let submenu = &list.items[list_idx]; let is_selected = list.state.selected().filter(|s| *s == list_idx).is_some(); + let text = text.as_textbox(); text.set_text_string(submenu.submenu_title); text.set_visible(true); - let text = text.as_textbox(); if is_selected { text.set_color(0x27, 0x4E, 0x13, 255); if let Some(footer) = root_pane.find_pane_by_name_recursive("trMod_menu_footer_txt") { - footer.set_text_string(submenu.help_text); + footer.as_textbox().set_text_string(submenu.help_text); } } else { text.set_color(255, 255, 255, 255); @@ -452,7 +517,7 @@ pub unsafe fn layout_build_parts_impl( }; } - let root_pane = &*(*layout).root_pane; + let root_pane = &mut *(*layout).root_pane; let block = data as *mut ResPane; let menu_pos = ResVec3::new(-360.0, 440.0, 0.0);