1
0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2026-02-07 18:02:26 +00:00

Refactor to use Web Sessions (#384)

* Initial commit

* don't rewrite file each time

* Format Rust code using rustfmt

* Receive menu settings from web via message

* Adjust logic

* Stub changes for json messages

* Rust: receive menu as json

* Small JS changes for desktop

* Attempt to fix exit issues

* Fix filename issue

* JS: Export menu as json

* Use JSON for Rust -> JS message

* Update .conf file schema to json

* Tear down session when leaving training mode

* Remove URL behavior, rename WebAppletResponse -> MenuJsonStruct

* Update TUI to use JSON

Co-authored-by: jugeeya <jugeeya@live.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
asimon-1
2022-09-07 22:34:39 -04:00
committed by GitHub
parent 55ee4733e2
commit 36c6e8859a
8 changed files with 484 additions and 470 deletions

View File

@@ -1,17 +1,21 @@
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate bitflags_serde_shim;
#[macro_use]
extern crate num_derive;
use core::f64::consts::PI;
use std::collections::HashMap;
use ramhorns::Content;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
#[cfg(feature = "smash")]
use smash::lib::lua_const::*;
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
use serde::{Serialize, Deserialize};
use ramhorns::Content;
use std::collections::HashMap;
pub trait ToggleTrait {
fn to_toggle_strs() -> Vec<&'static str>;
@@ -73,17 +77,14 @@ macro_rules! extra_bitflag_impls {
all_options.iter().map(|i| i.bits() as usize).collect()
}
}
impl ToUrlParam for $e {
fn to_url_param(&self) -> String {
self.bits().to_string()
}
}
}
}
pub fn get_random_int(_max: i32) -> i32 {
#[cfg(feature = "smash")]
unsafe { smash::app::sv_math::rand(smash::hash40("fighter"), _max) }
unsafe {
smash::app::sv_math::rand(smash::hash40("fighter"), _max)
}
#[cfg(not(feature = "smash"))]
0
@@ -101,7 +102,6 @@ pub fn random_option<T>(arg: &[T]) -> &T {
// DI / Left stick
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct Direction : u32 {
const OUT = 0x1;
const UP_OUT = 0x2;
@@ -163,10 +163,10 @@ impl Direction {
}
extra_bitflag_impls! {Direction}
impl_serde_for_bitflags!(Direction);
// Ledge Option
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct LedgeOption : u32
{
const NEUTRAL = 0x1;
@@ -179,7 +179,8 @@ bitflags! {
impl LedgeOption {
pub fn into_status(self) -> Option<i32> {
#[cfg(feature = "smash")] {
#[cfg(feature = "smash")]
{
Some(match self {
LedgeOption::NEUTRAL => *FIGHTER_STATUS_KIND_CLIFF_CLIMB,
LedgeOption::ROLL => *FIGHTER_STATUS_KIND_CLIFF_ESCAPE,
@@ -207,10 +208,10 @@ impl LedgeOption {
}
extra_bitflag_impls! {LedgeOption}
impl_serde_for_bitflags!(LedgeOption);
// Tech options
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct TechFlags : u32 {
const NO_TECH = 0x1;
const ROLL_F = 0x2;
@@ -232,10 +233,10 @@ impl TechFlags {
}
extra_bitflag_impls! {TechFlags}
impl_serde_for_bitflags!(TechFlags);
// Missed Tech Options
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct MissTechFlags : u32 {
const GETUP = 0x1;
const ATTACK = 0x2;
@@ -257,10 +258,13 @@ impl MissTechFlags {
}
extra_bitflag_impls! {MissTechFlags}
impl_serde_for_bitflags!(MissTechFlags);
/// Shield States
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive, EnumIter, Serialize, Deserialize)]
#[derive(
Debug, Clone, Copy, PartialEq, FromPrimitive, EnumIter, Serialize_repr, Deserialize_repr,
)]
pub enum Shield {
None = 0x0,
Infinite = 0x1,
@@ -277,10 +281,6 @@ impl Shield {
Shield::Constant => "Constant",
})
}
pub fn to_url_param(&self) -> String {
(*self as i32).to_string()
}
}
impl ToggleTrait for Shield {
@@ -295,7 +295,9 @@ impl ToggleTrait for Shield {
// Save State Mirroring
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive, EnumIter, Serialize, Deserialize)]
#[derive(
Debug, Clone, Copy, PartialEq, FromPrimitive, EnumIter, Serialize_repr, Deserialize_repr,
)]
pub enum SaveStateMirroring {
None = 0x0,
Alternate = 0x1,
@@ -310,15 +312,13 @@ impl SaveStateMirroring {
SaveStateMirroring::Random => "Random",
})
}
fn to_url_param(&self) -> String {
(*self as i32).to_string()
}
}
impl ToggleTrait for SaveStateMirroring {
fn to_toggle_strs() -> Vec<&'static str> {
SaveStateMirroring::iter().map(|i| i.as_str().unwrap_or("")).collect()
SaveStateMirroring::iter()
.map(|i| i.as_str().unwrap_or(""))
.collect()
}
fn to_toggle_vals() -> Vec<usize> {
@@ -328,7 +328,6 @@ impl ToggleTrait for SaveStateMirroring {
// Defensive States
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct Defensive : u32 {
const SPOT_DODGE = 0x1;
const ROLL_F = 0x2;
@@ -352,9 +351,10 @@ impl Defensive {
}
extra_bitflag_impls! {Defensive}
impl_serde_for_bitflags!(Defensive);
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)]
pub enum OnOff {
Off = 0,
On = 1,
@@ -375,10 +375,6 @@ impl OnOff {
OnOff::On => "On",
})
}
pub fn to_url_param(&self) -> String {
(*self as i32).to_string()
}
}
impl ToggleTrait for OnOff {
@@ -391,7 +387,6 @@ impl ToggleTrait for OnOff {
}
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct Action : u32 {
const AIR_DODGE = 0x1;
const JUMP = 0x2;
@@ -424,7 +419,8 @@ bitflags! {
impl Action {
pub fn into_attack_air_kind(self) -> Option<i32> {
#[cfg(feature = "smash")] {
#[cfg(feature = "smash")]
{
Some(match self {
Action::NAIR => *FIGHTER_COMMAND_ATTACK_AIR_KIND_N,
Action::FAIR => *FIGHTER_COMMAND_ATTACK_AIR_KIND_F,
@@ -472,9 +468,9 @@ impl Action {
}
extra_bitflag_impls! {Action}
impl_serde_for_bitflags!(Action);
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct AttackAngle : u32 {
const NEUTRAL = 0x1;
const UP = 0x2;
@@ -494,9 +490,9 @@ impl AttackAngle {
}
extra_bitflag_impls! {AttackAngle}
impl_serde_for_bitflags!(AttackAngle);
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct Delay : u32 {
const D0 = 0x1;
const D1 = 0x2;
@@ -534,7 +530,6 @@ bitflags! {
// Throw Option
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct ThrowOption : u32
{
const NONE = 0x1;
@@ -547,7 +542,8 @@ bitflags! {
impl ThrowOption {
pub fn into_cmd(self) -> Option<i32> {
#[cfg(feature = "smash")] {
#[cfg(feature = "smash")]
{
Some(match self {
ThrowOption::NONE => 0,
ThrowOption::FORWARD => *FIGHTER_PAD_CMD_CAT2_FLAG_THROW_F,
@@ -575,10 +571,10 @@ impl ThrowOption {
}
extra_bitflag_impls! {ThrowOption}
impl_serde_for_bitflags!(ThrowOption);
// Buff Option
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct BuffOption : u32
{
const ACCELERATLE = 0x1;
@@ -595,7 +591,8 @@ bitflags! {
impl BuffOption {
pub fn into_int(self) -> Option<i32> {
#[cfg(feature = "smash")] {
#[cfg(feature = "smash")]
{
Some(match self {
BuffOption::ACCELERATLE => *FIGHTER_BRAVE_SPECIAL_LW_COMMAND11_SPEED_UP,
BuffOption::OOMPH => *FIGHTER_BRAVE_SPECIAL_LW_COMMAND12_ATTACK_UP,
@@ -631,6 +628,7 @@ impl BuffOption {
}
extra_bitflag_impls! {BuffOption}
impl_serde_for_bitflags!(BuffOption);
impl Delay {
pub fn as_str(self) -> Option<&'static str> {
@@ -676,9 +674,9 @@ impl Delay {
}
extra_bitflag_impls! {Delay}
impl_serde_for_bitflags!(Delay);
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct MedDelay : u32 {
const D0 = 0x1;
const D5 = 0x2;
@@ -758,9 +756,9 @@ impl MedDelay {
}
extra_bitflag_impls! {MedDelay}
impl_serde_for_bitflags!(MedDelay);
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct LongDelay : u32 {
const D0 = 0x1;
const D10 = 0x2;
@@ -840,9 +838,9 @@ impl LongDelay {
}
extra_bitflag_impls! {LongDelay}
impl_serde_for_bitflags!(LongDelay);
bitflags! {
#[derive(Serialize, Deserialize)]
pub struct BoolFlag : u32 {
const TRUE = 0x1;
const FALSE = 0x2;
@@ -850,6 +848,7 @@ bitflags! {
}
extra_bitflag_impls! {BoolFlag}
impl_serde_for_bitflags!(BoolFlag);
impl BoolFlag {
pub fn into_bool(self) -> bool {
@@ -865,7 +864,9 @@ impl BoolFlag {
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, EnumIter, Serialize, Deserialize)]
#[derive(
Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, EnumIter, Serialize_repr, Deserialize_repr,
)]
pub enum InputFrequency {
None = 0,
Normal = 1,
@@ -891,15 +892,13 @@ impl InputFrequency {
InputFrequency::High => "High",
})
}
pub fn to_url_param(&self) -> String {
(*self as u32).to_string()
}
}
impl ToggleTrait for InputFrequency {
fn to_toggle_strs() -> Vec<&'static str> {
InputFrequency::iter().map(|i| i.as_str().unwrap_or("")).collect()
InputFrequency::iter()
.map(|i| i.as_str().unwrap_or(""))
.collect()
}
fn to_toggle_vals() -> Vec<usize> {
@@ -907,22 +906,11 @@ impl ToggleTrait for InputFrequency {
}
}
// For input delay
trait ToUrlParam {
fn to_url_param(&self) -> String;
}
// The i32 is now in log form, need to exponentiate
// back into 2^X when we pass back to the menu
impl ToUrlParam for i32 {
fn to_url_param(&self) -> String {
2_i32.pow(*self as u32).to_string()
}
}
/// Item Selections
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive, EnumIter, Serialize, Deserialize)]
#[derive(
Debug, Clone, Copy, PartialEq, FromPrimitive, EnumIter, Serialize_repr, Deserialize_repr,
)]
pub enum CharacterItem {
None = 0,
PlayerVariation1 = 0x1,
@@ -969,15 +957,13 @@ impl CharacterItem {
_ => "None",
})
}
pub fn to_url_param(&self) -> String {
(*self as i32).to_string()
}
}
impl ToggleTrait for CharacterItem {
fn to_toggle_strs() -> Vec<&'static str> {
CharacterItem::iter().map(|i| i.as_str().unwrap_or("")).collect()
CharacterItem::iter()
.map(|i| i.as_str().unwrap_or(""))
.collect()
}
fn to_toggle_vals() -> Vec<usize> {
@@ -985,85 +971,49 @@ impl ToggleTrait for CharacterItem {
}
}
// Macro to build the url parameter string
macro_rules! url_params {
(
#[repr(C)]
#[derive($($trait_name:ident, )*)]
pub struct $e:ident {
$(pub $field_name:ident: $field_type:ty,)*
}
) => {
#[repr(C)]
#[derive($($trait_name, )*)]
pub struct $e {
$(pub $field_name: $field_type,)*
}
impl $e {
pub fn to_url_params(&self, defaults: bool) -> String {
let mut s = "".to_string();
let defaults_str = match defaults {
true => &"__", // Prefix field name with "__" if it is for the default menu
false => &"",
};
$(
s.push_str(defaults_str);
s.push_str(stringify!($field_name));
s.push_str(&"=");
s.push_str(&self.$field_name.to_url_param());
s.push_str(&"&");
)*
s.pop();
s
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Serialize, Deserialize, Debug, )]
pub struct TrainingModpackMenu {
pub hitbox_vis: OnOff,
pub stage_hazards: OnOff,
pub di_state: Direction,
pub sdi_state: Direction,
pub sdi_strength: InputFrequency,
pub clatter_strength: InputFrequency,
pub air_dodge_dir: Direction,
pub mash_state: Action,
pub follow_up: Action,
pub attack_angle: AttackAngle,
pub ledge_state: LedgeOption,
pub ledge_delay: LongDelay,
pub tech_state: TechFlags,
pub miss_tech_state: MissTechFlags,
pub shield_state: Shield,
pub defensive_state: Defensive,
pub oos_offset: Delay,
pub reaction_time: Delay,
pub shield_tilt: Direction,
pub mash_in_neutral: OnOff,
pub fast_fall: BoolFlag,
pub fast_fall_delay: Delay,
pub falling_aerials: BoolFlag,
pub aerial_delay: Delay,
pub full_hop: BoolFlag,
pub crouch: OnOff,
pub input_delay: i32,
pub save_damage: OnOff,
pub save_state_mirroring: SaveStateMirroring,
pub frame_advantage: OnOff,
pub save_state_enable: OnOff,
pub save_state_autoload: OnOff,
pub throw_state: ThrowOption,
pub throw_delay: MedDelay,
pub pummel_delay: MedDelay,
pub buff_state: BuffOption,
pub character_item: CharacterItem,
pub quick_menu: OnOff,
}
url_params! {
#[repr(C)]
#[derive(Clone, Copy, Serialize, Deserialize, Debug, )]
pub struct TrainingModpackMenu {
pub hitbox_vis: OnOff,
pub stage_hazards: OnOff,
pub di_state: Direction,
pub sdi_state: Direction,
pub sdi_strength: InputFrequency,
pub clatter_strength: InputFrequency,
pub air_dodge_dir: Direction,
pub mash_state: Action,
pub follow_up: Action,
pub attack_angle: AttackAngle,
pub ledge_state: LedgeOption,
pub ledge_delay: LongDelay,
pub tech_state: TechFlags,
pub miss_tech_state: MissTechFlags,
pub shield_state: Shield,
pub defensive_state: Defensive,
pub oos_offset: Delay,
pub reaction_time: Delay,
pub shield_tilt: Direction,
pub mash_in_neutral: OnOff,
pub fast_fall: BoolFlag,
pub fast_fall_delay: Delay,
pub falling_aerials: BoolFlag,
pub aerial_delay: Delay,
pub full_hop: BoolFlag,
pub crouch: OnOff,
pub input_delay: i32,
pub save_damage: OnOff,
pub save_state_mirroring: SaveStateMirroring,
pub frame_advantage: OnOff,
pub save_state_enable: OnOff,
pub save_state_autoload: OnOff,
pub throw_state: ThrowOption,
pub throw_delay: MedDelay,
pub pummel_delay: MedDelay,
pub buff_state: BuffOption,
pub character_item: CharacterItem,
pub quick_menu: OnOff,
}
}
macro_rules! set_by_str {
($obj:ident, $s:ident, $($field:ident = $rhs:expr,)*) => {
@@ -1075,11 +1025,14 @@ macro_rules! set_by_str {
}
}
const fn num_bits<T>() -> usize { std::mem::size_of::<T>() * 8 }
const fn num_bits<T>() -> usize {
std::mem::size_of::<T>() * 8
}
fn log_2(x: u32) -> u32 {
if x == 0 { 0 }
else {
if x == 0 {
0
} else {
num_bits::<u32>() as u32 - x.leading_zeros() - 1
}
}
@@ -1131,6 +1084,14 @@ impl TrainingModpackMenu {
}
}
#[repr(C)]
#[derive(Debug, Serialize, Deserialize)]
pub struct MenuJsonStruct {
pub menu: TrainingModpackMenu,
pub defaults_menu: TrainingModpackMenu,
// pub last_focused_submenu: &str
}
// Fighter Ids
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -1146,11 +1107,11 @@ pub enum SubMenuType {
}
impl SubMenuType {
pub fn from_str(s : &str) -> SubMenuType {
pub fn from_str(s: &str) -> SubMenuType {
match s {
"toggle" => SubMenuType::TOGGLE,
"slider" => SubMenuType::SLIDER,
_ => panic!("Unexpected SubMenuType!")
_ => panic!("Unexpected SubMenuType!"),
}
}
}
@@ -1224,43 +1185,34 @@ pub struct SubMenu<'a> {
}
impl<'a> SubMenu<'a> {
pub fn add_toggle(
&mut self,
toggle_value: usize,
toggle_title: &'a str
) {
self.toggles.push(
Toggle {
toggle_value: toggle_value,
toggle_title: toggle_title,
checked: false
}
);
pub fn add_toggle(&mut self, toggle_value: usize, toggle_title: &'a str) {
self.toggles.push(Toggle {
toggle_value: toggle_value,
toggle_title: toggle_title,
checked: false,
});
}
pub fn new_with_toggles<T:ToggleTrait>(
pub fn new_with_toggles<T: ToggleTrait>(
submenu_title: &'a str,
submenu_id: &'a str,
help_text: &'a str,
is_single_option: bool,
) -> SubMenu<'a> {
let mut instance = SubMenu {
submenu_title: submenu_title,
submenu_id: submenu_id,
help_text: help_text,
is_single_option: is_single_option,
toggles: Vec::new(),
_type: "toggle"
};
let values = T::to_toggle_vals();
let titles = T::to_toggle_strs();
for i in 0..values.len() {
instance.add_toggle(
values[i],
titles[i],
);
}
instance
let mut instance = SubMenu {
submenu_title: submenu_title,
submenu_id: submenu_id,
help_text: help_text,
is_single_option: is_single_option,
toggles: Vec::new(),
_type: "toggle",
};
let values = T::to_toggle_vals();
let titles = T::to_toggle_strs();
for i in 0..values.len() {
instance.add_toggle(values[i], titles[i]);
}
instance
}
}
@@ -1279,14 +1231,12 @@ impl<'a> Tab<'a> {
help_text: &'a str,
is_single_option: bool,
) {
self.tab_submenus.push(
SubMenu::new_with_toggles::<T>(
submenu_title,
submenu_id,
help_text,
is_single_option,
)
);
self.tab_submenus.push(SubMenu::new_with_toggles::<T>(
submenu_title,
submenu_id,
help_text,
is_single_option,
));
}
}
@@ -1295,39 +1245,8 @@ pub struct UiMenu<'a> {
pub tabs: Vec<Tab<'a>>,
}
pub fn get_menu_from_url(mut menu: TrainingModpackMenu, s: &str, defaults: bool) -> TrainingModpackMenu {
let base_url_len = "http://localhost/?".len();
let total_len = s.len();
let ss: String = s
.chars()
.skip(base_url_len)
.take(total_len - base_url_len)
.collect();
for toggle_values in ss.split('&') {
let toggle_value_split = toggle_values.split('=').collect::<Vec<&str>>();
let mut toggle = toggle_value_split[0];
if toggle.is_empty() | (
// Default menu settings begin with the prefix "__"
// So if skip toggles without the prefix if defaults is true
// And skip toggles with the prefix if defaults is false
defaults ^ toggle.starts_with("__")
) { continue }
toggle = toggle.strip_prefix("__").unwrap_or(toggle);
let bits: u32 = toggle_value_split[1].parse().unwrap_or(0);
menu.set(toggle, bits);
}
menu
}
pub unsafe fn get_menu() -> UiMenu<'static> {
let mut overall_menu = UiMenu {
tabs: Vec::new(),
};
let mut overall_menu = UiMenu { tabs: Vec::new() };
let mut mash_tab = Tab {
tab_id: "mash",
@@ -1420,7 +1339,6 @@ pub unsafe fn get_menu() -> UiMenu<'static> {
);
overall_menu.tabs.push(mash_tab);
let mut defensive_tab = Tab {
tab_id: "defensive",
tab_title: "Defensive Settings",
@@ -1508,13 +1426,13 @@ pub unsafe fn get_menu() -> UiMenu<'static> {
"Character Item",
"character_item",
"Character Item: CPU/Player item to hold when loading a save state",
true
true,
);
defensive_tab.add_submenu_with_toggles::<OnOff>(
"Crouch",
"crouch",
"Crouch: Should the CPU crouch when on the ground",
true
true,
);
overall_menu.tabs.push(defensive_tab);
@@ -1569,41 +1487,42 @@ pub unsafe fn get_menu() -> UiMenu<'static> {
"Stage Hazards",
"stage_hazards",
"Stage Hazards: Should stage hazards be present",
true
true,
);
misc_tab.add_submenu_with_toggles::<OnOff>(
"Quick Menu",
"quick_menu",
"Quick Menu: Should use quick or web menu",
true
true,
);
overall_menu.tabs.push(misc_tab);
let non_ui_menu = MENU;
let url_params = non_ui_menu.to_url_params(false);
let toggle_values_all = url_params.split("&");
let mut sub_menu_id_to_vals : HashMap<&str, u32> = HashMap::new();
let non_ui_menu = serde_json::to_string(&MENU).unwrap().replace("\"", "");
let toggle_values_all = non_ui_menu.split(',').collect::<Vec<&str>>();
let mut sub_menu_id_to_vals: HashMap<&str, u32> = HashMap::new();
for toggle_values in toggle_values_all {
let toggle_value_split = toggle_values.split('=').collect::<Vec<&str>>();
let mut sub_menu_id = toggle_value_split[0];
if sub_menu_id.is_empty() { continue }
sub_menu_id = sub_menu_id.strip_prefix("__").unwrap_or(sub_menu_id);
let toggle_value_split = toggle_values.split(':').collect::<Vec<&str>>();
let sub_menu_id = toggle_value_split[0];
if sub_menu_id.is_empty() {
continue;
}
let full_bits: u32 = toggle_value_split[1].parse().unwrap_or(0);
sub_menu_id_to_vals.insert(sub_menu_id, full_bits);
sub_menu_id_to_vals.insert(&sub_menu_id, full_bits);
}
overall_menu.tabs.iter_mut()
.for_each(|tab| {
tab.tab_submenus.iter_mut().for_each(|sub_menu| {
let sub_menu_id = sub_menu.submenu_id;
sub_menu.toggles.iter_mut().for_each(|toggle| {
if sub_menu_id_to_vals.contains_key(sub_menu_id) &&
(sub_menu_id_to_vals[sub_menu_id] & (toggle.toggle_value as u32) != 0) {
toggle.checked = true
}
})
overall_menu.tabs.iter_mut().for_each(|tab| {
tab.tab_submenus.iter_mut().for_each(|sub_menu| {
let sub_menu_id = sub_menu.submenu_id;
sub_menu.toggles.iter_mut().for_each(|toggle| {
if sub_menu_id_to_vals.contains_key(sub_menu_id)
&& (sub_menu_id_to_vals[sub_menu_id] & (toggle.toggle_value as u32) != 0)
{
toggle.checked = true
}
})
});
})
});
overall_menu
}