mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-27 20:34:03 +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:
parent
c1a6f6626d
commit
7ec7928c55
5 changed files with 78 additions and 1004 deletions
|
@ -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_smash = { git = "https://github.com/ultimate-research/skyline-smash.git", branch = "no-cache" }
|
||||||
skyline-web = { git = "https://github.com/skyline-rs/skyline-web.git" }
|
skyline-web = { git = "https://github.com/skyline-rs/skyline-web.git" }
|
||||||
bitflags = "1.2.1"
|
bitflags = "1.2.1"
|
||||||
bitfield-struct = "0.1.8"
|
|
||||||
parking_lot = { version = "0.12.0", features = ["nightly"] }
|
parking_lot = { version = "0.12.0", features = ["nightly"] }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
owo-colors = "2.1.0"
|
owo-colors = "2.1.0"
|
||||||
|
@ -35,6 +34,7 @@ native-tls = { version = "0.2.11", features = ["vendored"] }
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
native-tls = { git = "https://github.com/skyline-rs/rust-native-tls", rev = "f202fca" }
|
native-tls = { git = "https://github.com/skyline-rs/rust-native-tls", rev = "f202fca" }
|
||||||
|
nnsdk = { git = "https://github.com/ultimate-research/nnsdk-rs" }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
|
@ -23,7 +23,6 @@ pub mod sdi;
|
||||||
pub mod shield;
|
pub mod shield;
|
||||||
pub mod tech;
|
pub mod tech;
|
||||||
pub mod throw;
|
pub mod throw;
|
||||||
pub mod ui;
|
|
||||||
pub mod ui_hacks;
|
pub mod ui_hacks;
|
||||||
|
|
||||||
mod air_dodge_direction;
|
mod air_dodge_direction;
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +1,76 @@
|
||||||
use crate::common::{get_player_dmg_digits, is_ready_go, is_training_mode};
|
use crate::common::{get_player_dmg_digits, is_ready_go, is_training_mode};
|
||||||
use crate::consts::FighterId;
|
use crate::consts::FighterId;
|
||||||
use crate::training::ui::*;
|
|
||||||
use crate::{common::menu::QUICK_MENU_ACTIVE, training::combo::FRAME_ADVANTAGE};
|
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_consts::{OnOff, MENU};
|
||||||
use training_mod_tui::gauge::GaugeState;
|
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_DISPLAY_PANES: usize = 1;
|
||||||
pub static NUM_MENU_TEXT_OPTIONS: usize = 27;
|
pub static NUM_MENU_TEXT_OPTIONS: usize = 27;
|
||||||
pub static NUM_MENU_TEXT_SLIDERS: usize = 4;
|
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" {
|
if is_training_mode() && is_ready_go() && layout_name == "info_melee" {
|
||||||
for player_name in &["p1", "p2"] {
|
for player_name in &["p1", "p2"] {
|
||||||
if let Some(parent) = root_pane.find_pane_by_name_recursive(player_name) {
|
if let Some(parent) = root_pane.find_pane_by_name_recursive(player_name) {
|
||||||
let _p1_layout_name =
|
let _p1_layout_name = skyline::from_c_str((*parent.as_parts().layout).layout_name);
|
||||||
skyline::from_c_str((*(*parent.as_parts()).layout).layout_name);
|
let anim_list = &mut (*parent.as_parts().layout).anim_trans_list;
|
||||||
let anim_list = &mut (*(*parent.as_parts()).layout).anim_trans_list;
|
|
||||||
|
|
||||||
let mut has_altered_anim_list = false;
|
let mut has_altered_anim_list = false;
|
||||||
let (hundreds, tens, _, _) = get_player_dmg_digits(match *player_name {
|
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 {
|
if dmg_num.alpha != 255 || dmg_num.global_alpha != 255 {
|
||||||
dmg_num.set_visible(true);
|
dmg_num.set_visible(true);
|
||||||
if !has_altered_anim_list {
|
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;
|
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") {
|
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") {
|
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();
|
let text = text.as_textbox();
|
||||||
|
text.set_text_string(format!("{FRAME_ADVANTAGE}").as_str());
|
||||||
match FRAME_ADVANTAGE {
|
match FRAME_ADVANTAGE {
|
||||||
x if x < 0 => text.set_color(200, 8, 8, 255),
|
x if x < 0 => text.set_color(200, 8, 8, 255),
|
||||||
x if x == 0 => text.set_color(0, 0, 0, 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"] {
|
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) {
|
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"
|
"Modpack Menu"
|
||||||
} else {
|
} else {
|
||||||
// Awkward. We should get the o.g. translation for non-english games
|
// 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| {
|
(0..NUM_MENU_TABS).for_each(|idx| {
|
||||||
root_pane
|
root_pane
|
||||||
.find_pane_by_name_recursive(format!("trMod_menu_tab_{idx}").as_str())
|
.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 {
|
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 list = &tab.lists[list_section];
|
||||||
let submenu = &list.items[list_idx];
|
let submenu = &list.items[list_idx];
|
||||||
let is_selected = list.state.selected().filter(|s| *s == list_idx).is_some();
|
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_text_string(submenu.submenu_title);
|
||||||
text.set_visible(true);
|
text.set_visible(true);
|
||||||
let text = text.as_textbox();
|
|
||||||
if is_selected {
|
if is_selected {
|
||||||
text.set_color(0x27, 0x4E, 0x13, 255);
|
text.set_color(0x27, 0x4E, 0x13, 255);
|
||||||
if let Some(footer) =
|
if let Some(footer) =
|
||||||
root_pane.find_pane_by_name_recursive("trMod_menu_footer_txt")
|
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 {
|
} else {
|
||||||
text.set_color(255, 255, 255, 255);
|
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 block = data as *mut ResPane;
|
||||||
let menu_pos = ResVec3::new(-360.0, 440.0, 0.0);
|
let menu_pos = ResVec3::new(-360.0, 440.0, 0.0);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue