mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2025-05-03 19:09:18 +00:00
149 lines
5.2 KiB
Rust
149 lines
5.2 KiB
Rust
#[cfg(feature = "layout_arc_from_file")]
|
|
use byte_unit::MEBIBYTE;
|
|
use sarc::SarcFile;
|
|
use skyline::nn::ui2d::*;
|
|
use training_mod_consts::{OnOff, MENU};
|
|
|
|
use crate::common::{is_ready_go, is_training_mode, menu::QUICK_MENU_ACTIVE};
|
|
#[cfg(feature = "layout_arc_from_file")]
|
|
use crate::consts::LAYOUT_ARC_PATH;
|
|
|
|
mod damage;
|
|
mod display;
|
|
mod input_log;
|
|
mod menu;
|
|
pub mod notifications;
|
|
|
|
#[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).layout_name);
|
|
let root_pane = &mut *(*layout).root_pane;
|
|
|
|
// Set HUD to invisible if HUD is toggled off
|
|
if is_training_mode()
|
|
&& is_ready_go()
|
|
&& [
|
|
"info_playercursor",
|
|
"info_playercursor_item",
|
|
"info_melee",
|
|
"info_radar_a",
|
|
"info_radar_b",
|
|
]
|
|
.contains(&layout_name.as_str())
|
|
{
|
|
// InfluencedAlpha means "Should my children panes' alpha be influenced by mine, as the parent?"
|
|
root_pane.flags |= 1 << PaneFlag::InfluencedAlpha as u8;
|
|
root_pane.set_visible(MENU.hud == OnOff::On && !QUICK_MENU_ACTIVE);
|
|
}
|
|
|
|
damage::draw(root_pane, &layout_name);
|
|
|
|
if layout_name == "info_training" {
|
|
input_log::draw(root_pane);
|
|
display::draw(root_pane);
|
|
menu::draw(root_pane);
|
|
}
|
|
|
|
original!()(layout, draw_info, cmd_buffer);
|
|
}
|
|
|
|
// Allocate a static amount of memory that Smash isn't allowed to deallocate,
|
|
// in order for us to be able to swap the 'layout.arc' with the current
|
|
// version of the file in between loads of training mode.
|
|
#[cfg(feature = "layout_arc_from_file")]
|
|
const LAYOUT_ARC_SIZE: usize = (3 * MEBIBYTE) as usize;
|
|
#[cfg(feature = "layout_arc_from_file")]
|
|
static mut LAYOUT_ARC: &mut [u8; LAYOUT_ARC_SIZE] = &mut [0u8; LAYOUT_ARC_SIZE];
|
|
|
|
/// We are editing the info_training/layout.arc and replacing the original file with our
|
|
/// modified version from `LAYOUT_ARC_PATH`
|
|
///
|
|
/// When we edit the layout we are doing two things.
|
|
///
|
|
/// 1. Creating a new BFLYT inside the layout.arc for whatever component we are making. For example,
|
|
/// the slider menu button.
|
|
///
|
|
/// 2. Adding a Parts pane to the info_training.bflyt with the "Part Name" matching the name of
|
|
/// our new BFLYT without the file extension (mimicking how it's done with native Parts panes)
|
|
///
|
|
/// # Warnings
|
|
/// When creating a BFLYT from an existing one we need to edit the names of the panes so that
|
|
/// the default animations no longer modify them. Otherwise the game will override properties,
|
|
/// i.e. material colours, and we won't be able to control them properly.
|
|
///
|
|
/// Once we have the file edited and saved to the correct location we can access the pane
|
|
/// from the layout as we normally would in our Draw function
|
|
/// `(root_pane.find_pane_by_name_recursive("name_of_parts_pane")`.
|
|
///
|
|
/// # Usage
|
|
/// Now say I want to edit background colour of the button's label.
|
|
/// I would have to grab the parts pane and find the pane I want to modify on it, then I'd be able
|
|
/// to make the modifications as I normally would.
|
|
///
|
|
/// ```rust
|
|
/// let slider_button = root_pane.find_pane_by_name_recursive("name_of_parts_pane");
|
|
/// let label_bg = slider_button.find_pane_by_name_recursive("name_of_picture_pane");
|
|
///
|
|
/// let label_material = &mut *label_bg.as_picture().material;
|
|
///
|
|
/// label_material.set_white_res_color(LABEL_WHITE_SELECTED_COLOR);
|
|
/// label_material.set_black_res_color(LABEL_BLACK_SELECTED_COLOR);
|
|
/// ```
|
|
#[skyline::hook(offset = 0x37730d4, inline)]
|
|
unsafe fn handle_layout_arc_malloc(ctx: &mut skyline::hooks::InlineCtx) {
|
|
if !is_training_mode() {
|
|
return;
|
|
}
|
|
|
|
let decompressed_file = *ctx.registers[21].x.as_ref() as *const u8;
|
|
let decompressed_size = *ctx.registers[1].x.as_ref() as usize;
|
|
|
|
let layout_arc = SarcFile::read(std::slice::from_raw_parts(
|
|
decompressed_file,
|
|
decompressed_size,
|
|
))
|
|
.unwrap();
|
|
let training_layout = layout_arc.files.iter().find(|f| {
|
|
f.name.is_some() && f.name.as_ref().unwrap() == &String::from("blyt/info_training.bflyt")
|
|
});
|
|
if training_layout.is_none() {
|
|
return;
|
|
}
|
|
|
|
let inject_arc;
|
|
let inject_arc_size: u64;
|
|
|
|
#[cfg(feature = "layout_arc_from_file")]
|
|
{
|
|
let inject_arc_from_file = std::fs::read(LAYOUT_ARC_PATH).unwrap();
|
|
inject_arc_size = inject_arc_from_file.len() as u64;
|
|
|
|
// Copy read file to global
|
|
inject_arc_from_file
|
|
.iter()
|
|
.enumerate()
|
|
.for_each(|(idx, byte)| LAYOUT_ARC[idx] = *byte);
|
|
inject_arc = LAYOUT_ARC.as_ptr();
|
|
}
|
|
|
|
#[cfg(not(feature = "layout_arc_from_file"))]
|
|
{
|
|
include_flate::flate!(static INJECT_ARC_FROM_FILE: [u8] from "src/static/layout.arc");
|
|
|
|
inject_arc = INJECT_ARC_FROM_FILE.as_ptr();
|
|
inject_arc_size = INJECT_ARC_FROM_FILE.len() as u64;
|
|
}
|
|
|
|
// Decompressed file pointer
|
|
let decompressed_file = ctx.registers[21].x.as_mut();
|
|
*decompressed_file = inject_arc as u64;
|
|
|
|
// Decompressed size is in each of these registers
|
|
*ctx.registers[1].x.as_mut() = inject_arc_size;
|
|
*ctx.registers[23].x.as_mut() = inject_arc_size;
|
|
*ctx.registers[24].x.as_mut() = inject_arc_size;
|
|
}
|
|
|
|
pub fn init() {
|
|
skyline::install_hooks!(handle_draw, handle_layout_arc_malloc);
|
|
}
|