#![feature(proc_macro_hygiene)] #![feature(with_options)] #![feature(const_mut_refs)] #![feature(exclusive_range_pattern)] #![feature(once_cell)] #![allow( clippy::borrow_interior_mutable_const, clippy::not_unsafe_ptr_arg_deref, clippy::missing_safety_doc, clippy::wrong_self_convention, clippy::option_map_unit_fn, clippy::float_cmp )] pub mod common; mod hazard_manager; mod hitbox_visualizer; mod training; #[cfg(test)] mod test; use crate::common::consts::get_menu_from_url; use crate::common::*; use crate::events::{Event, EVENT_QUEUE}; use skyline::libc::{c_char, mkdir}; use skyline::nro::{self, NroInfo}; use std::fs; use crate::training::frame_counter; use owo_colors::OwoColorize; use training_mod_consts::OnOff; use training_mod_tui::Color; fn nro_main(nro: &NroInfo<'_>) { if nro.module.isLoaded { return; } if nro.name == "common" { skyline::install_hooks!( training::shield::handle_sub_guard_cont, training::directional_influence::handle_correct_damage_vector_common, training::tech::handle_change_status, ); } } extern "C" { #[link_name = "render_text_to_screen"] pub fn render_text_to_screen_cstr(str: *const c_char); #[link_name = "set_should_display_text_to_screen"] pub fn set_should_display_text_to_screen(toggle: bool); } macro_rules! c_str { ($l:tt) => { [$l.as_bytes(), "\u{0}".as_bytes()].concat().as_ptr(); }; } pub fn render_text_to_screen(s: &str) { unsafe { render_text_to_screen_cstr(c_str!(s)); } } #[skyline::main(name = "training_modpack")] pub fn main() { macro_rules! log { ($($arg:tt)*) => { println!("{}{}", "[Training Modpack] ".green(), format!($($arg)*)); }; } log!("Initialized."); unsafe { EVENT_QUEUE.push(Event::smash_open()); } hitbox_visualizer::hitbox_visualization(); hazard_manager::hazard_manager(); training::training_mods(); nro::add_hook(nro_main).unwrap(); unsafe { mkdir(c_str!("sd:/TrainingModpack/"), 777); } let ovl_path = "sd:/switch/.overlays/ovlTrainingModpack.ovl"; if fs::metadata(ovl_path).is_ok() { log!("Removing ovlTrainingModpack.ovl..."); fs::remove_file(ovl_path).unwrap(); } log!("Performing version check..."); release::version_check(); let menu_conf_path = "sd:/TrainingModpack/training_modpack_menu.conf"; log!("Checking for previous menu in training_modpack_menu.conf..."); if fs::metadata(menu_conf_path).is_ok() { let menu_conf = fs::read(menu_conf_path).unwrap(); if menu_conf.starts_with(b"http://localhost") { log!("Previous menu found, loading from training_modpack_menu.conf"); unsafe { MENU = get_menu_from_url(MENU, std::str::from_utf8(&menu_conf).unwrap(), false); DEFAULTS_MENU = get_menu_from_url( DEFAULTS_MENU, std::str::from_utf8(&menu_conf).unwrap(), true, ); } } else { log!("Previous menu found but is invalid."); } } else { log!("No previous menu file found."); } if is_emulator() { unsafe { DEFAULTS_MENU.quick_menu = OnOff::On; MENU.quick_menu = OnOff::On; } } std::thread::spawn(|| loop { std::thread::sleep(std::time::Duration::from_secs(10)); unsafe { while let Some(event) = EVENT_QUEUE.pop() { let host = "https://my-project-1511972643240-default-rtdb.firebaseio.com"; let path = format!( "/event/{}/device/{}/{}.json", event.event_name, event.device_id, event.event_time ); let url = format!("{}{}", host, path); minreq::post(url).with_json(&event).unwrap().send().ok(); } } }); std::thread::spawn(|| { std::thread::sleep(std::time::Duration::from_secs(10)); let menu; unsafe { menu = crate::common::consts::get_menu(); } let mut app = training_mod_tui::App::new(menu); let backend = training_mod_tui::TestBackend::new(75, 15); let mut terminal = training_mod_tui::Terminal::new(backend).unwrap(); unsafe { let mut has_slept_millis = 0; let render_frames = 5; let mut url = String::new(); let button_presses = &mut common::menu::BUTTON_PRESSES; let mut received_input = true; loop { button_presses.a.read_press().then(|| { app.on_a(); received_input = true; }); let b_press = &mut button_presses.b; let b_prev_press = b_press.prev_frame_is_pressed; b_press.read_press().then(|| { received_input = true; if !app.outer_list { app.on_b() } else if frame_counter::get_frame_count(menu::QUICK_MENU_FRAME_COUNTER_INDEX) == 0 { // Leave menu. menu::QUICK_MENU_ACTIVE = false; crate::menu::set_menu_from_url(url.as_str()); println!("URL: {}", url.as_str()); } }); button_presses.zl.read_press().then(|| { app.on_l(); received_input = true; }); button_presses.zr.read_press().then(|| { app.on_r(); received_input = true; }); button_presses.left.read_press().then(|| { app.on_left(); received_input = true; }); button_presses.right.read_press().then(|| { app.on_right(); received_input = true; }); button_presses.up.read_press().then(|| { app.on_up(); received_input = true; }); button_presses.down.read_press().then(|| { app.on_down(); received_input = true; }); std::thread::sleep(std::time::Duration::from_millis(16)); has_slept_millis += 16; if has_slept_millis < 16 * render_frames { continue; } has_slept_millis = 16; if !menu::QUICK_MENU_ACTIVE { app = training_mod_tui::App::new(crate::common::consts::get_menu()); set_should_display_text_to_screen(false); continue; } if !received_input { continue; } let mut view = String::new(); let frame_res = terminal .draw(|f| url = training_mod_tui::ui(f, &mut app)) .unwrap(); use std::fmt::Write; for (i, cell) in frame_res.buffer.content().iter().enumerate() { match cell.fg { Color::Black => write!(&mut view, "{}", &cell.symbol.black()), Color::Blue => write!(&mut view, "{}", &cell.symbol.blue()), Color::LightBlue => write!(&mut view, "{}", &cell.symbol.bright_blue()), Color::Cyan => write!(&mut view, "{}", &cell.symbol.cyan()), Color::LightCyan => write!(&mut view, "{}", &cell.symbol.cyan()), Color::Red => write!(&mut view, "{}", &cell.symbol.red()), Color::LightRed => write!(&mut view, "{}", &cell.symbol.bright_red()), Color::LightGreen => write!(&mut view, "{}", &cell.symbol.bright_green()), Color::Green => write!(&mut view, "{}", &cell.symbol.green()), Color::Yellow => write!(&mut view, "{}", &cell.symbol.yellow()), Color::LightYellow => write!(&mut view, "{}", &cell.symbol.bright_yellow()), Color::Magenta => write!(&mut view, "{}", &cell.symbol.magenta()), Color::LightMagenta => { write!(&mut view, "{}", &cell.symbol.bright_magenta()) } _ => write!(&mut view, "{}", &cell.symbol), } .unwrap(); if i % frame_res.area.width as usize == frame_res.area.width as usize - 1 { writeln!(&mut view).unwrap(); } } writeln!(&mut view).unwrap(); render_text_to_screen(view.as_str()); received_input = false; } } }); }