1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2024-11-24 02:44:17 +00:00

Use nnsdk and smash upstreams for ui2d (#453)

* A bunch of things

* Current progress

* Fix for ResAnimationContent

* Figure out Parts*

* Cleanup, just because

* New pane working!!!

* New null pane for hierarchy

* Success with parent pane

* Generate multiple panes

* Multiple panes, almost working text color

* MaterialColor test, but fails

* Forgot bitfield-struct

* Vtable for material. Fixes SetWhiteColor!

* Refactor color changing, change naming scheme

* Just Frame Advantage

* Merge

* Delete T_test.txt

* Delete set_txt_num_01.txt

* Delete libtraining_modpack.nro

* Format Rust code using rustfmt

* Ignore shell scripts in repo languages

* General refactor, add basis for quick menu

* Small refactor, fix ordering of submenu options

* Toggles, sliders

* Tons of progress...

* Correct dmg updater, remove old quick menu backend

* Fix damage percentage display

* Small QoL

* Format Rust code using rustfmt

* More edits. Use Quit Training button as Modpack Menu header

* Finish merge

* Format Rust code using rustfmt

* Use vanilla backgrounds for text options

* Format ui_hacks, also always do new percent display

* Fix merge

* That was the most awful merge ever

* Address clippy warnings

* Format Rust code using rustfmt

* Last impls for resources, small cleanup

* Use macro for pane names

* Format

* Add HUD toggle

* Small change

* Fix for reentering training mode

* Last cleanup

* Format Rust code using rustfmt

* Try using nnsdk/smash upstream

* Format Rust code using rustfmt

* Update Cargo.toml

* Update Cargo.toml

* Update Cargo.toml

* Update Cargo.toml

* Update Cargo.toml

* Update Cargo.toml

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
jugeeya 2022-12-30 19:22:30 -08:00 committed by GitHub
parent c1a6f6626d
commit 7ec7928c55
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 78 additions and 1004 deletions

View file

@ -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"

View file

@ -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;

View file

@ -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::<String>()
}
}
#[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)
}

View file

@ -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::<String>()
}
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<const TEX_COORD_COUNT: usize> {
pub picture: ResPicture,
tex_coords: [[ResVec2; TEX_COORD_COUNT]; 4],
}
impl<const TEX_COORD_COUNT: usize> Deref for ResPictureWithTex<TEX_COORD_COUNT> {
type Target = ResPane;
fn deref(&self) -> &Self::Target {
&self.picture
}
}
impl<const TEX_COORD_COUNT: usize> DerefMut for ResPictureWithTex<TEX_COORD_COUNT> {
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<const PROPERTY_COUNT: usize> {
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<const TEX_COORD_COUNT: usize> {
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<const TEX_COORD_COUNT: usize, const FRAME_COUNT: usize> {
pub window: ResWindow,
content: ResWindowContentWithTexCoords<TEX_COORD_COUNT>,
frame_offset_table: [u32; FRAME_COUNT],
frames: [ResWindowFrame; FRAME_COUNT],
}
impl<const TEX_COORD_COUNT: usize, const FRAME_COUNT: usize> Deref
for ResWindowWithTexCoordsAndFrames<TEX_COORD_COUNT, FRAME_COUNT>
{
type Target = ResPane;
fn deref(&self) -> &Self::Target {
&self.window
}
}
impl<const TEX_COORD_COUNT: usize, const FRAME_COUNT: usize> DerefMut
for ResWindowWithTexCoordsAndFrames<TEX_COORD_COUNT, FRAME_COUNT>
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.window
}
}

View file

@ -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);