- Notifications
You must be signed in to change notification settings - Fork 2
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.
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.
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)
These functions add items to the root "Mods" page. They're the easiest way to integrate.
SharedAPI.DebugMenu.RegisterToggle(mod_name, display_name, default_state, callback)| Parameter | Type | Description |
|---|---|---|
mod_name | string | Your mod's identifier (e.g., "GodMode") |
display_name | string | Text shown in the menu (e.g., "God Mode") |
default_state | boolean | Initial on/off state |
callback | function | fn(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]
SharedAPI.DebugMenu.RegisterAction(mod_name, display_name, callback)| Parameter | Type | Description |
|---|---|---|
mod_name | string | Mod identifier |
display_name | string | Button text |
callback | function | fn(item) — called on confirm |
Example:
SharedAPI.DebugMenu.RegisterAction("Spawner", "Spawn Enemy", function()
-- Spawn logic hereLog("Enemy spawned!")
end)SharedAPI.DebugMenu.RegisterSelector(mod_name, display_name, options, callback)| Parameter | Type | Description |
|---|---|---|
mod_name | string | Mod identifier |
display_name | string | Label text |
options | table | {"Easy", "Normal", "Hard"} |
callback | function | fn(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.
For dynamic sub-pages with content that can change at runtime.
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)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()).
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.
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.
For pages with fixed content that doesn't change.
localpage=SharedAPI.DebugMenu.AddPage(page_id, page_title)Creates a static page and auto-adds a navigation link on the root Mods page.
SharedAPI.DebugMenu.AddItemToPage(page, mod_name, name, item_type, opts)| Parameter | Type | Description |
|---|---|---|
page | table | Page returned by AddPage() |
mod_name | string | Mod identifier |
name | string | Display name |
item_type | string | "toggle", "action", or "selector" |
opts | table | {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
})SharedAPI.DebugMenu.GetPages() -- All custom pages (read-only)SharedAPI.DebugMenu.IsCustomPage(byte) -- Is this byte a custom page?SharedAPI.DebugMenu.VERSION-- API version string-- 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