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

Move files to sd:/ultimate/TrainingModpack (#480)

* Initial

* Move filepaths

* Small fix

* Notification on save state save
This commit is contained in:
jugeeya 2023-02-13 19:58:22 -08:00 committed by GitHub
parent 8ac2a3e8b1
commit e981a0bfd0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1272 additions and 1220 deletions

View file

@ -357,7 +357,7 @@ To install a beta version of the modpack, follow the same procedure using the [l
`SD:/atmosphere/contents/01006A800016E000/romfs/skyline/plugins/libnro_hook.nro`
`SD:/atmosphere/contents/01006A800016E000/romfs/skyline/plugins/libparam_hook.nro`
`SD:/atmosphere/contents/01006A800016E000/romfs/skyline/plugins/libtraining_modpack.nro`
`SD:/TrainingModpack/`
`SD:/ultimate/TrainingModpack/`
17. **Can I donate to the Training Modpack?**
You can find the donation link in the [#faq](https://discord.com/channels/407970595418931200/714960353058095216) Discord channel. We use the money to commission video edits for releases, so thank you if you do end up donating!
@ -386,7 +386,7 @@ To install a beta version of the modpack, follow the same procedure using the [l
25. **How do I reset my Training Modpack settings?**
If you want to completely reset your menu selections back to the factory default, all you have to do is delete this file:
`SD:/TrainingModpack/training_modpack_menu.conf`
`SD:/ultimate/TrainingModpack/training_modpack_menu.conf`
26. **What input delay should I pick for practicing online?**
Good LAN connections can be simulated with an input delay of 3-5 frames. Poorer Wifi connections can be up to 6-8 frames.

View file

@ -1,6 +1,8 @@
use std::collections::HashMap;
use std::fs;
use crate::consts::TRAINING_MODPACK_TOML_PATH;
use lazy_static::lazy_static;
use log::info;
use serde::Deserialize;
@ -78,13 +80,13 @@ pub struct TopLevelBtnComboConfig {
}
pub fn load_from_file() {
let combo_path = "sd:/TrainingModpack/training_modpack.toml";
info!("Checking for previous button combo settings in training_modpack.toml...");
let combo_path = TRAINING_MODPACK_TOML_PATH;
info!("Checking for previous button combo settings in {TRAINING_MODPACK_TOML_PATH}...");
let mut valid_button_config = false;
if fs::metadata(combo_path).is_ok() {
info!("Previous button combo settings found. Loading...");
let combo_conf =
fs::read_to_string(combo_path).unwrap_or_else(|_| panic!("Could not read {}", combo_path));
let combo_conf = fs::read_to_string(combo_path)
.unwrap_or_else(|_| panic!("Could not read {}", combo_path));
let conf: Result<TopLevelBtnComboConfig, toml::de::Error> = toml::from_str(&combo_conf);
if let Ok(conf) = conf {
if validate_config(conf) {
@ -96,13 +98,11 @@ pub fn load_from_file() {
if !valid_button_config {
info!("No previous button combo file found. Creating...");
fs::write(combo_path, DEFAULT_BTN_CONFIG)
.expect("Failed to write button config conf file");
fs::write(combo_path, DEFAULT_BTN_CONFIG).expect("Failed to write button config conf file");
save_all_btn_config_from_defaults();
}
}
fn save_all_btn_config_from_defaults() {
let conf = TopLevelBtnComboConfig {
button_config: BtnComboConfig {
@ -146,8 +146,13 @@ fn save_all_btn_config_from_toml(data: &str) {
fn validate_config(conf: TopLevelBtnComboConfig) -> bool {
let conf = conf.button_config;
let configs = [conf.open_menu, conf.save_state, conf.load_state,
conf.previous_save_state_slot, conf.next_save_state_slot];
let configs = [
conf.open_menu,
conf.save_state,
conf.load_state,
conf.previous_save_state_slot,
conf.next_save_state_slot,
];
let bad_keys = configs
.iter()
.flat_map(|btn_list| {
@ -164,8 +169,9 @@ fn validate_config(conf: TopLevelBtnComboConfig) -> bool {
0x71,
"Training Modpack custom button\nconfiguration is invalid!\0",
&format!(
"The following keys are invalid in\nsd:/TrainingModpack/training_modpack.toml:\n\
"The following keys are invalid in\n{}:\n\
{:?}\n\nPossible Keys: {:#?}\0",
TRAINING_MODPACK_TOML_PATH,
&bad_keys,
BUTTON_MAPPING.keys()
),
@ -207,13 +213,14 @@ fn combo_passes(
) -> bool {
unsafe {
let (hold, press) = get_combo_keys(combo);
let this_combo_passes = hold.iter()
let this_combo_passes = hold
.iter()
.map(|hold| *BUTTON_MAPPING.get(&*hold.to_uppercase()).unwrap())
.all(|hold| ControlModule::check_button_on(module_accessor, hold))
&& press
.iter()
.map(|press| *BUTTON_MAPPING.get(&*press.to_uppercase()).unwrap())
.all(|press| ControlModule::check_button_trigger(module_accessor, press));
.iter()
.map(|press| *BUTTON_MAPPING.get(&*press.to_uppercase()).unwrap())
.all(|press| ControlModule::check_button_trigger(module_accessor, press));
this_combo_passes
}

View file

@ -6,12 +6,13 @@ use serde::Deserialize;
use skyline::nn::hid::NpadGcState;
use toml;
use crate::consts::DEV_TOML_PATH;
use crate::logging::info;
/// Hot-reloadable configs for quicker development
///
/// In game, press L+R+A at any point to reread these configs from
/// the file in sd:/TrainingModpack/dev.toml
/// the file in DEV_TOML_PATH on the SD card
///
/// Example usage:
///
@ -42,7 +43,7 @@ lazy_static! {
impl DevConfig {
fn load_from_toml() -> DevConfig {
let dev_path = "sd:/TrainingModpack/dev.toml";
let dev_path = DEV_TOML_PATH;
if fs::metadata(dev_path).is_ok() {
info!("Loading dev.toml configs...");
let dev_config_str = fs::read_to_string(dev_path).unwrap_or_else(|_| panic!("Could not read {}", dev_path));

View file

@ -8,6 +8,7 @@ use training_mod_consts::MenuJsonStruct;
use training_mod_tui::AppPage;
use crate::common::*;
use crate::consts::MENU_OPTIONS_PATH;
use crate::events::{Event, EVENT_QUEUE};
use crate::logging::*;
@ -22,14 +23,11 @@ pub unsafe fn menu_condition(module_accessor: &mut app::BattleObjectModuleAccess
button_config::combo_passes_exclusive(module_accessor, button_config::ButtonCombo::OpenMenu)
}
const MENU_CONF_PATH: &str = "sd:/TrainingModpack/training_modpack_menu.json";
pub fn load_from_file() {
let menu_conf_path = "sd:/TrainingModpack/training_modpack_menu.json";
info!("Checking for previous menu in training_modpack_menu.json...");
if fs::metadata(menu_conf_path).is_ok() {
let menu_conf = fs::read_to_string(menu_conf_path)
.unwrap_or_else(|_| panic!("Could not remove {}", menu_conf_path));
info!("Checking for previous menu in {MENU_OPTIONS_PATH}...");
if fs::metadata(MENU_OPTIONS_PATH).is_ok() {
let menu_conf = fs::read_to_string(MENU_OPTIONS_PATH)
.unwrap_or_else(|_| panic!("Could not remove {}", MENU_OPTIONS_PATH));
if let Ok(menu_conf_json) = serde_json::from_str::<MenuJsonStruct>(&menu_conf) {
unsafe {
MENU = menu_conf_json.menu;
@ -38,10 +36,10 @@ pub fn load_from_file() {
}
} else {
warn!("Previous menu found but is invalid. Deleting...");
fs::remove_file(menu_conf_path).unwrap_or_else(|_| {
fs::remove_file(MENU_OPTIONS_PATH).unwrap_or_else(|_| {
panic!(
"{} has invalid schema but could not be deleted!",
menu_conf_path
MENU_OPTIONS_PATH
)
});
}
@ -58,7 +56,7 @@ pub unsafe fn set_menu_from_json(message: &str) {
MENU = message_json.menu;
DEFAULTS_MENU = message_json.defaults_menu;
fs::write(
MENU_CONF_PATH,
MENU_OPTIONS_PATH,
serde_json::to_string_pretty(&message_json).unwrap(),
)
.expect("Failed to write menu settings file");
@ -208,7 +206,7 @@ pub fn handle_get_npad_state(state: *mut NpadGcState, _controller_id: *const u32
BUTTON_PRESSES.r.is_pressed = true;
}
// Special case for frame-by-frame
if FRAME_COUNTER < MENU_INPUT_WAIT_FRAMES && (*state).Buttons & (1 << 8) > 0 {
if FRAME_COUNTER > MENU_INPUT_WAIT_FRAMES && (*state).Buttons & (1 << 8) > 0 {
BUTTON_PRESSES.zl.is_pressed = true;
}
if (*state).Buttons & (1 << 9) > 0 {
@ -223,7 +221,10 @@ pub fn handle_get_npad_state(state: *mut NpadGcState, _controller_id: *const u32
if (*state).Buttons & ((1 << 15) | (1 << 19)) > 0 {
BUTTON_PRESSES.down.is_pressed = true;
}
if (*state).Buttons & ((1 << 13) | (1 << 17)) > 0 {
// Special case for "UP" in menu open button combo
if FRAME_COUNTER > MENU_INPUT_WAIT_FRAMES
&& (*state).Buttons & ((1 << 13) | (1 << 17)) > 0
{
BUTTON_PRESSES.up.is_pressed = true;
}

View file

@ -2,10 +2,12 @@ use std::fs;
use skyline_web::DialogOk;
use crate::consts::{
LEGACY_MENU_OPTIONS_PATH, MENU_DEFAULT_OPTIONS_PATH, MENU_OPTIONS_PATH, VERSION_TXT_PATH,
};
use crate::logging::*;
pub const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
const VERSION_FILE_PATH: &str = "sd:/TrainingModpack/version.txt";
enum VersionCheck {
Current,
@ -33,7 +35,7 @@ fn record_current_version(fpath: &str) {
}
pub fn version_check() {
match is_current_version(VERSION_FILE_PATH) {
match is_current_version(VERSION_TXT_PATH) {
VersionCheck::Current => {
// Version is current, no need to take any action
}
@ -47,13 +49,16 @@ pub fn version_check() {
)
);
// Remove old menu selections, silently ignoring errors (i.e. if the file doesn't exist)
fs::remove_file("sd:/TrainingModpack/training_modpack_menu.conf")
.unwrap_or_else(|_| error!("Couldn't remove training_modpack_menu.conf"));
fs::remove_file("sd:/TrainingModpack/training_modpack_menu.json")
.unwrap_or_else(|_| error!("Couldn't remove training_modpack_menu.json"));
fs::remove_file("sd:/TrainingModpack/training_modpack_menu_defaults.conf")
.unwrap_or_else(|_| error!("Couldn't remove training_modpack_menu_defaults.conf"));
record_current_version(VERSION_FILE_PATH);
[
MENU_OPTIONS_PATH,
MENU_DEFAULT_OPTIONS_PATH,
LEGACY_MENU_OPTIONS_PATH,
]
.iter()
.for_each(|path| {
fs::remove_file(path).unwrap_or_else(|_| error!("Couldn't remove {path}"))
});
record_current_version(VERSION_TXT_PATH);
}
VersionCheck::NoFile => {
// Display dialog box on fresh installation
@ -63,7 +68,7 @@ pub fn version_check() {
Please refer to the Github page and the Discord server for a full list of features and instructions on how to utilize the improved Training Mode."
)
);
record_current_version(VERSION_FILE_PATH);
record_current_version(VERSION_TXT_PATH);
}
}
}

View file

@ -4,23 +4,25 @@
#![feature(once_cell)]
#![feature(c_variadic)]
#![allow(
clippy::borrow_interior_mutable_const,
clippy::declare_interior_mutable_const,
clippy::not_unsafe_ptr_arg_deref,
clippy::missing_safety_doc,
clippy::wrong_self_convention,
clippy::option_map_unit_fn,
clippy::fn_null_check,
clippy::transmute_num_to_bytes
clippy::borrow_interior_mutable_const,
clippy::declare_interior_mutable_const,
clippy::not_unsafe_ptr_arg_deref,
clippy::missing_safety_doc,
clippy::wrong_self_convention,
clippy::option_map_unit_fn,
clippy::fn_null_check,
clippy::transmute_num_to_bytes
)]
use std::fs;
use std::path::PathBuf;
use skyline::libc::mkdir;
use skyline::nro::{self, NroInfo};
use training_mod_consts::LEGACY_TRAINING_MODPACK_ROOT;
use crate::common::*;
use crate::common::events::events_loop;
use crate::common::*;
use crate::consts::TRAINING_MODPACK_ROOT;
use crate::events::{Event, EVENT_QUEUE};
use crate::logging::*;
use crate::menu::quick_menu_loop;
@ -47,12 +49,6 @@ fn nro_main(nro: &NroInfo<'_>) {
}
}
macro_rules! c_str {
($l:tt) => {
[$l.as_bytes(), "\u{0}".as_bytes()].concat().as_ptr()
};
}
#[skyline::main(name = "training_modpack")]
pub fn main() {
std::panic::set_hook(Box::new(|info| {
@ -79,8 +75,16 @@ pub fn main() {
unsafe {
EVENT_QUEUE.push(Event::smash_open());
notification("Training Modpack".to_string(), "Welcome!".to_string(), 60);
notification("Open Menu".to_string(), "Special + Uptaunt".to_string(), 120);
notification("Save State".to_string(), "Grab + Downtaunt".to_string(), 120);
notification(
"Open Menu".to_string(),
"Special + Uptaunt".to_string(),
120,
);
notification(
"Save State".to_string(),
"Grab + Downtaunt".to_string(),
120,
);
notification("Load State".to_string(), "Grab + Uptaunt".to_string(), 120);
}
@ -89,14 +93,21 @@ pub fn main() {
training::training_mods();
nro::add_hook(nro_main).unwrap();
unsafe {
mkdir(c_str!("sd:/TrainingModpack/"), 777);
}
fs::create_dir_all(TRAINING_MODPACK_ROOT)
.expect("Could not create Training Modpack root folder!");
let ovl_path = "sd:/switch/.overlays/ovlTrainingModpack.ovl";
if fs::metadata(ovl_path).is_ok() {
warn!("Removing ovlTrainingModpack.ovl...");
fs::remove_file(ovl_path).unwrap_or_else(|_| panic!("Could not remove {}", ovl_path))
// Migrate legacy if exists
if fs::metadata(LEGACY_TRAINING_MODPACK_ROOT).is_ok() {
for entry in fs::read_dir(LEGACY_TRAINING_MODPACK_ROOT).unwrap() {
let entry = entry.unwrap();
let src_path = &entry.path();
let dest_path = &PathBuf::from(TRAINING_MODPACK_ROOT).join(entry.file_name());
fs::rename(src_path, dest_path).unwrap_or_else(|e| {
error!("Could not move file from {src_path:#?} to {dest_path:#?} with error {e}")
});
}
fs::remove_dir_all(LEGACY_TRAINING_MODPACK_ROOT)
.expect("Could not delete legacy Training Modpack folder!");
}
info!("Performing version check...");

View file

@ -17,6 +17,7 @@ use crate::common::consts::get_random_int;
use crate::common::consts::FighterId;
use crate::common::consts::OnOff;
use crate::common::consts::SaveStateMirroring;
use crate::common::consts::SAVE_STATES_TOML_PATH;
use crate::common::is_dead;
use crate::common::MENU;
use crate::is_operation_cpu;
@ -114,14 +115,13 @@ pub fn load_from_file() -> SaveStateSlots {
cpu: [default_save_state!(); NUM_SAVE_STATE_SLOTS],
};
let save_states_path = "sd:/TrainingModpack/save_states.toml";
info!("Checking for previous save state settings in save_states.toml...");
if std::fs::metadata(save_states_path).is_err() {
info!("Checking for previous save state settings in {SAVE_STATES_TOML_PATH}...");
if std::fs::metadata(SAVE_STATES_TOML_PATH).is_err() {
return defaults;
}
info!("Previous save state settings found. Loading...");
if let Ok(data) = std::fs::read_to_string(save_states_path) {
if let Ok(data) = std::fs::read_to_string(SAVE_STATES_TOML_PATH) {
let input_slots = toml::from_str::<SaveStateSlots>(&data);
if let Ok(input_slots) = input_slots {
return input_slots;
@ -134,7 +134,7 @@ pub fn load_from_file() -> SaveStateSlots {
pub unsafe fn save_to_file() {
let save_states_str = toml::to_string_pretty(&*SAVE_STATE_SLOTS.data_ptr())
.expect("Error serializing save state information");
std::fs::write("sd:/TrainingModpack/save_states.toml", save_states_str)
std::fs::write(SAVE_STATES_TOML_PATH, save_states_str)
.expect("Could not write save state information to file");
}
@ -596,6 +596,12 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
MIRROR_STATE = 1.0;
save_state_player().state = Save;
save_state_cpu().state = Save;
notifications::clear_notifications("Save State");
notifications::notification(
"Save State".to_string(),
format!("Saved Slot {SAVE_STATE_SLOT}"),
120,
);
}
if save_state.state == Save && !fighter_is_nana {

View file

@ -1,8 +1,10 @@
use sarc::SarcFile;
use skyline::nn::ui2d::*;
use training_mod_consts::{MENU, OnOff};
use training_mod_consts::{OnOff, MENU};
use crate::common::{is_ready_go, is_training_mode};
#[cfg(feature = "layout_arc_from_file")]
use crate::consts::LAYOUT_ARC_PATH;
mod damage;
mod display;
@ -37,8 +39,7 @@ pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64)
static mut LAYOUT_ARC: &mut [u8; 600000] = &mut [0u8; 600000];
/// We are editing the info_training/layout.arc and replacing the original file with our
/// modified version from `sd://TrainingModpack/layout.arc` or, in the case of Ryujinx for the cool
/// kids `${RYUJINX_DIR}/sdcard/TrainingModpack/layout.arc`
/// modified version from `LAYOUT_ARC_PATH`
///
/// When we edit the layout we are doing two things.
///
@ -72,9 +73,7 @@ static mut LAYOUT_ARC: &mut [u8; 600000] = &mut [0u8; 600000];
/// 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
) {
unsafe fn handle_layout_arc_malloc(ctx: &mut skyline::hooks::InlineCtx) {
if !is_training_mode() {
return;
}
@ -82,9 +81,11 @@ unsafe fn handle_layout_arc_malloc(
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 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")
});
@ -95,8 +96,9 @@ unsafe fn handle_layout_arc_malloc(
let inject_arc;
let inject_arc_size: u64;
#[cfg(feature = "layout_arc_from_file")] {
let inject_arc_from_file = std::fs::read("sd:/TrainingModpack/layout.arc").unwrap();
#[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
@ -107,7 +109,8 @@ unsafe fn handle_layout_arc_malloc(
inject_arc = LAYOUT_ARC.as_ptr();
}
#[cfg(not(feature = "layout_arc_from_file"))] {
#[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();
@ -125,8 +128,5 @@ unsafe fn handle_layout_arc_malloc(
}
pub fn init() {
skyline::install_hooks!(
handle_draw,
handle_layout_arc_malloc
);
skyline::install_hooks!(handle_draw, handle_layout_arc_malloc);
}

View file

@ -0,0 +1,14 @@
pub const ULTIMATE_ROOT: &str = "sd:/ultimate/";
pub const LEGACY_TRAINING_MODPACK_ROOT: &str = "sd:/TrainingModpack";
pub const TRAINING_MODPACK_ROOT: &str = "sd:/ultimate/TrainingModpack";
pub const TRAINING_MODPACK_TOML_PATH: &str = "sd:/ultimate/TrainingModpack/training_modpack.toml";
pub const SAVE_STATES_TOML_PATH: &str = "sd:/ultimate/TrainingModpack/save_states.toml";
pub const DEV_TOML_PATH: &str = "sd:/ultimate/TrainingModpack/dev.toml";
pub const VERSION_TXT_PATH: &str = "sd:/ultimate/TrainingModpack/version.txt";
pub const LAYOUT_ARC_PATH: &str = "sd:/ultimate/TrainingModpack/layout.arc";
pub const MENU_OPTIONS_PATH: &str = "sd:/ultimate/TrainingModpack/training_modpack_menu.conf";
pub const LEGACY_MENU_OPTIONS_PATH: &str =
"sd:/ultimate/TrainingModpack/training_modpack_menu.json";
pub const MENU_DEFAULT_OPTIONS_PATH: &str =
"sd:/ultimate/TrainingModpack/training_modpack_menu_defaults.conf";

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff