mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-20 00:46:34 +00:00
Use UI text box for Frame Advantage; add ui2d backend (#449)
* 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 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
c8349005c3
commit
a1c9e35b19
10 changed files with 808 additions and 13 deletions
2
.devcontainer/devcontainer.json
vendored
2
.devcontainer/devcontainer.json
vendored
|
@ -2,7 +2,7 @@
|
|||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.140.1/containers/docker-from-docker
|
||||
{
|
||||
"name": "Cargo Skyline",
|
||||
"image": "jugeeya/cargo-skyline:3.2.0",
|
||||
"image": "jugeeya/cargo-skyline:3.2.0-no-dkp",
|
||||
"mounts": [
|
||||
"source=ultimatetrainingmodpack-bashhistory,target=/commandhistory,type=volume"
|
||||
],
|
||||
|
|
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -1,2 +1,4 @@
|
|||
.devcontainer/** linguist-vendored
|
||||
.vscode/** linguist-vendored
|
||||
ryujinx_build.ps1 linguist-vendored
|
||||
ryujinx_build.sh linguist-vendored
|
||||
|
|
|
@ -12,6 +12,7 @@ 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"
|
||||
|
|
4
ryujinx_build.ps1
vendored
Normal file
4
ryujinx_build.ps1
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
$IP=(Test-Connection -ComputerName (hostname) -Count 1 | Select -ExpandProperty IPV4Address).IPAddressToString
|
||||
cargo skyline build --release
|
||||
Copy-Item target/aarch64-skyline-switch/release/libtraining_modpack.nro 'C:\Users\Jdsam\AppData\Roaming\Ryujinx\mods\contents\01006A800016E000\romfs\skyline\plugins\'
|
||||
cargo skyline listen --ip=$IP
|
|
@ -2,6 +2,7 @@
|
|||
#![feature(const_mut_refs)]
|
||||
#![feature(exclusive_range_pattern)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(c_variadic)]
|
||||
#![allow(
|
||||
clippy::borrow_interior_mutable_const,
|
||||
clippy::not_unsafe_ptr_arg_deref,
|
||||
|
@ -84,6 +85,8 @@ pub fn main() {
|
|||
EVENT_QUEUE.push(Event::smash_open());
|
||||
}
|
||||
|
||||
training::ui_hacks::install_hooks();
|
||||
|
||||
hitbox_visualizer::hitbox_visualization();
|
||||
hazard_manager::hazard_manager();
|
||||
training::training_mods();
|
||||
|
|
|
@ -44,15 +44,9 @@ unsafe fn is_actionable(module_accessor: *mut app::BattleObjectModuleAccessor) -
|
|||
}) || CancelModule::is_enable_cancel(module_accessor)
|
||||
}
|
||||
|
||||
fn update_frame_advantage(
|
||||
module_accessor: *mut app::BattleObjectModuleAccessor,
|
||||
new_frame_adv: i32,
|
||||
) {
|
||||
fn update_frame_advantage(new_frame_adv: i32) {
|
||||
unsafe {
|
||||
FRAME_ADVANTAGE = new_frame_adv;
|
||||
if MENU.frame_advantage == consts::OnOff::On {
|
||||
raygun_printer::print_string(&mut *module_accessor, &format!("{}", FRAME_ADVANTAGE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +81,6 @@ pub unsafe fn is_enable_transition_term(
|
|||
let cpu_module_accessor = get_module_accessor(FighterId::CPU);
|
||||
if was_in_hitstun(cpu_module_accessor) || was_in_shieldstun(cpu_module_accessor) {
|
||||
update_frame_advantage(
|
||||
module_accessor,
|
||||
(CPU_ACTIVE_FRAME as i64 - PLAYER_ACTIVE_FRAME as i64) as i32,
|
||||
);
|
||||
}
|
||||
|
@ -139,10 +132,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModule
|
|||
// if both are now active
|
||||
if PLAYER_ACTIONABLE && CPU_ACTIONABLE && FRAME_ADVANTAGE_CHECK {
|
||||
if was_in_hitstun(cpu_module_accessor) || was_in_shieldstun(cpu_module_accessor) {
|
||||
update_frame_advantage(
|
||||
player_module_accessor,
|
||||
(CPU_ACTIVE_FRAME as i64 - PLAYER_ACTIVE_FRAME as i64) as i32,
|
||||
);
|
||||
update_frame_advantage((CPU_ACTIVE_FRAME as i64 - PLAYER_ACTIVE_FRAME as i64) as i32);
|
||||
}
|
||||
|
||||
frame_counter::stop_counting(FRAME_COUNTER_INDEX);
|
||||
|
|
|
@ -23,6 +23,8 @@ pub mod sdi;
|
|||
pub mod shield;
|
||||
pub mod tech;
|
||||
pub mod throw;
|
||||
pub mod ui;
|
||||
pub mod ui_hacks;
|
||||
|
||||
mod air_dodge_direction;
|
||||
mod attack_angle;
|
||||
|
|
432
src/training/ui/mod.rs
Normal file
432
src/training/ui/mod.rs
Normal file
|
@ -0,0 +1,432 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use bitfield_struct::bitfield;
|
||||
|
||||
mod resources;
|
||||
pub use resources::*;
|
||||
|
||||
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) {
|
||||
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;
|
||||
let frame = (*self).frame;
|
||||
println!(
|
||||
"animTransform/resAnimationContent_{anim_cont_idx}: {name} of type {anim_type} on frame {frame}",
|
||||
);
|
||||
// AnimContentType 1 == MATERIAL
|
||||
if (name == "dig_3_anim" || name == "set_dmg_num_3") && anim_type == 1 {
|
||||
(*self).frame = 4.0;
|
||||
}
|
||||
if (name == "dig_2_anim" || name == "set_dmg_num_2") && anim_type == 1 {
|
||||
(*self).frame = 2.0;
|
||||
}
|
||||
if (name == "dig_1_anim" || name == "set_dmg_num_1") && anim_type == 1 {
|
||||
(*self).frame = 8.0;
|
||||
}
|
||||
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
|
||||
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],
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
pub unsafe fn as_parts(&mut self) -> *mut Parts {
|
||||
self as *mut Pane as *mut Parts
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct Parts {
|
||||
pub pane: Pane,
|
||||
// Some IntrusiveList
|
||||
link: PaneNode,
|
||||
pub layout: *mut Layout,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Picture {
|
||||
pub pane: Pane,
|
||||
material: *mut u8,
|
||||
vertex_colors: [[u8; 4]; 4],
|
||||
shared_memory: *mut u8,
|
||||
}
|
||||
|
||||
#[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
|
||||
m_text_buf: *const 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,
|
||||
m_text_len: u16,
|
||||
|
||||
m_bits: TextBoxBits,
|
||||
m_text_position: u8,
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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 {
|
||||
FlagsUserAllocated,
|
||||
FlagsTextureOnly,
|
||||
FlagsThresholdingAlphaInterpolation,
|
||||
FlagsBlackColorFloat,
|
||||
FlagsWhiteColorFloat,
|
||||
FlagsDynamicAllocatedColorData,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct Material {
|
||||
vtable: u64,
|
||||
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,
|
||||
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::FlagsBlackColorFloat as u8, 0)
|
||||
} else {
|
||||
(MaterialFlags::FlagsWhiteColorFloat 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)]
|
||||
pub struct RawLayout {
|
||||
pub anim_trans_list: AnimTransformNode,
|
||||
pub root_pane: *const Pane,
|
||||
group_container: u64,
|
||||
layout_size: f64,
|
||||
pub layout_name: *const skyline::libc::c_char,
|
||||
}
|
||||
|
||||
#[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 raw_layout: RawLayout,
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
170
src/training/ui/resources.rs
Normal file
170
src/training/ui/resources.rs
Normal file
|
@ -0,0 +1,170 @@
|
|||
// Maybe needs a vtable.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResVec2 {
|
||||
x: f32,
|
||||
y: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResVec3 {
|
||||
x: f32,
|
||||
y: f32,
|
||||
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 name_matches(&self, other: &str) -> bool {
|
||||
self.name
|
||||
.iter()
|
||||
.take_while(|b| **b != 0)
|
||||
.map(|b| *b as char)
|
||||
.collect::<String>()
|
||||
== other
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResTextBox {
|
||||
pub pane: ResPane,
|
||||
text_buf_bytes: u16,
|
||||
text_str_bytes: u16,
|
||||
material_idx: u16,
|
||||
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.
|
||||
*/
|
||||
}
|
||||
|
||||
#[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;
|
||||
*/
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResPictureWithTex<const TEX_COORD_COUNT: usize> {
|
||||
pub picture: ResPicture,
|
||||
tex_coords: [[ResVec2; TEX_COORD_COUNT]; 4],
|
||||
}
|
191
src/training/ui_hacks.rs
Normal file
191
src/training/ui_hacks.rs
Normal file
|
@ -0,0 +1,191 @@
|
|||
use crate::training::combo::FRAME_ADVANTAGE;
|
||||
use crate::training::ui::*;
|
||||
use training_mod_consts::OnOff;
|
||||
|
||||
#[skyline::hook(offset = 0x4b620)]
|
||||
pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) {
|
||||
let layout_name = skyline::from_c_str((*layout).raw_layout.layout_name);
|
||||
let layout_root_pane = &*(*layout).raw_layout.root_pane;
|
||||
let _anim_list = &mut (*layout).raw_layout.anim_trans_list;
|
||||
// anim_list.iterate_anim_list();
|
||||
|
||||
if layout_name == "info_training" {
|
||||
if let Some(parent) = layout_root_pane.find_pane_by_name_recursive("trMod_disp_0") {
|
||||
if crate::common::MENU.frame_advantage == OnOff::On {
|
||||
parent.alpha = 255;
|
||||
parent.global_alpha = 255;
|
||||
} else {
|
||||
parent.alpha = 0;
|
||||
parent.global_alpha = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(header) = layout_root_pane.find_pane_by_name_recursive("trMod_disp_0_header") {
|
||||
header.set_text_string("Frame Advantage");
|
||||
}
|
||||
|
||||
if let Some(text) = layout_root_pane.find_pane_by_name_recursive("trMod_disp_0_txt") {
|
||||
text.set_text_string(format!("{FRAME_ADVANTAGE}").as_str());
|
||||
let text = text as *mut Pane as *mut TextBox;
|
||||
if FRAME_ADVANTAGE < 0 {
|
||||
(*text).set_color(200, 8, 8, 255);
|
||||
} else if FRAME_ADVANTAGE == 0 {
|
||||
(*text).set_color(0, 0, 0, 255);
|
||||
} else {
|
||||
(*text).set_color(31, 198, 0, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
original!()(layout, draw_info, cmd_buffer);
|
||||
}
|
||||
|
||||
#[skyline::hook(offset = 0x493a0)]
|
||||
pub unsafe fn layout_build_parts_impl(
|
||||
layout: *mut Layout,
|
||||
out_build_result_information: *mut u8,
|
||||
device: *const u8,
|
||||
data: *mut u8,
|
||||
parts_build_data_set: *const u8,
|
||||
build_arg_set: *const u8,
|
||||
build_res_set: *const u8,
|
||||
kind: u32,
|
||||
) -> *mut Pane {
|
||||
let layout_name = skyline::from_c_str((*layout).raw_layout.layout_name);
|
||||
let _kind_str: String = kind.to_le_bytes().map(|b| b as char).iter().collect();
|
||||
|
||||
if layout_name != "info_training" {
|
||||
return original!()(
|
||||
layout,
|
||||
out_build_result_information,
|
||||
device,
|
||||
data,
|
||||
parts_build_data_set,
|
||||
build_arg_set,
|
||||
build_res_set,
|
||||
kind,
|
||||
);
|
||||
}
|
||||
|
||||
let root_pane = (*layout).raw_layout.root_pane;
|
||||
|
||||
let block = data as *mut ResPane;
|
||||
let num_display_panes = 1;
|
||||
(0..num_display_panes).for_each(|idx| {
|
||||
let mod_prefix = "trMod_disp_";
|
||||
let parent_name = format!("{mod_prefix}{idx}");
|
||||
let pic_name = format!("{mod_prefix}{idx}_base");
|
||||
let header_name = format!("{mod_prefix}{idx}_header");
|
||||
let txt_name = format!("{mod_prefix}{idx}_txt");
|
||||
|
||||
if (*block).name_matches("pic_numbase_01") {
|
||||
let block = block as *mut ResPictureWithTex<1>;
|
||||
let mut pic_block = (*block).clone();
|
||||
pic_block.picture.pane.set_name(pic_name.as_str());
|
||||
pic_block.picture.pane.set_pos(ResVec3::default());
|
||||
let pic_pane = original!()(
|
||||
layout,
|
||||
out_build_result_information,
|
||||
device,
|
||||
&mut pic_block as *mut ResPictureWithTex<1> as *mut u8,
|
||||
parts_build_data_set,
|
||||
build_arg_set,
|
||||
build_res_set,
|
||||
kind,
|
||||
);
|
||||
(*(*pic_pane).parent).remove_child(&*pic_pane);
|
||||
|
||||
// pic is loaded first, we can create our parent pane here.
|
||||
let disp_pane_kind = u32::from_le_bytes([b'p', b'a', b'n', b'1']);
|
||||
let mut disp_pane_block = ResPane::new(parent_name.as_str());
|
||||
disp_pane_block.set_pos(ResVec3::new(806.0, 390.0 - (idx as f32 * 110.0), 0.0));
|
||||
let disp_pane = original!()(
|
||||
layout,
|
||||
out_build_result_information,
|
||||
device,
|
||||
&mut disp_pane_block as *mut ResPane as *mut u8,
|
||||
parts_build_data_set,
|
||||
build_arg_set,
|
||||
build_res_set,
|
||||
disp_pane_kind,
|
||||
);
|
||||
(*(*disp_pane).parent).remove_child(&*disp_pane);
|
||||
(*root_pane).append_child(&*disp_pane);
|
||||
(*disp_pane).append_child(&*pic_pane);
|
||||
}
|
||||
|
||||
if (*block).name_matches("set_txt_num_01") {
|
||||
let disp_pane = (*root_pane)
|
||||
.find_pane_by_name(parent_name.as_str(), true)
|
||||
.unwrap();
|
||||
|
||||
let block = data as *mut ResTextBox;
|
||||
let mut text_block = (*block).clone();
|
||||
text_block.pane.set_name(txt_name.as_str());
|
||||
text_block.pane.set_pos(ResVec3::new(-10.0, -25.0, 0.0));
|
||||
let text_pane = original!()(
|
||||
layout,
|
||||
out_build_result_information,
|
||||
device,
|
||||
&mut text_block as *mut ResTextBox as *mut u8,
|
||||
parts_build_data_set,
|
||||
build_arg_set,
|
||||
build_res_set,
|
||||
kind,
|
||||
);
|
||||
(*text_pane).set_text_string(format!("Pane {idx}!").as_str());
|
||||
// Ensure Material Colors are not hardcoded so we can just use SetTextColor.
|
||||
(*((*(text_pane as *mut TextBox)).m_p_material))
|
||||
.set_white_color(255.0, 255.0, 255.0, 255.0);
|
||||
(*((*(text_pane as *mut TextBox)).m_p_material)).set_black_color(0.0, 0.0, 0.0, 255.0);
|
||||
(*(*text_pane).parent).remove_child(&*text_pane);
|
||||
(*disp_pane).append_child(&*text_pane);
|
||||
}
|
||||
|
||||
if (*block).name_matches("txt_cap_01") {
|
||||
let disp_pane = (*root_pane)
|
||||
.find_pane_by_name(parent_name.as_str(), true)
|
||||
.unwrap();
|
||||
|
||||
let block = data as *mut ResTextBox;
|
||||
let mut header_block = (*block).clone();
|
||||
header_block.pane.set_name(header_name.as_str());
|
||||
header_block.pane.set_pos(ResVec3::new(0.0, 25.0, 0.0));
|
||||
let header_pane = original!()(
|
||||
layout,
|
||||
out_build_result_information,
|
||||
device,
|
||||
&mut header_block as *mut ResTextBox as *mut u8,
|
||||
parts_build_data_set,
|
||||
build_arg_set,
|
||||
build_res_set,
|
||||
kind,
|
||||
);
|
||||
(*header_pane).set_text_string(format!("Header {idx}").as_str());
|
||||
// Ensure Material Colors are not hardcoded so we can just use SetTextColor.
|
||||
(*((*(header_pane as *mut TextBox)).m_p_material))
|
||||
.set_white_color(255.0, 255.0, 255.0, 255.0);
|
||||
(*((*(header_pane as *mut TextBox)).m_p_material))
|
||||
.set_black_color(0.0, 0.0, 0.0, 255.0);
|
||||
// Header should be white text
|
||||
(*(header_pane as *mut TextBox)).set_color(255, 255, 255, 255);
|
||||
(*(*header_pane).parent).remove_child(&*header_pane);
|
||||
(*disp_pane).append_child(&*header_pane);
|
||||
}
|
||||
});
|
||||
|
||||
original!()(
|
||||
layout,
|
||||
out_build_result_information,
|
||||
device,
|
||||
data,
|
||||
parts_build_data_set,
|
||||
build_arg_set,
|
||||
build_res_set,
|
||||
kind,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn install_hooks() {
|
||||
skyline::install_hooks!(handle_draw, layout_build_parts_impl,);
|
||||
}
|
Loading…
Reference in a new issue