Skip to content

Debug Menu API

xAstroBoy edited this page Mar 20, 2026 · 1 revision

Debug Menu API

The DebugMenuAPI mod provides an in-game menu system that other mods can use to register toggles, actions, selectors, and sub-pages.

Overview

The debug menu is accessed in-game via the VR controller debug input. The DebugMenuAPI mod adds a "Mods" entry to the main debug menu page, which opens a custom page where all registered mod options appear.

Architecture

Main Debug Menu (page 1, Blueprint)
├── Settings
├── Display
├── ...
└── Mods ──► Mods Root Page (page 100, Lua)
├── God Mode [ON] (toggle)
├── No Recoil [OFF] (toggle)
├── Difficulty [Normal] (selector)
├── Spawn Enemy (action)
├── Advanced Settings >> (submenu)
│ ├── Speed: 1.0x (dynamic item)
│ ├── Reset All (dynamic item)
│ └── Back (auto-added)
└── Back (auto-added)

Simple API

These functions add items to the root "Mods" page. They're the easiest way to integrate.

RegisterToggle

SharedAPI.DebugMenu.RegisterToggle(mod_name, display_name, default_state, callback)
ParameterTypeDescription
mod_namestringYour mod's identifier (e.g., "GodMode")
display_namestringText shown in the menu (e.g., "God Mode")
default_statebooleanInitial on/off state
callbackfunctionfn(new_state, item) — called on toggle

Returns: item table

Example:

SharedAPI.DebugMenu.RegisterToggle("GodMode", "God Mode", false, function(enabled)
god_mode=enabledLog("God Mode: " ..tostring(enabled))
end)

Display: God Mode [OFF] / God Mode [ON]

RegisterAction

SharedAPI.DebugMenu.RegisterAction(mod_name, display_name, callback)
ParameterTypeDescription
mod_namestringMod identifier
display_namestringButton text
callbackfunctionfn(item) — called on confirm

Example:

SharedAPI.DebugMenu.RegisterAction("Spawner", "Spawn Enemy", function()
-- Spawn logic hereLog("Enemy spawned!")
end)

RegisterSelector

SharedAPI.DebugMenu.RegisterSelector(mod_name, display_name, options, callback)
ParameterTypeDescription
mod_namestringMod identifier
display_namestringLabel text
optionstable{"Easy", "Normal", "Hard"}
callbackfunctionfn(selected_value, selected_index, item)

Example:

SharedAPI.DebugMenu.RegisterSelector("MyMod", "Difficulty",
{"Easy", "Normal", "Hard", "Nightmare"},
function(value, index)
Log("Difficulty: " ..value.." (index " ..index..")")
end
)

Display: Difficulty [Normal] — cycles on each confirm.

Advanced API

For dynamic sub-pages with content that can change at runtime.

RegisterSubMenu

SharedAPI.DebugMenu.RegisterSubMenu(mod_name, display_name, callback)

Adds a >> link on the root page. When selected, callback fires — call NavigateTo inside it.

Example:

SharedAPI.DebugMenu.RegisterSubMenu("MyMod", "Advanced Settings", function()
SharedAPI.DebugMenu.NavigateTo({
name="Advanced Settings",
populate=function()
SharedAPI.DebugMenu.AddItem("Option 1", function()
Log("Selected option 1")
end)
SharedAPI.DebugMenu.AddItem("Option 2", function()
Log("Selected option 2")
SharedAPI.DebugMenu.Refresh() -- Rebuild pageend)
end
})
end)

NavigateTo

SharedAPI.DebugMenu.NavigateTo({ name="Title", populate=function() ...end })

Creates a new page and navigates to it. The populate function is called every time the page is rendered (including on Refresh()).

AddItem

SharedAPI.DebugMenu.AddItem(display_name, callback_or_nil)

Adds an item to the page currently being built inside a populate callback. Pass nil as callback for a non-interactive label/separator.

Refresh

SharedAPI.DebugMenu.Refresh()

Re-renders the current custom page. For dynamic pages, re-calls the populate function. Use this to update displayed values after state changes.

Static Sub-Pages

For pages with fixed content that doesn't change.

AddPage

localpage=SharedAPI.DebugMenu.AddPage(page_id, page_title)

Creates a static page and auto-adds a navigation link on the root Mods page.

AddItemToPage

SharedAPI.DebugMenu.AddItemToPage(page, mod_name, name, item_type, opts)
ParameterTypeDescription
pagetablePage returned by AddPage()
mod_namestringMod identifier
namestringDisplay name
item_typestring"toggle", "action", or "selector"
optstable{default, callback, options, default_index}

Example:

localpage=SharedAPI.DebugMenu.AddPage("settings", "My Settings")
SharedAPI.DebugMenu.AddItemToPage(page, "MyMod", "Verbose Logs", "toggle", {
default=false,
callback=function(on) verbose=onend
})
SharedAPI.DebugMenu.AddItemToPage(page, "MyMod", "Reset", "action", {
callback=function() reset_all() end
})

Utility Functions

SharedAPI.DebugMenu.GetPages() -- All custom pages (read-only)SharedAPI.DebugMenu.IsCustomPage(byte) -- Is this byte a custom page?SharedAPI.DebugMenu.VERSION-- API version string

Complete Example

-- mods/MyMod/main.lualocalTAG="MyMod"localstate= {
enabled=true,
difficulty="Normal",
speed=1.0,
}
-- Load saved configlocalsaved=ModConfig.Load(TAG)
ifsavedthenifsaved.enabled~=nilthenstate.enabled=saved.enabledendifsaved.difficultythenstate.difficulty=saved.difficultyendifsaved.speedthenstate.speed=saved.speedendendlocalfunctionsave() ModConfig.Save(TAG, state) end-- Register in debug menulocalapi=SharedAPIandSharedAPI.DebugMenuifapithen-- Toggle on root pageapi.RegisterToggle(TAG, "My Feature", state.enabled, function(on)
state.enabled=onsave()
end)
-- Selector on root pageapi.RegisterSelector(TAG, "Difficulty",
{"Easy", "Normal", "Hard"},
function(val) state.difficulty=val; save() end
)
-- Sub-menu with dynamic contentapi.RegisterSubMenu(TAG, "Speed Settings", function()
api.NavigateTo({
name="Speed Settings",
populate=function()
localspeeds= {0.5, 1.0, 1.5, 2.0, 3.0}
for_, sinipairs(speeds) dolocallabel="Speed " ..s.."x"ifs==state.speedthenlabel=label.."" endapi.AddItem(label, function()
state.speed=ssave()
api.Refresh()
end)
endend
})
end)
end

Clone this wiki locally