mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-28 04:44:06 +00:00
Move files to sd:/ultimate/TrainingModpack (#480)
* Initial * Move filepaths * Small fix * Notification on save state save
This commit is contained in:
parent
8ac2a3e8b1
commit
e981a0bfd0
11 changed files with 1272 additions and 1220 deletions
|
@ -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/libnro_hook.nro`
|
||||||
`SD:/atmosphere/contents/01006A800016E000/romfs/skyline/plugins/libparam_hook.nro`
|
`SD:/atmosphere/contents/01006A800016E000/romfs/skyline/plugins/libparam_hook.nro`
|
||||||
`SD:/atmosphere/contents/01006A800016E000/romfs/skyline/plugins/libtraining_modpack.nro`
|
`SD:/atmosphere/contents/01006A800016E000/romfs/skyline/plugins/libtraining_modpack.nro`
|
||||||
`SD:/TrainingModpack/`
|
`SD:/ultimate/TrainingModpack/`
|
||||||
17. **Can I donate to the Training Modpack?**
|
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!
|
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?**
|
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:
|
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?**
|
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.
|
Good LAN connections can be simulated with an input delay of 3-5 frames. Poorer Wifi connections can be up to 6-8 frames.
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
|
use crate::consts::TRAINING_MODPACK_TOML_PATH;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use log::info;
|
use log::info;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -78,13 +80,13 @@ pub struct TopLevelBtnComboConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_from_file() {
|
pub fn load_from_file() {
|
||||||
let combo_path = "sd:/TrainingModpack/training_modpack.toml";
|
let combo_path = TRAINING_MODPACK_TOML_PATH;
|
||||||
info!("Checking for previous button combo settings in training_modpack.toml...");
|
info!("Checking for previous button combo settings in {TRAINING_MODPACK_TOML_PATH}...");
|
||||||
let mut valid_button_config = false;
|
let mut valid_button_config = false;
|
||||||
if fs::metadata(combo_path).is_ok() {
|
if fs::metadata(combo_path).is_ok() {
|
||||||
info!("Previous button combo settings found. Loading...");
|
info!("Previous button combo settings found. Loading...");
|
||||||
let combo_conf =
|
let combo_conf = fs::read_to_string(combo_path)
|
||||||
fs::read_to_string(combo_path).unwrap_or_else(|_| panic!("Could not read {}", combo_path));
|
.unwrap_or_else(|_| panic!("Could not read {}", combo_path));
|
||||||
let conf: Result<TopLevelBtnComboConfig, toml::de::Error> = toml::from_str(&combo_conf);
|
let conf: Result<TopLevelBtnComboConfig, toml::de::Error> = toml::from_str(&combo_conf);
|
||||||
if let Ok(conf) = conf {
|
if let Ok(conf) = conf {
|
||||||
if validate_config(conf) {
|
if validate_config(conf) {
|
||||||
|
@ -96,13 +98,11 @@ pub fn load_from_file() {
|
||||||
|
|
||||||
if !valid_button_config {
|
if !valid_button_config {
|
||||||
info!("No previous button combo file found. Creating...");
|
info!("No previous button combo file found. Creating...");
|
||||||
fs::write(combo_path, DEFAULT_BTN_CONFIG)
|
fs::write(combo_path, DEFAULT_BTN_CONFIG).expect("Failed to write button config conf file");
|
||||||
.expect("Failed to write button config conf file");
|
|
||||||
save_all_btn_config_from_defaults();
|
save_all_btn_config_from_defaults();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn save_all_btn_config_from_defaults() {
|
fn save_all_btn_config_from_defaults() {
|
||||||
let conf = TopLevelBtnComboConfig {
|
let conf = TopLevelBtnComboConfig {
|
||||||
button_config: BtnComboConfig {
|
button_config: BtnComboConfig {
|
||||||
|
@ -146,8 +146,13 @@ fn save_all_btn_config_from_toml(data: &str) {
|
||||||
|
|
||||||
fn validate_config(conf: TopLevelBtnComboConfig) -> bool {
|
fn validate_config(conf: TopLevelBtnComboConfig) -> bool {
|
||||||
let conf = conf.button_config;
|
let conf = conf.button_config;
|
||||||
let configs = [conf.open_menu, conf.save_state, conf.load_state,
|
let configs = [
|
||||||
conf.previous_save_state_slot, conf.next_save_state_slot];
|
conf.open_menu,
|
||||||
|
conf.save_state,
|
||||||
|
conf.load_state,
|
||||||
|
conf.previous_save_state_slot,
|
||||||
|
conf.next_save_state_slot,
|
||||||
|
];
|
||||||
let bad_keys = configs
|
let bad_keys = configs
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|btn_list| {
|
.flat_map(|btn_list| {
|
||||||
|
@ -164,8 +169,9 @@ fn validate_config(conf: TopLevelBtnComboConfig) -> bool {
|
||||||
0x71,
|
0x71,
|
||||||
"Training Modpack custom button\nconfiguration is invalid!\0",
|
"Training Modpack custom button\nconfiguration is invalid!\0",
|
||||||
&format!(
|
&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",
|
{:?}\n\nPossible Keys: {:#?}\0",
|
||||||
|
TRAINING_MODPACK_TOML_PATH,
|
||||||
&bad_keys,
|
&bad_keys,
|
||||||
BUTTON_MAPPING.keys()
|
BUTTON_MAPPING.keys()
|
||||||
),
|
),
|
||||||
|
@ -207,13 +213,14 @@ fn combo_passes(
|
||||||
) -> bool {
|
) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
let (hold, press) = get_combo_keys(combo);
|
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())
|
.map(|hold| *BUTTON_MAPPING.get(&*hold.to_uppercase()).unwrap())
|
||||||
.all(|hold| ControlModule::check_button_on(module_accessor, hold))
|
.all(|hold| ControlModule::check_button_on(module_accessor, hold))
|
||||||
&& press
|
&& press
|
||||||
.iter()
|
.iter()
|
||||||
.map(|press| *BUTTON_MAPPING.get(&*press.to_uppercase()).unwrap())
|
.map(|press| *BUTTON_MAPPING.get(&*press.to_uppercase()).unwrap())
|
||||||
.all(|press| ControlModule::check_button_trigger(module_accessor, press));
|
.all(|press| ControlModule::check_button_trigger(module_accessor, press));
|
||||||
|
|
||||||
this_combo_passes
|
this_combo_passes
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,13 @@ use serde::Deserialize;
|
||||||
use skyline::nn::hid::NpadGcState;
|
use skyline::nn::hid::NpadGcState;
|
||||||
use toml;
|
use toml;
|
||||||
|
|
||||||
|
use crate::consts::DEV_TOML_PATH;
|
||||||
use crate::logging::info;
|
use crate::logging::info;
|
||||||
|
|
||||||
/// Hot-reloadable configs for quicker development
|
/// Hot-reloadable configs for quicker development
|
||||||
///
|
///
|
||||||
/// In game, press L+R+A at any point to reread these configs from
|
/// 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:
|
/// Example usage:
|
||||||
///
|
///
|
||||||
|
@ -42,7 +43,7 @@ lazy_static! {
|
||||||
|
|
||||||
impl DevConfig {
|
impl DevConfig {
|
||||||
fn load_from_toml() -> 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() {
|
if fs::metadata(dev_path).is_ok() {
|
||||||
info!("Loading dev.toml configs...");
|
info!("Loading dev.toml configs...");
|
||||||
let dev_config_str = fs::read_to_string(dev_path).unwrap_or_else(|_| panic!("Could not read {}", dev_path));
|
let dev_config_str = fs::read_to_string(dev_path).unwrap_or_else(|_| panic!("Could not read {}", dev_path));
|
||||||
|
|
|
@ -8,6 +8,7 @@ use training_mod_consts::MenuJsonStruct;
|
||||||
use training_mod_tui::AppPage;
|
use training_mod_tui::AppPage;
|
||||||
|
|
||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
|
use crate::consts::MENU_OPTIONS_PATH;
|
||||||
use crate::events::{Event, EVENT_QUEUE};
|
use crate::events::{Event, EVENT_QUEUE};
|
||||||
use crate::logging::*;
|
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)
|
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() {
|
pub fn load_from_file() {
|
||||||
let menu_conf_path = "sd:/TrainingModpack/training_modpack_menu.json";
|
info!("Checking for previous menu in {MENU_OPTIONS_PATH}...");
|
||||||
info!("Checking for previous menu in training_modpack_menu.json...");
|
if fs::metadata(MENU_OPTIONS_PATH).is_ok() {
|
||||||
if fs::metadata(menu_conf_path).is_ok() {
|
let menu_conf = fs::read_to_string(MENU_OPTIONS_PATH)
|
||||||
let menu_conf = fs::read_to_string(menu_conf_path)
|
.unwrap_or_else(|_| panic!("Could not remove {}", MENU_OPTIONS_PATH));
|
||||||
.unwrap_or_else(|_| panic!("Could not remove {}", menu_conf_path));
|
|
||||||
if let Ok(menu_conf_json) = serde_json::from_str::<MenuJsonStruct>(&menu_conf) {
|
if let Ok(menu_conf_json) = serde_json::from_str::<MenuJsonStruct>(&menu_conf) {
|
||||||
unsafe {
|
unsafe {
|
||||||
MENU = menu_conf_json.menu;
|
MENU = menu_conf_json.menu;
|
||||||
|
@ -38,10 +36,10 @@ pub fn load_from_file() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warn!("Previous menu found but is invalid. Deleting...");
|
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!(
|
panic!(
|
||||||
"{} has invalid schema but could not be deleted!",
|
"{} 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;
|
MENU = message_json.menu;
|
||||||
DEFAULTS_MENU = message_json.defaults_menu;
|
DEFAULTS_MENU = message_json.defaults_menu;
|
||||||
fs::write(
|
fs::write(
|
||||||
MENU_CONF_PATH,
|
MENU_OPTIONS_PATH,
|
||||||
serde_json::to_string_pretty(&message_json).unwrap(),
|
serde_json::to_string_pretty(&message_json).unwrap(),
|
||||||
)
|
)
|
||||||
.expect("Failed to write menu settings file");
|
.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;
|
BUTTON_PRESSES.r.is_pressed = true;
|
||||||
}
|
}
|
||||||
// Special case for frame-by-frame
|
// 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;
|
BUTTON_PRESSES.zl.is_pressed = true;
|
||||||
}
|
}
|
||||||
if (*state).Buttons & (1 << 9) > 0 {
|
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 {
|
if (*state).Buttons & ((1 << 15) | (1 << 19)) > 0 {
|
||||||
BUTTON_PRESSES.down.is_pressed = true;
|
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;
|
BUTTON_PRESSES.up.is_pressed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,12 @@ use std::fs;
|
||||||
|
|
||||||
use skyline_web::DialogOk;
|
use skyline_web::DialogOk;
|
||||||
|
|
||||||
|
use crate::consts::{
|
||||||
|
LEGACY_MENU_OPTIONS_PATH, MENU_DEFAULT_OPTIONS_PATH, MENU_OPTIONS_PATH, VERSION_TXT_PATH,
|
||||||
|
};
|
||||||
use crate::logging::*;
|
use crate::logging::*;
|
||||||
|
|
||||||
pub const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
const VERSION_FILE_PATH: &str = "sd:/TrainingModpack/version.txt";
|
|
||||||
|
|
||||||
enum VersionCheck {
|
enum VersionCheck {
|
||||||
Current,
|
Current,
|
||||||
|
@ -33,7 +35,7 @@ fn record_current_version(fpath: &str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn version_check() {
|
pub fn version_check() {
|
||||||
match is_current_version(VERSION_FILE_PATH) {
|
match is_current_version(VERSION_TXT_PATH) {
|
||||||
VersionCheck::Current => {
|
VersionCheck::Current => {
|
||||||
// Version is current, no need to take any action
|
// 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)
|
// 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"));
|
MENU_OPTIONS_PATH,
|
||||||
fs::remove_file("sd:/TrainingModpack/training_modpack_menu.json")
|
MENU_DEFAULT_OPTIONS_PATH,
|
||||||
.unwrap_or_else(|_| error!("Couldn't remove training_modpack_menu.json"));
|
LEGACY_MENU_OPTIONS_PATH,
|
||||||
fs::remove_file("sd:/TrainingModpack/training_modpack_menu_defaults.conf")
|
]
|
||||||
.unwrap_or_else(|_| error!("Couldn't remove training_modpack_menu_defaults.conf"));
|
.iter()
|
||||||
record_current_version(VERSION_FILE_PATH);
|
.for_each(|path| {
|
||||||
|
fs::remove_file(path).unwrap_or_else(|_| error!("Couldn't remove {path}"))
|
||||||
|
});
|
||||||
|
record_current_version(VERSION_TXT_PATH);
|
||||||
}
|
}
|
||||||
VersionCheck::NoFile => {
|
VersionCheck::NoFile => {
|
||||||
// Display dialog box on fresh installation
|
// 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."
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
61
src/lib.rs
61
src/lib.rs
|
@ -4,23 +4,25 @@
|
||||||
#![feature(once_cell)]
|
#![feature(once_cell)]
|
||||||
#![feature(c_variadic)]
|
#![feature(c_variadic)]
|
||||||
#![allow(
|
#![allow(
|
||||||
clippy::borrow_interior_mutable_const,
|
clippy::borrow_interior_mutable_const,
|
||||||
clippy::declare_interior_mutable_const,
|
clippy::declare_interior_mutable_const,
|
||||||
clippy::not_unsafe_ptr_arg_deref,
|
clippy::not_unsafe_ptr_arg_deref,
|
||||||
clippy::missing_safety_doc,
|
clippy::missing_safety_doc,
|
||||||
clippy::wrong_self_convention,
|
clippy::wrong_self_convention,
|
||||||
clippy::option_map_unit_fn,
|
clippy::option_map_unit_fn,
|
||||||
clippy::fn_null_check,
|
clippy::fn_null_check,
|
||||||
clippy::transmute_num_to_bytes
|
clippy::transmute_num_to_bytes
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use skyline::libc::mkdir;
|
|
||||||
use skyline::nro::{self, NroInfo};
|
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::events::events_loop;
|
||||||
|
use crate::common::*;
|
||||||
|
use crate::consts::TRAINING_MODPACK_ROOT;
|
||||||
use crate::events::{Event, EVENT_QUEUE};
|
use crate::events::{Event, EVENT_QUEUE};
|
||||||
use crate::logging::*;
|
use crate::logging::*;
|
||||||
use crate::menu::quick_menu_loop;
|
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")]
|
#[skyline::main(name = "training_modpack")]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
std::panic::set_hook(Box::new(|info| {
|
std::panic::set_hook(Box::new(|info| {
|
||||||
|
@ -79,8 +75,16 @@ pub fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
EVENT_QUEUE.push(Event::smash_open());
|
EVENT_QUEUE.push(Event::smash_open());
|
||||||
notification("Training Modpack".to_string(), "Welcome!".to_string(), 60);
|
notification("Training Modpack".to_string(), "Welcome!".to_string(), 60);
|
||||||
notification("Open Menu".to_string(), "Special + Uptaunt".to_string(), 120);
|
notification(
|
||||||
notification("Save State".to_string(), "Grab + Downtaunt".to_string(), 120);
|
"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);
|
notification("Load State".to_string(), "Grab + Uptaunt".to_string(), 120);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,14 +93,21 @@ pub fn main() {
|
||||||
training::training_mods();
|
training::training_mods();
|
||||||
nro::add_hook(nro_main).unwrap();
|
nro::add_hook(nro_main).unwrap();
|
||||||
|
|
||||||
unsafe {
|
fs::create_dir_all(TRAINING_MODPACK_ROOT)
|
||||||
mkdir(c_str!("sd:/TrainingModpack/"), 777);
|
.expect("Could not create Training Modpack root folder!");
|
||||||
}
|
|
||||||
|
|
||||||
let ovl_path = "sd:/switch/.overlays/ovlTrainingModpack.ovl";
|
// Migrate legacy if exists
|
||||||
if fs::metadata(ovl_path).is_ok() {
|
if fs::metadata(LEGACY_TRAINING_MODPACK_ROOT).is_ok() {
|
||||||
warn!("Removing ovlTrainingModpack.ovl...");
|
for entry in fs::read_dir(LEGACY_TRAINING_MODPACK_ROOT).unwrap() {
|
||||||
fs::remove_file(ovl_path).unwrap_or_else(|_| panic!("Could not remove {}", ovl_path))
|
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...");
|
info!("Performing version check...");
|
||||||
|
|
|
@ -17,6 +17,7 @@ use crate::common::consts::get_random_int;
|
||||||
use crate::common::consts::FighterId;
|
use crate::common::consts::FighterId;
|
||||||
use crate::common::consts::OnOff;
|
use crate::common::consts::OnOff;
|
||||||
use crate::common::consts::SaveStateMirroring;
|
use crate::common::consts::SaveStateMirroring;
|
||||||
|
use crate::common::consts::SAVE_STATES_TOML_PATH;
|
||||||
use crate::common::is_dead;
|
use crate::common::is_dead;
|
||||||
use crate::common::MENU;
|
use crate::common::MENU;
|
||||||
use crate::is_operation_cpu;
|
use crate::is_operation_cpu;
|
||||||
|
@ -114,14 +115,13 @@ pub fn load_from_file() -> SaveStateSlots {
|
||||||
cpu: [default_save_state!(); NUM_SAVE_STATE_SLOTS],
|
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_PATH}...");
|
||||||
info!("Checking for previous save state settings in save_states.toml...");
|
if std::fs::metadata(SAVE_STATES_TOML_PATH).is_err() {
|
||||||
if std::fs::metadata(save_states_path).is_err() {
|
|
||||||
return defaults;
|
return defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Previous save state settings found. Loading...");
|
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);
|
let input_slots = toml::from_str::<SaveStateSlots>(&data);
|
||||||
if let Ok(input_slots) = input_slots {
|
if let Ok(input_slots) = input_slots {
|
||||||
return input_slots;
|
return input_slots;
|
||||||
|
@ -134,7 +134,7 @@ pub fn load_from_file() -> SaveStateSlots {
|
||||||
pub unsafe fn save_to_file() {
|
pub unsafe fn save_to_file() {
|
||||||
let save_states_str = toml::to_string_pretty(&*SAVE_STATE_SLOTS.data_ptr())
|
let save_states_str = toml::to_string_pretty(&*SAVE_STATE_SLOTS.data_ptr())
|
||||||
.expect("Error serializing save state information");
|
.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");
|
.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;
|
MIRROR_STATE = 1.0;
|
||||||
save_state_player().state = Save;
|
save_state_player().state = Save;
|
||||||
save_state_cpu().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 {
|
if save_state.state == Save && !fighter_is_nana {
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use sarc::SarcFile;
|
use sarc::SarcFile;
|
||||||
use skyline::nn::ui2d::*;
|
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};
|
use crate::common::{is_ready_go, is_training_mode};
|
||||||
|
#[cfg(feature = "layout_arc_from_file")]
|
||||||
|
use crate::consts::LAYOUT_ARC_PATH;
|
||||||
|
|
||||||
mod damage;
|
mod damage;
|
||||||
mod display;
|
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];
|
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
|
/// 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
|
/// modified version from `LAYOUT_ARC_PATH`
|
||||||
/// kids `${RYUJINX_DIR}/sdcard/TrainingModpack/layout.arc`
|
|
||||||
///
|
///
|
||||||
/// When we edit the layout we are doing two things.
|
/// 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);
|
/// label_material.set_black_res_color(LABEL_BLACK_SELECTED_COLOR);
|
||||||
/// ```
|
/// ```
|
||||||
#[skyline::hook(offset = 0x37730d4, inline)]
|
#[skyline::hook(offset = 0x37730d4, inline)]
|
||||||
unsafe fn handle_layout_arc_malloc(
|
unsafe fn handle_layout_arc_malloc(ctx: &mut skyline::hooks::InlineCtx) {
|
||||||
ctx: &mut skyline::hooks::InlineCtx
|
|
||||||
) {
|
|
||||||
if !is_training_mode() {
|
if !is_training_mode() {
|
||||||
return;
|
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_file = *ctx.registers[21].x.as_ref() as *const u8;
|
||||||
let decompressed_size = *ctx.registers[1].x.as_ref() as usize;
|
let decompressed_size = *ctx.registers[1].x.as_ref() as usize;
|
||||||
|
|
||||||
let layout_arc = SarcFile::read(
|
let layout_arc = SarcFile::read(std::slice::from_raw_parts(
|
||||||
std::slice::from_raw_parts(decompressed_file, decompressed_size)
|
decompressed_file,
|
||||||
).unwrap();
|
decompressed_size,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
let training_layout = layout_arc.files.iter().find(|f| {
|
let training_layout = layout_arc.files.iter().find(|f| {
|
||||||
f.name.is_some() && f.name.as_ref().unwrap() == &String::from("blyt/info_training.bflyt")
|
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;
|
||||||
let inject_arc_size: u64;
|
let inject_arc_size: u64;
|
||||||
|
|
||||||
#[cfg(feature = "layout_arc_from_file")] {
|
#[cfg(feature = "layout_arc_from_file")]
|
||||||
let inject_arc_from_file = std::fs::read("sd:/TrainingModpack/layout.arc").unwrap();
|
{
|
||||||
|
let inject_arc_from_file = std::fs::read(LAYOUT_ARC_PATH).unwrap();
|
||||||
inject_arc_size = inject_arc_from_file.len() as u64;
|
inject_arc_size = inject_arc_from_file.len() as u64;
|
||||||
|
|
||||||
// Copy read file to global
|
// Copy read file to global
|
||||||
|
@ -107,7 +109,8 @@ unsafe fn handle_layout_arc_malloc(
|
||||||
inject_arc = LAYOUT_ARC.as_ptr();
|
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");
|
include_flate::flate!(static INJECT_ARC_FROM_FILE: [u8] from "src/static/layout.arc");
|
||||||
|
|
||||||
inject_arc = INJECT_ARC_FROM_FILE.as_ptr();
|
inject_arc = INJECT_ARC_FROM_FILE.as_ptr();
|
||||||
|
@ -125,8 +128,5 @@ unsafe fn handle_layout_arc_malloc(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
skyline::install_hooks!(
|
skyline::install_hooks!(handle_draw, handle_layout_arc_malloc);
|
||||||
handle_draw,
|
|
||||||
handle_layout_arc_malloc
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
14
training_mod_consts/src/files.rs
Normal file
14
training_mod_consts/src/files.rs
Normal 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
1108
training_mod_consts/src/options.rs
Normal file
1108
training_mod_consts/src/options.rs
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue