ActionButton.Root The button's GameObject.
Shared C# layer the other mods build on.
The shared foundation Cairn mods build on — clean, named APIs over the game's internals, so you spend your time on your mod instead of reverse-engineering the plumbing.
Hook into the game's menus, build settings pages, show in-world prompts, read and change the inventory, teleport the climber, and react to game state.
Features
Requires
MelonLoader only.
A bottom-strip text action button (the native "Return"/"Reset" style), with an optional live keycap glyph at its left.
ActionButton.Root The button's GameObject.
ActionButton.Rect The RectTransform (authored size 200×50; resize or let a layout group drive it).
ActionButton.Selectable The underlying uGUI Selectable, for navigation wiring.
ActionButton.Create(parent, label, onClick, glyphAction?) Create an action button under parent. Click / Submit fires onClick. Returns null on failure (game UI not loaded yet).
parent | RectTransform | Where to attach (typically a bottom HorizontalLayoutGroup strip). |
label | string | Button text. |
onClick | Action | Fired on click / Submit. |
glyphAction opt | InputAction | Optional input action whose keycap renders left of the button (see CairnAPI.Glyph). |
ActionButton.SetLabel(text) Change the label text.
text | string |
ActionButton.SetInteractable(interactable) Enable/disable interaction (native disabled tint).
interactable | bool |
ActionButton.Select() Move uGUI selection to this button.
ActionButton.Destroy() Tear the button down. Safe to call more than once.
var b = ActionButton.Create(bar, "Return", Close, Glyph.Action(GameAction.UICancel)); Return value from Inventory.Add.
AddResult.Ok True if all requested items were added.
AddResult.Added How many were actually added.
AddResult.Error Failure reason when Ok is false.
Load any of the game's assets by Addressables key, from any game state — the title screen included. Every asset the game ships (prefabs, ScriptableObjects, materials, textures, timelines) is in the Addressables catalog; there is never a reason to wait for gameplay so a bundle happens to be loaded, or to clone a live scene object as a substitute for the real asset. Keys are forgiving: pass the full catalog address, the asset's GUID, or just the bare asset name (Assets.Load
Assets.TryResolveKey(query, key, typeName?) Resolve a query (exact catalog key, GUID, full path, or bare asset name — case-insensitive) to the exact catalog key. When several assets share a bare name, typeName (e.g. "GameObject") picks between them. Returns false when nothing matches.
query | string | |
key | string | |
typeName opt | string |
Assets.FindKeys(substring) All catalog keys containing substring (case-insensitive) — discovery for tooling and exploratory code. GUID keys are included.
substring | string |
Assets.Load``1(keyOrName) Load an asset synchronously. T is the expected asset type (GameObject for prefabs); the result is the ASSET, not an instance — Instantiate what you need from it. Returns null (with a logged warning) for unknown keys, failed loads, and type mismatches. The underlying Addressables handle is cached and held, so repeat calls are free and the asset stays valid until Assets.Release.
keyOrName | string |
Assets.LoadAsync``1(keyOrName, onReady) Load an asset without blocking; onReady fires on the main thread with the asset, or null on failure — synchronously when the asset is already cached. Same caching and resolution semantics as Assets.Load%60%601.
keyOrName | string | |
onReady | Action<T> |
Assets.Release(keyOrName) Release a previously loaded asset's Addressables handle. After this the asset (and clones of it) may be unloaded by the engine — only call it when the mod is done with the asset for good.
keyOrName | string |
The game's center-screen announcement banner.
Banner.Show(text, seconds?, onEnd?) Show a center-screen announcement in the game's own banner style, auto-closing after seconds. Returns false if the game UI isn't loaded yet. A banner shown while one is already up replaces its text and timer.
text | string | The message (shown as-is). |
seconds opt | float | Seconds until the banner closes itself. |
onEnd opt | Action | Optional callback when the banner has closed. |
Banner.Show("Route complete!", 3f); A story-beat sensor location.
Beat.Label Authored beat name.
Beat.Position World-space center of the sensor trigger.
Enumerate story-beat sensors in the current scene.
Beats.Available → bool True when the story manager is live. Check before calling Snapshot.
Beats.Snapshot() → List Every story-beat sensor in the current scene, sorted by label. Pure — no caching.
if (!Beats.Available) return;
var beats = Beats.Snapshot();
foreach (var b in beats)
Log($"{b.Label} @{b.Position}");
Teleport.To(Stance.Ground(beats[0].Position)); The climbbot's belay as state a teleport must MANAGE, not destroy. The game attaches/secures the bot itself on climbing-mode entry (proven live: the bot re-attached ~30ms after a wall arrival), so the rules are: • a placement that yanks a BELAYED climber stands the belay down first (else the rope + its quickdraws stay anchored to the old wall across the jump); • a climbing arrival re-secures — natively when the placement crosses a mode edge, explicitly via Belay.Resume when it doesn't (wall→wall keeps the mode, so no native attach fires); • a ground arrival stays detached — the native attach re-arms on the next climb. Never stand the belay down outside a placement (a spawn-time stand-down fights the game's own attach).
Belay.Active A climbbot is currently attached to the climber's harness.
Belay.StandDown() Stand the belay down (stop securing + detach the rope) — the bot's own setters in its recall flow's order. Safe no-op when not belayed. Only call around a placement.
Belay.Resume() Re-establish the belay after a placement that ended in CLIMBING without a mode edge (the native attach only fires on entry into climbing). No-ops when the pawn isn't climbing — SetSecureClimber's own mode check guards it — or when no bot exists.
One saved bookmark: a named world position bound to the map it was placed on. A bookmark captured while climbing also carries the verbatim on-wall pose.
Bookmark.Pose The verbatim pose captured with the bookmark, or null for a ground bookmark (existing stores load with no pose and behave exactly as before).
Bookmark.Position The bookmark's world position.
Bookmark.OnWall True when this bookmark was captured on the wall (it carries a climbing pose).
Saved warp-point bookmarks, shared across mods. A bookmark is a named world position on a specific map; while that map is loaded it appears in the eagle-eye fast-travel list as a warpable destination. Add, rename, and remove here — materializing the live warp points (register on gameplay load, re-anchor on zone change, stand down on session end) is automatic.
Bookmarks.OnRegistryChanged Fires when the live warp-point registry changes wholesale — after a lifecycle stand-down (session end, zone change) and after a rebuild completes. UIs holding warp-point rows should re-pull them.
Bookmarks.OnCurrentMap() Every bookmark saved for the current map, or an empty list when not in a level.
Bookmarks.ForMap(mapKey) Every bookmark saved for an explicit map key (a shipped mountain's world name, or a custom level's "cml:" address — the same key World.CurrentMapKey reports in-level). For menu-time enumeration, when no world is loaded. Null or empty key → empty list.
mapKey | string |
Bookmarks.Add(name?, allowOnWall?) Save a bookmark at the local climber's current spot on the current map. Standing on the ground saves a plain position; a stable climbing stance saves the verbatim on-wall pose with it. Pass allowOnWall false when the calling surface can only manage ground bookmarks — an on-wall capture is then refused (the grounded-only behavior). A null or blank name gets a default. Returns null when the climber is not spawned or is mid-move (falling, reaching, on the rope, or off every hold) — those states can't be captured.
name opt | string | |
allowOnWall opt | bool |
Bookmarks.Add(position, name?) Save a bookmark at an explicit world position on the current map. A null or blank name gets a default. Returns null when not in a level.
position | Vector3 | |
name opt | string |
Bookmarks.Rename(bookmark, name) Rename a bookmark and persist; its warp-list row updates on the game's next refresh.
bookmark | Bookmark | |
name | string |
Bookmarks.Remove(bookmark) Remove a bookmark and its live warp point, if any. Returns false if unknown.
bookmark | Bookmark |
Bookmarks.ForWarpPoint(warpPoint) The bookmark behind a live warp point, or null if the point is not a bookmark's.
warpPoint | FreeRoamWarpPoint |
Bookmarks.LocKeyOf(bookmark) The loc key rendering a bookmark's name while it is materialized (for live edits via Localization.Update), or default when it has no live point.
bookmark | Bookmark |
Bookmarks.WarpConfirmed Fires when a bookmark is warp-confirmed from the eagle-eye view (after the pawn is placed). A session mod (Boulderdash) uses it to fold the arrival into its own run/restart bookkeeping.
Caches a scan's results indexed by key (e.g. LootProvider by UniquePersistentID). A miss rebuilds the whole index in one scan rather than scanning per lookup — turns an O(n) scan repeated m times (once per point-query) into one O(n) scan plus m O(1) dictionary lookups.
Caches independent results keyed by an arbitrary value (e.g. a font atlas texture, a template-array pointer). Unlike CairnAPI.CachedRef%601, multiple keys stay cached simultaneously instead of evicting each other — use when the same call site legitimately queries more than one distinct key over the object's lifetime (e.g. a two-rung "prefer X, else Y" fallback).
Caches a single resolved instance. A live (non-null, Unity's overridden operator) cached value short-circuits the scan entirely. An optional key lets the cache self-invalidate when the caller's identity changes (e.g. a respawn swaps which pawn is "local", or the active scene changes) even though the old cached value may still technically be non-null.
CachedRef.Get(resolve) Resolve once and hold forever (until Unity-null). A null result is remembered too — resolve() won't run again unless CachedRef%601.Invalidate is called. Use when a null result means "confirmed absent, and nothing else here would make it appear" (e.g. a fixed, load-once asset).
resolve | Func<T> |
CachedRef.GetUntilFound(resolve) Same, but a null result is NOT remembered — every call re-resolves until resolve() finally succeeds, then stays cached from then on. Use for a transient condition you're waiting on (e.g. "has the pawn spawned yet") where retrying every call is the point.
resolve | Func<T> |
CachedRef.Get``1(key, resolve) Resolve and cache, but re-resolve (including re-trying a previously-null result) whenever key differs from the key last used to produce the cached value — e.g. a scene name, so "no MainMenu in this scene" stays cached until the scene actually changes.
key | TKey | |
resolve | Func<T> |
Caches the full result of a scan (e.g. every loaded InputActionAsset) until explicitly invalidated. Use when a caller needs to enumerate ALL matching instances repeatedly, not look up one by key — the instances themselves are stable even though which of them are individually "active" varies per call.
Cameras.Reseat() Re-seat the gameplay camera behind the pawn NOW — the native "climber reset" verb. Selects the current camera (ForceCameraChangeNow, byte-identical to CheckCurrentCamera) and resets the live rig (repositions its look-at pivot and computes the behind-her rotation). Mirrors the native teleport chain, which our teleport pipeline doesn't otherwise trigger. Returns false if the camera system isn't up or the call failed.
Cameras.EagleViewActive True while any eagle-eye view (plain / plus / free / route-scouting) is the active camera — the read-only observer for Cameras.Reseat's camera family. False on any failure.
Carousel.Root The widget's root GameObject.
Carousel.SelectionChanged Fires with the newly-centered entry's index whenever the selection moves.
Carousel.Create(parent, items, onPick, canPick?) Build a native item carousel under parent. onPick fires with the centered entry's index on Submit / click; canPick (optional) refuses a pick with the native shake. Returns null when the carousel template isn't available.
parent | RectTransform | |
items | IReadOnlyList<InventoryItemStringIdEnum> | |
onPick | Action<int> | |
canPick opt | Func<int, bool> |
Carousel.SelectedIndex The centered entry's index into the list passed to Create.
Carousel.Move(direction) Move the selection left (-1) / right (+1) with the native slide.
direction | int |
Carousel.Select(index) Center an entry immediately (no slide).
index | int |
Carousel.FocusFirst() Focus the carousel so gamepad/keyboard axis input drives it.
Carousel.Destroy() Tear the carousel down. Safe to call more than once.
The game clock — a day-seconds float owned by the game's time system. Reads fail soft (zero) when no session is up. Writes are deliberately SILENT (the game's bare clock write): survival systems do not react, so they're right for corrections, replication, and scripted setups. There is no wrapper for the event-firing setter — passing time "for real" (hunger ticks, day count) belongs to real sleeps at bivouacs.
Clock.GameTime The game clock in day-seconds (wraps daily; 3600 = 1:00 AM). 0 when no session is up.
Clock.Day How many in-game days have passed.
Clock.TimeOfDay01 Time of day as 0..1 across the current day (0.5 = noon).
Clock.Paused Whether the game clock is currently paused (menus, cinematics, photo mode).
Clock.SetSilently(daySeconds) Set the clock to an absolute day-seconds value, silently (no survival side effects). Returns false when no session is up.
daySeconds | float |
Clock.SetSilently(hours, minutes?) Set the time of day within the current day, silently (no survival side effects).
hours | int | |
minutes opt | int |
THE CYCLE WIDGET — the game's own "label ‹ value ›" arrows row (the exact FieldListArrows the settings menus render), lifted out of the menu-screen context as a standalone palette widget: host it in any RectTransform (the eagle-eye prompt band, a HUD line, a widget page) and drive it by Cycler.Index. Rendering, arrow buttons, and value refresh are entirely the native row (the shared donor-template machinery under CairnAPI.FieldRows); this wrapper owns only a compact, layout-group-friendly container and the model. Null from Create when no donor templates exist yet (build once a menu/gameplay host is up).
Cycler.Rect The widget's container — anchor/place it like any child (it also carries a LayoutElement, so layout-group hosts flow it inline).
Cycler.Create(parent, label, options, index, onChanged, width?, height?) Build the native arrows row under parent. onChanged fires with the new option index — from the arrow buttons AND from programmatic Cycler.Index writes (hotkey-driven cycling).
parent | RectTransform | |
label | string | |
options | string[] | |
index | int | |
onChanged | Action<int> | |
width opt | float | |
height opt | float |
Cycler.EnsureFitted() One-shot post-materialize normalization for standalone hosts — the row prefab is authored for the full settings-panel width (prefab-measured: label cell 0–40%, value cluster 60–100%, the value text spanning the WHOLE cluster with the 32px arrows floating on its ends, and the right arrow pivoted to hang 32px PAST the row edge). At widget widths (~480px) that collides. Retune: label 0–30%, cluster 30–100%, right arrow pivoted inside, text inset clear of both arrows. Call per frame (rows materialize a frame after build via the game's deferred refresh); no-ops once applied.
Cycler.Index The selected option. Setting it drives the NATIVE row refresh (and the onChanged callback) through the model's own Index setter; an unchanged value is a no-op.
Cycler.Destroy() Tear the widget down. Safe to call more than once.
The game's own settings rows (the ones CairnAPI.Fields builds) hosted inside a container you own — for mixing native rows into a custom widget page. Create with the rows, or FieldRows.Set later. Returns null from Create when the game UI isn't loaded yet.
FieldRows.Rect The rows' RectTransform — anchor/place it like any child; height auto-fits.
FieldRows.Create(parent, fields) Build native rows under parent. Top-anchored, parent-width, auto-height; re-anchor FieldRows.Rect to place. Null when no donor templates exist yet (build once a menu or gameplay host is up).
parent | RectTransform | |
fields | Field[] |
FieldRows.Valid True while the host and its donor templates are alive.
FieldRows.Set(fields) Replace the rows (the game's own RemoveAll → Add → Activate cycle).
fields | Field[] |
FieldRows.Selectables() The rows' Selectables in visual (sibling) order — for wiring explicit navigation between the rows and neighbouring controls. Live query: rows are born a frame after FieldRows.Set (the game's deferred Refresh), so call this from a later frame; empty until then.
FieldRows.LastSelectable() The actual Selectable the game focuses on the LAST navigable row (native FieldsUI.GetLastSelectable) — not the first child Selectable FieldRows.Selectables returns, which on a value row (ListArrows/slider) can be an inner arrow. Use this when wiring a control BELOW the rows: UI.FieldsUI re-derives its rows' Navigation struct on every selection change (FieldUI.SetNavigation), nulling the bottom field's selectOnDown — so re-assert the link to this selectable each frame, don't set it once. Null when no rows / host dead.
FieldRows.FirstSelectable() The actual Selectable of the FIRST navigable row (native FieldsUI.GetFirstSelectable) — the counterpart to FieldRows.LastSelectable for wiring a control ABOVE the rows.
FieldRows.SelectFirst() Hand EventSystem focus to the first selectable row.
FieldRows.Destroy() Tear the rows down and invalidate the handle. Safe to call more than once.
Fields.PillButton(label, buttonLabel, onClick) A settings row with a REAL pill-chromed button as its widget — label on the left, button on the right (unlike Fields.Button, where the whole chromeless row is the button).
label | string | Row label (left column). |
buttonLabel | string | Text on the pill button. |
onClick | Action | Fired when the button is clicked / confirmed. |
Fields.Grid(label, cells, initialIndex, onChanged) A grid of icon+label cells the player clicks to pick one. Renders in settings, photo mode, and debug menu pages alongside the other field rows.
label | string | |
cells | (Sprite icon, string label)[] | |
initialIndex | int | |
onChanged | Action<int, int> |
Fields.VectorSlider(label, initial, onChanged, min, max, wholeNumbers?) A 2-component row of sliders for editing a Vector2, e.g. a min/max or X/Y pair.
label | string | |
initial | Vector2 | |
onChanged | Action<Vector2, Vector2> | |
min | Vector2 | |
max | Vector2 | |
wholeNumbers opt | bool |
Fields.VectorSlider(label, initial, onChanged, min, max, wholeNumbers?) A 3-component row of sliders for editing a Vector3, e.g. an X/Y/Z offset.
label | string | |
initial | Vector3 | |
onChanged | Action<Vector3, Vector3> | |
min | Vector3 | |
max | Vector3 | |
wholeNumbers opt | bool |
Fields.VectorSlider(label, initial, onChanged, min, max, wholeNumbers?) A 4-component row of sliders for editing a Vector4, e.g. a color or a rect.
label | string | |
initial | Vector4 | |
onChanged | Action<Vector4, Vector4> | |
min | Vector4 | |
max | Vector4 | |
wholeNumbers opt | bool |
Fields.VectorText(label, initial, onChanged, min, max, wholeNumbers?) A 2-component row of text inputs for editing a Vector2, e.g. a min/max or X/Y pair.
label | string | |
initial | Vector2 | |
onChanged | Action<Vector2, Vector2> | |
min | Vector2 | |
max | Vector2 | |
wholeNumbers opt | bool |
Fields.VectorText(label, initial, onChanged, min, max, wholeNumbers?) A 3-component row of text inputs for editing a Vector3, e.g. an X/Y/Z offset.
label | string | |
initial | Vector3 | |
onChanged | Action<Vector3, Vector3> | |
min | Vector3 | |
max | Vector3 | |
wholeNumbers opt | bool |
Fields.VectorText(label, initial, onChanged, min, max, wholeNumbers?) A 4-component row of text inputs for editing a Vector4, e.g. a color or a rect.
label | string | |
initial | Vector4 | |
onChanged | Action<Vector4, Vector4> | |
min | Vector4 | |
max | Vector4 | |
wholeNumbers opt | bool |
FieldsPanel.Create(title?, width?) Build a hidden panel that will host native settings rows. The panel is created but NOT shown — call FieldsPanel.Show after adding fields. Row visuals come from the game's own settings-row templates, acquired once at build time. Returns an invalid handle (all methods no-op) if the game hasn't loaded its UI yet — build the panel once a menu or gameplay is up.
title opt | string | Optional heading drawn above the rows; null = no header. |
width opt | float | Panel width in reference pixels (height auto-fits the rows). |
FieldsPanel.Valid True once the panel is built and its FieldsUI + row templates are still alive.
FieldsPanel.Visible True while the panel is on-screen (between FieldsPanel.Show and FieldsPanel.Hide).
FieldsPanel.Add(fields) Add native rows for the given game UI.Field data objects (the ones CairnAPI.Fields builds). Rows are born inactive and appear a frame later via the game's own deferred Refresh — do not fight it. Repeated Add of the same Field is NOT deduplicated; call FieldsPanel.Clear before rebuilding. Keep the total under ~12 rows (no scroll in v1).
fields | Field[] |
FieldsPanel.Show() Show the panel and hand focus to its first row (EventSystem row-nav then works). Idempotent. The game supplies the EventSystem; without one, rows draw but can't be navigated.
FieldsPanel.Hide() Hide the panel (rows and their state are kept; call FieldsPanel.Show to reveal again).
FieldsPanel.Clear() Destroy every current row (the game's own RemoveAll — unbinds, stops coroutines, destroys row GOs).
FieldsPanel.Destroy() Tear the panel down entirely and invalidate the handle. Safe to call more than once.
Friendly names for the game actions a custom prompt most commonly echoes. See Glyph.Action.
GameAction.Interact GameAction.SharePath GameAction.Confirm GameAction.Cancel GameAction.Navigate GameAction.Pause GameAction.Rest GameAction.Rappel GameAction.AscendRope GameAction.GrabRope GameAction.Rewind GameTime.PauseGameplay() Request a gameplay pause — freezes the simulated world (climber, physics) while leaving the camera and UI on the engine clock. Reference-counted; balance every call with GameTime.UnpauseGameplay. Returns false if the time system isn't up.
GameTime.UnpauseGameplay() Release one gameplay-pause request. GUARDED against the OnLevelLoading drain trap: TimeManager.OnLevelLoading drains the pause-request counter to zero on every level load, so a request held across a reload is ALREADY released by the game — decrementing afterward would drive the counter negative and silently eat a future pause. So when the pawn is despawned (a level load in flight) or there is no world at all, the decrement is SKIPPED and this returns false. Otherwise it releases and returns true.
GameTime.GameplayPaused True while gameplay is paused (the request counter is above zero) — the read-only observer for the pause verbs. False on any failure.
Glyph.Action(action) The player's live InputAction for a curated game action (reflects their current rebind), or null if the input system isn't ready yet. Hand the result to a Prompt as its glyph.
action | GameAction |
Glyph.Named(mapSlashAction) Resolve any game action by its "Map/Action" (or bare "Action") name against the live input asset — the escape hatch for actions not in the CairnAPI.GameAction enum. Null if not found / not ready.
mapSlashAction | string |
Glyph.Key(key) A glyph for a raw keyboard key, e.g. Glyph.Key("g"). Special keys (enter/space/esc/tab/arrows…) resolve to a stock sprite; plain letter/number keys have no sprite in the icon DB, so they render as the human-readable key text ("G") — exactly as the game does. See CairnAPI.Glyph.
key | string |
Glyph.Path(controlPath) A glyph for an arbitrary control path, e.g. Glyph.Path("
controlPath | string |
Glyph.Custom(name, bindingPaths) A cross-device action with MULTIPLE bindings (e.g. a keyboard key AND a gamepad button), enabled so it fires on either device, and usable BOTH as a prompt glyph (the glyph + adaptiveBinding auto-picks the active device's binding, so the keycap swaps to the pad button on a controller) AND as live input (poll action.WasPerformedThisFrame()). This is the parity path: bind "
name | string | |
bindingPaths | string[] |
Glyph.Asset The live InputActionAsset the game is driving (player's bindings live here), or null pre-game.
GlyphImage.Root The widget's GameObject (an Image the native component drives). Parent/position freely.
GlyphImage.Rect The RectTransform, for layout.
GlyphImage.Create(parent, action, size?) Create an inline glyph image under parent showing the sprite for action's current binding (see CairnAPI.Glyph for obtaining actions). The icon tracks device changes and rebinds natively. Returns null if construction fails; a null action is allowed — the glyph stays hidden until GlyphImage.SetAction is called.
parent | RectTransform | Transform to nest under (layout groups size it via its RectTransform). |
action | InputAction | The input action whose binding the glyph renders, or null for none yet. |
size opt | float | Square edge length in reference pixels (native prompt glyphs are ~60). |
GlyphImage.Create(parent, action, size?) Create showing the player's current binding for a curated CairnAPI.GameAction.
parent | RectTransform | |
action | GameAction | |
size opt | float |
GlyphImage.SetAction(action) Point the glyph at a different action (it re-renders; null hides it).
action | InputAction |
GlyphImage.SetBindingIndex(index) Show a specific binding of the action instead of the device-adaptive pick.
index | int |
GlyphImage.Destroy() Tear the glyph down. Safe to call more than once.
Whether the streamed climbing holds have arrived at a position. A level loads a low-detail wall first and streams the real holds subscene in a moment later; until the hold behaviours register (they do so in OnEnable) and answer with candidates, a climbing placement there has nothing to grip. Holds.ReadyAt is that readiness signal — the scene's own grab-candidate lookup answering with holds IS the "the wall is here now" edge a race-safe on-wall spawn waits on.
Holds.ReadyAt(pos) True when the streamed climbing holds are present around pos — at least one registered SceneHoldsSpatialPartitioning answers with candidate holds there. False (never throws) while the holds subscene is still streaming in, or when the scene state can't be read.
pos | Vector3 |
HudPanel.Content The region to build panel content under (full-screen stretch; anchor your own layout).
HudPanel.Create(name?, fadeDuration?, sortingOrder?) Build a hidden HUD panel with the native open/close fade lifecycle. Build content under HudPanel.Content, then HudPanel.Open. The panel survives scene loads. Returns an invalid handle (all methods no-op) if construction fails.
name opt | string | GameObject name (diagnostics); null = a default. |
fadeDuration opt | float | Open/close fade seconds (unscaled). Must be > 0 for the async fade. |
sortingOrder opt | int | Canvas order: over the game HUD, under the pause menu (1000) by default. |
HudPanel.Valid True once built and still alive.
HudPanel.IsOpen True while the panel is open or fading in (the native state query).
HudPanel.Open() Open with the native fade-in. Idempotent while already open.
HudPanel.Close() Close with the native fade-out. Idempotent while already closed.
HudPanel.SnapOpen() Snap open/closed without the fade (the native ForceOpen/ForceClose path).
HudPanel.SnapClosed() Snap closed without the fade.
HudPanel.Destroy() Tear the panel down entirely and invalidate the handle. Safe to call more than once.
A contributor of destinations to the eagle-eye fast-travel list. Register with WarpSources.Register; the active source's IWarpSource.Entries are materialized as live warp points, and selecting one routes to IWarpSource.Confirm (never the native warp — so no loading screen and full control over what "arrive" means: teleport, start a run, …). Rename/Delete drive the in-view edit keybinds. Call WarpSources.Invalidate when your entries change.
IWarpSource.Label Short label for the source toggle prompt ("Bookmarks", "Routes").
IWarpSource.Entries() The destinations for the CURRENT map (the source reads World.CurrentMapKey itself). Called on every (re)materialize; return a fresh list.
IWarpSource.Confirm(entry) Arrive at a selected entry. Runs INSTEAD of the native warp (which is skipped), so this owns placement — use Teleport.To with a CairnAPI.Stance, or start a run; never the native WarpToPoint.
entry | WarpEntry |
IWarpSource.CanEdit(entry) Whether this entry may be renamed/deleted from the eagle-eye view.
entry | WarpEntry |
IWarpSource.Rename(entry, newName) Rename an editable entry (persist + WarpSources.Invalidate).
entry | WarpEntry | |
newName | string |
IWarpSource.Delete(entry) Delete an editable entry (persist + WarpSources.Invalidate).
entry | WarpEntry |
IWarpSource.Available Whether this source is currently offerable at all — it only counts toward the toggle, can be switched to, and materializes while true. Bookmarks are always available; routes only inside a Boulderdash session, so in a plain campaign the routes list and its toggle never appear.
IWarpSource.CanAddHere Whether the "add here" keybind applies to this source (bookmarks capture the climber's spot; sources whose destinations are authored elsewhere — routes are recorded — return false).
IWarpSource.ListsNativePoints Whether the game's OWN warp points stay in the eagle-eye list while this source is active. Bookmarks say yes (native destinations belong with them); routes say no (the list shows routes only — natives are pulled while active and restored on toggle/stand-down).
IWarpSource.NativeLabel Label for the game-provided entries this source can show/hide from its list ("game points", "game routes"), or null when it has none — the eagle-eye "show/hide" keybind only appears for a labelled source. The view flips IWarpSource.NativeShown and re-materializes via WarpSources.Refresh.
IWarpSource.NativeShown Whether the game-provided entries are currently shown in this source's list.
IWarpSource.SelectorOptions Optional in-view option cycler shown while this source is active (routes offer the launch mode). Null/empty = no selector; the view renders "
IWarpSource.SelectorLabel What the selector chooses (e.g. "Mode") — the prompt's label prefix.
IWarpSource.SelectorIndex The selected option (index into IWarpSource.SelectorOptions); the view writes it as the player cycles.
IWarpSource.AddHere() Author a new destination at the climber's current spot. Returns true if one was added (the controller then rebuilds the list). No-op / false when unsupported.
Add items to and query the player's inventory.
Inventory.Add(id, count?) → AddResult Add items to the appropriate storage slot. Stops cleanly at capacity.
id | InventoryItemStringIdEnum | Item to add. |
count opt | int | How many to add. |
Inventory.Count(id) → int How many of an item the player currently holds.
id | InventoryItemStringIdEnum | Item to count. |
Inventory.StorageWeight(storage) → float Current total weight in a storage slot.
storage | StorageType | Which slot to query. |
Inventory.MaxBagWeight() → float The bag's weight capacity.
var result = Inventory.Add(InventoryItemStringIdEnum.Food_Nuts, 3);
if (!result.Ok) LogWarning(result.Error);
else Log($"Added {result.Added}");
int nuts = Inventory.Count(InventoryItemStringIdEnum.Food_Nuts);
float bag = Inventory.StorageWeight(StorageType.Bag); ItemGrid.Root The grid's root GameObject.
ItemGrid.Create(parent, entries, onConfirm, columns?, cellSize?, spacing?) Build a scrollable native item grid under parent. onConfirm fires with the entry index on click / gamepad Submit. Returns null when the native cell template isn't available yet.
parent | RectTransform | Content region to fill (e.g. a widget page host). |
entries | IReadOnlyList<ItemGridEntry> | The items (and count badges) to show, in grid order. |
onConfirm | Action<int> | Fires with the picked entry's index. |
columns opt | int | Cells per row (navigation math derives from this). |
cellSize opt | float | Cell edge in reference pixels; 0 = the cell's native authored size. |
spacing opt | float | Gap between cells. |
ItemGrid.Count Number of cells.
ItemGrid.FocusFirst() Focus the first cell (gamepad/keyboard nav anchors here).
ItemGrid.SetEntry(index, entry) Re-bind one cell to a different item/count in place.
index | int | |
entry | ItemGridEntry |
ItemGrid.Destroy() Tear the grid down. Safe to call more than once.
One grid entry: a game item and the count badge to show on its cell.
ItemGridEntry.Item The item to display.
ItemGridEntry.Count Count shown on the cell's native badge.
Per-item metadata.
ItemInfo.Id Enum identifier.
ItemInfo.Name Display name.
ItemInfo.StoredIn Which storage slot holds this item.
ItemInfo.MaxCount Maximum stack count.
ItemInfo.HasIcon True when the item ships real icon art (not the game's placeholder icon).
ItemInfo.Icon The item's icon sprite, shared by reference; null when the item ships no real art (the game's placeholder icon — see ItemInfo.HasIcon).
ItemInfo.UnitWeight Weight per unit. NaN for non-physical items.
A world site that yields inventory items when interacted with — a foraged plant, a cache, a bag, a multi-item container. Identified by the game's own stable per-node id, which is deterministic across launches and saves (it is the same key the game's save system uses to remember which pickups were consumed).
ItemLocation.Id Stable unique id of this location (the game's persistent provider id).
ItemLocation.Name Name of the GameObject hosting the pickup (diagnostic).
ItemLocation.SceneName Name of the scene the pickup lives in.
ItemLocation.Position World position of the pickup.
ItemLocation.Items The item yielded per slot, in slot order. Single pickups have one entry; containers have several.
ItemLocation.IsContainer True when the site holds more than one slot (opens the native item carousel).
ItemLocation.CanLoot Whether the site can currently be looted (not emptied, not gated).
World item-location API — enumerate every item pickup in the loaded world by stable id, and override what any of them yields (and the name shown at it). The foundation for randomizers: an override makes the site give — and label itself as — a different item, natively. Containers show the overridden items' icons in the game's own carousel automatically. Overrides are durable for the session: they are applied to live nodes immediately, re-applied automatically when a scene (re)loads or a save is loaded, and never touch the shared loot assets — only the one node. They are not written to the save file; re-register them each session (a seeded randomizer recomputes them anyway).
ItemLocations.Enumerate() Every item location in the currently loaded scenes. Only sites with a stable id (finite-stock pickups) are returned; infinite sources (e.g. bottomless bushes) are not item locations. Never throws; empty when no world is loaded.
ItemLocations.Find(id) The location with the given id, if it is loaded right now. Null otherwise.
id | ulong |
ItemLocations.Override(id, items, label?) Register a durable override: the location yields items (one per slot) and — for single pickups — shows label as its world-prompt name (defaults to the first item's own name). Applied now if the node is loaded, and re-applied whenever the game (re)creates it. Replaces any previous override for the same id.
id | ulong | |
items | InventoryItemStringIdEnum[] | |
label opt | LocKeyStringId? |
ItemLocations.OverrideSingle(id, item) Convenience for the common single-slot case; the prompt name follows the item.
id | ulong | |
item | InventoryItemStringIdEnum |
ItemLocations.ClearOverride(id) Remove the override for a location, restoring its original loot and label (takes effect immediately if the node is loaded).
id | ulong |
ItemLocations.ClearAll() Remove every registered override, restoring loaded nodes.
ItemLocations.OnLooted Fires on the main thread when any item location is actually looted: (location id, slot index, item taken). Slot is -1 when the game looted without a specific slot (e.g. "take all" / auto-fit paths). This is the "check" signal for randomizers.
ItemSlot.Root The cell's GameObject.
ItemSlot.Rect The cell's RectTransform (size it, or let a layout group drive it).
ItemSlot.Selectable The cell's uGUI Selectable — compose into navigation chains (ItemGrid does).
ItemSlot.AuthoredSize The cell's authored (prefab) size — the native footprint layout containers should honor.
ItemSlot.Create(parent, item, count?, onConfirm?) Create a native item cell under parent showing item. Hover selects; click / gamepad Submit fires onConfirm. Returns null when the native slot template isn't available (the game UI hasn't loaded).
parent | RectTransform | |
item | InventoryItemStringIdEnum | |
count opt | int | |
onConfirm opt | Action |
ItemSlot.SetItem(item, count?) Re-bind the cell to another item/count (the slot's own native Setup path).
item | InventoryItemStringIdEnum | |
count opt | int |
ItemSlot.Select() Move uGUI selection to this cell (fires the authored selection feedback).
ItemSlot.SetVisible(visible) Show/hide the cell without destroying it (the slot's native ToggleDisplay).
visible | bool |
ItemSlot.Destroy() Tear the cell down. Safe to call more than once.
Read-only catalog of every item in the game.
Items.All → IReadOnlyList Every item in the game (315 entries). Cached after first access.
Items.Get(id) → InventoryItem Resolve a single item config by enum id.
id | InventoryItemStringIdEnum | The item's enum identifier. |
foreach (var info in Items.All)
Log($"{info.Name} {info.StoredIn} {info.UnitWeight:F2}kg");
var rope = Items.Get(InventoryItemStringIdEnum.Rope_Standard); A text label in the game's own font. Prefer this over Ui.Label (a plain fallback font) for any text a player will see.
Label.Root The label's GameObject.
Label.Rect The RectTransform (sized by its parent layout or by you).
Label.Tmp The underlying TextMeshPro component, for advanced styling.
Label.GameFont The game's own TMP font asset; null until the game UI has loaded.
Label.Create(parent, text, fontSize?, color?, alignment?) Create a native-font label under parent. Fills the parent by default — re-anchor Label.Rect or let a layout group drive it. Returns null on failure (game UI not loaded yet).
parent | RectTransform | Where to attach. |
text | string | Initial text. |
fontSize opt | float | Point size (native menus use 26–38; headers up to 51). |
color opt | Color? | Text color; null = white (the native default). |
alignment opt | TextAlignmentOptions? | TMP alignment; null = centered. |
Label.SetText(text) Change the text.
text | string |
Label.SetColor(color) Change the text color.
color | Color |
Label.Destroy() Tear the label down. Safe to call more than once.
The local player's lamp (the glowing light stick). Its state is a three-way mode, not a bool: Auto (the game decides by darkness), ForceOn, ForceOff. Reads return null and writes return false when no pawn is up yet.
Lamp.Mode The local player's lamp mode, or null when no pawn is up.
Lamp.SetMode(mode) Set the local player's lamp mode through the lamp's own verb (visuals update immediately). Returns false when no pawn is up.
mode | AavaLightStick.Mode |
LevelDescriptor.LevelKind.GameWorld LevelDescriptor.LevelKind.Custom LevelLoader.CustomSessionLive A custom-level session is live — traveling into a custom level or its scene is resident.
LevelLoader.LaunchNonce Per-launch identity of the last MOD-INITIATED custom launch (the custom analog of Session.LaunchGuid). LevelLoader.CreateAndPlay's custom branch mints a fresh one at launch-fire; the launching mod captures it and compares on arrival to prove the gameplay that arrived is the launch it fired. CustomSessionLive alone is a CLASS check — a native Continue of a custom save arms the same session machinery — so the nonce narrows arrival to OUR launch. What keeps it honest: every save-READ while a launch is pending stands the whole launch down (SaveLoadCustomPatch — a mod launch never reads a save), so no Continue variant can be adopted; and quit-to-menu stands it down at residency end (OnSceneUnloaded), so nothing armed persists at the menu. The ONE remaining window: a player-initiated NEW GAME inside the wedge window (≤30s, the watchdog's bound) reads no save and resolves through the same armed new-game redirect — indistinguishable from our launch at the resolver — and is adopted.
The local climber's four limbs — resolution, state reads, and actions. Everything resolves through PawnManager.ClimbingPawnController, the same active-controller handle the game's own limb-selection HUD drives, so Limbs.LocalController is always the LOCAL pawn even in co-op (each remote ghost has its own controller and four limbs, which this never touches). All members are null-safe: they return null / false when there is no climbing session. Limbs are addressed by identity — IKLimbTarget (LeftHand / RightHand / LeftFoot / RightFoot), a ctor-set readonly enum on each limb that never drifts — via the controller's named-field accessors, the stable interop surface.
Limbs.LocalController The local player's active climbing controller, or null when not climbing. This is the game's own PawnManager.ClimbingPawnController: the local pawn, never a co-op ghost.
Limbs.LeftHand The local left-hand limb, or null when not climbing.
Limbs.RightHand The local right-hand limb, or null when not climbing.
Limbs.LeftFoot The local left-foot limb, or null when not climbing.
Limbs.RightFoot The local right-foot limb, or null when not climbing.
Limbs.Get(target) → ClimbingV2PawnLimb, or null. The local limb for a given target, or null when not climbing.
target | ClimbingPawnCairnIK.IKLimbTarget | Which limb — LeftHand, RightHand, LeftFoot, or RightFoot. |
Limbs.All → IReadOnlyList All four local limbs, in LeftHand, RightHand, LeftFoot, RightFoot order, skipping any that are null. Empty when not climbing.
Limbs.OppositeOf(limb) → The opposite ClimbingV2PawnLimb, or null. The same-kind opposite of a limb (left↔right within hand, or within foot), or null. Useful for auto-pickers that must never hand back the passed limb.
limb | ClimbingV2PawnLimb | The limb to mirror. |
Limbs.IsHolding(limb) → True if holding. True when the limb is gripping a hold (state == Holding). This is the game's load-bearing signal: the effort/stamina economy and every "is attached" predicate key on it.
limb | ClimbingV2PawnLimb | The limb to test. |
Limbs.IsActive(limb) → True if the limb is engaged rather than idle. True when the limb is in any active climbing state — reaching, holding, or moving to a hold (including the ice-climbing variants) — as opposed to Idle.
limb | ClimbingV2PawnLimb | The limb to test. |
Limbs.GrabNearbyHolds() → True if the grab was issued. Snap every idle/reaching limb onto the nearest reachable hold — the game's own ForceAllReachingAndIdleLimbsToGrab. Used to attach the climber to the wall after a bare climbing placement (a route start with no captured pose): the pawn arrives in climbing mode with limbs dangling, and this grabs the holds around them. No-op (returns false) when not climbing.
Limbs.Drop(limb) → True if a drop was issued. Force the limb to let go through the game's own Drop path — clears its current grab and routes it back to Idle. Local pawn only. No-op (returns false) if the limb is null.
limb | ClimbingV2PawnLimb | The limb to release. |
Localization.Register(english) Register english under English and hand back a loc key that renders it in EVERY language (English is the fallback for all). For plain or user-generated content (names, labels) that is not translated. Write the returned key wherever the game wants a LocKeyStringId and the game's own text pipeline renders this string there, durably.
english | string |
Localization.Register(byLanguage) Register a full per-language table and hand back a loc key. Language codes are upper-normalized (so "en" and "EN" are the same entry). The English entry is the fallback for any language not in the table; if the table has no English entry the first entry is used as the fallback.
byLanguage | IDictionary<string, string> |
Localization.Update(key, english) Replace the English / fallback text of a key returned by Localization.Register.
key | LocKeyStringId | |
english | string |
Localization.Update(key, lang, text) Set or replace the text for one language of a registered key (language code upper-normalized). A key not registered here is ignored.
key | LocKeyStringId | |
lang | string | |
text | string |
Localization.Unregister(key) Drop a registered key; the game falls back to its own resolution for that id afterward.
key | LocKeyStringId |
Localization.IsRegistered(key) True if key is one this facade resolves.
key | LocKeyStringId |
Built-in Lucide icon set (1964 icons), embedded as an indexed PNG blob and decoded to sprites on demand. Mods reference an icon by its Lucide name (e.g. "anchor", "flame", "mountain-snow"). Icons are white line-art on transparent — they tint cleanly over the menu's coloured wedge backgrounds. Pack format (little-endian): u32 count, then count × (u16 nameLen, name UTF-8, u32 dataLen) index, then the concatenated PNG bytes in index order.
LucideIcons.Names All available Lucide icon names (loads the index on first call).
LucideIcons.Has(name) True if the named icon exists in the bundle.
name | string |
LucideIcons.Get(name) Get the sprite for a Lucide icon name, decoding + caching on first use. Returns null if the name is unknown (caller falls back to a placeholder).
name | string |
The game's segmented stat bar (the character-menu vitals meter) as a mod widget.
Meter.Root The meter's GameObject.
Meter.Rect The RectTransform (authored size 361×31; resize or let a layout group drive it).
Meter.Create(parent) Create a native stat bar under parent. Returns null on failure (game UI not loaded yet).
parent | RectTransform |
Meter.Set(fill, preview?, low?, critical?) Set the meter. fill and preview are 0–1; preview shows a pending change (defaults to the fill value); low tints the fill, critical plays the critical state.
fill | float | |
preview opt | float | |
low opt | bool | |
critical opt | bool |
Meter.Destroy() Tear the meter down. Safe to call more than once.
var m = Meter.Create(hud.Content);
m.Set(0.75f); // value
m.Set(0.35f, low: true); // low-state tint
m.Set(0.10f, critical: true); // critical blink Modal.Confirm(message, onConfirm, onCancel?, confirmLabel?, cancelLabel?, title?) Show a two-button dialog. onConfirm fires when the player accepts, onCancel (if given) when they decline or dismiss. Game input is blocked while it's up. Returns false if the popup system isn't available yet or the call failed.
message | string | |
onConfirm | Action | |
onCancel opt | Action | |
confirmLabel opt | string | |
cancelLabel opt | string | |
title opt | string |
Modal.Info(message, onDismiss?, okLabel?, title?) Show a one-button acknowledgement dialog. onDismiss (if given) fires when the player dismisses it. Game input is blocked while it's up. Returns false if the popup system isn't available yet or the call failed.
message | string | |
onDismiss opt | Action | |
okLabel opt | string | |
title opt | string |
Modal.Reveal(item, title?, description?, onDismiss?) Show the game's item-reveal popup (the special-loot presentation: item render, title, flash effect, native accept prompt) for any game item. One-button acknowledge form — onDismiss fires when the player accepts or the popup dismisses. Returns false if the reveal surface isn't available.
item | InventoryItemStringIdEnum | The item to present. |
title opt | string | Heading; null = the item's own native title. |
description opt | string | Body text; null = the item's own native description. |
onDismiss opt | Action |
Modal.Reveal(item, title, description, onChoice, acceptLabel?, refuseLabel?) Show the item-reveal popup with the native accept / refuse choice. onChoice fires with true when accepted, false when refused.
item | InventoryItemStringIdEnum | |
title | string | |
description | string | |
onChoice | Action<bool> | |
acceptLabel opt | string | Accept-prompt label; null = the native default. |
refuseLabel opt | string | Refuse-prompt label; null = "Refuse" (the authored label belongs to the game's own resurrection flow). |
Programmatic new-game launch: start a fresh story-mode game (creating a new save) without walking the native menu screens. The exact endpoint the game's own New Game flow reaches — the difficulty/tutorial choices its screens collect are passed in instead.
NewGame.LaunchStory(difficulty, character?, skipTutorials?, skipPractice?) Launch a new story-mode game with the given difficulty and character, optionally skipping the tutorials and the practice wall. Returns a status string ("STORY_LAUNCH_INVOKED" on success); fire-and-return — the load runs natively.
difficulty | DifficultyTweakables.SelectedDifficulty | |
character opt | PawnManager.Character | |
skipTutorials opt | bool | |
skipPractice opt | bool |
The player's outfit (body + clothes skin). Outfits are authored PawnSkinData assets keyed by a small enum (PawnBodyAndOutfitSkinType: Default / IceClimbing / Pajamas / NoHood) in the pawn's skin database; applying one swaps meshes and materials on the character's renderers with bones rebound BY NAME — which makes the applier rig-portable: Outfit.ApplyToRig can dress any Aava-skeleton rig (the netplay ghost included), not just the local pawn. Reads return null and writes return false when no pawn is up.
Outfit.Current The local player's current outfit, or null when no pawn is up.
Outfit.Set(type) Switch the local player's outfit through the pawn's own verb (meshes and materials swap immediately). Returns false when no pawn is up, the type is unknown to the skin database, or the outfit is already current.
type | PawnBodyAndOutfitSkinType |
Outfit.ApplyToRig(type, skeletonRoot, bodyRenderer, outfitRenderer) Dress an arbitrary Aava-skeleton rig in type: the outfit's authored mesh, materials and bounds are copied onto the given body/outfit renderers with bones rebound by name against skeletonRoot's hierarchy — the game's own cross-rig skin worker. The skin data comes from the LOCAL pawn's skin database (always populated in gameplay). Returns false when no pawn is up or the type is unknown.
type | PawnBodyAndOutfitSkinType | |
skeletonRoot | Transform | |
bodyRenderer | SkinnedMeshRenderer | |
outfitRenderer | SkinnedMeshRenderer |
A container panel wearing the game's own authored chrome (see CairnAPI.PanelStyle). Build content under Panel.Content — it is inset past the chrome's drawn border.
Panel.Root The panel's GameObject.
Panel.Rect The panel's RectTransform (fills the parent by default; re-anchor or resize freely).
Panel.Content The content region, inset past the chrome's drawn border — build inside this.
Panel.Create(parent, style?, hat?) Create a native-chromed panel under parent. Fills the parent by default — re-anchor Panel.Rect or let a layout group drive it. Returns null on failure (game UI not loaded yet).
parent | RectTransform | Where to attach. |
style opt | PanelStyle | Which authored skin. |
hat opt | bool | Dialog only: also add the authored top-center crest decoration. |
Panel.Destroy() Tear the panel down. Safe to call more than once.
The authored chrome skins a CairnAPI.Panel can wear.
PanelStyle.Dialog The cream dialog-box background the game's popups use.
PanelStyle.Outline The border-only frame the in-game goals list uses.
A verbatim snapshot of the local climber's stance: locomotion mode, body/root world transforms, and all four limbs. Captured with Poses.TryCapture, re-applied with Poses.Restore. Pure floats and hold ids — embeds directly in JSON stores (bookmarks, route markers).
PawnPose.Mode Locomotion mode at capture (PawnControllerSwitcher.Mode; 2 = Climbing).
PawnPose.Body Body world transform, packed [px,py,pz, rx,ry,rz,rw].
PawnPose.Root Root-node world transform, packed [px,py,pz, rx,ry,rz,rw].
PawnPose.LeftHand The left-hand limb snapshot.
PawnPose.RightHand The right-hand limb snapshot.
PawnPose.LeftFoot The left-foot limb snapshot.
PawnPose.RightFoot The right-foot limb snapshot.
PawnPose.OnWall True when this pose was captured on the wall (climbing mode).
One limb of a captured pose: attachment state, IK end bone, grab anchor, and the hold it was on (for drift detection at restore). Pure floats — JSON-serializable, no scene references.
PawnPoseLimb.State The limb's attachment state (ClimbingV2PawnLimb.LimbState; 2 = on a hold).
PawnPoseLimb.End IK end-bone world transform, packed [px,py,pz, rx,ry,rz,rw].
PawnPoseLimb.Anchor Grab-anchor world transform, packed [px,py,pz, rx,ry,rz,rw].
PawnPoseLimb.Bend IK bend-goal world position [x,y,z].
PawnPoseLimb.SubBone Local sub-bone rotation (foot ball bone) [x,y,z,w].
PawnPoseLimb.HoldId Persistent id of the hold the limb was on, or 0 when unattached.
PawnPoseLimb.Attached True when this limb was captured gripping a hold.
A filled pill button — the style the game's dialog options and bivouac actions use.
PillButton.Root The button's GameObject.
PillButton.Rect The RectTransform (authored footprint 200×50; resize or let a layout group drive it).
PillButton.Selectable The underlying uGUI Selectable, for navigation wiring.
PillButton.Create(parent, label, onClick, glyphAction?) Create a pill button under parent. Click / Submit fires onClick. Returns null on failure (game UI not loaded yet).
parent | RectTransform | Where to attach. |
label | string | Button text. |
onClick | Action | Fired on click / Submit. |
glyphAction opt | InputAction | Optional input action whose keycap renders inside the left edge (see CairnAPI.Glyph). |
PillButton.Create(parent, label, onClick, icon) Create a pill button with a sprite icon (e.g. ItemInfo.Icon) inside the left edge.
parent | RectTransform | |
label | string | |
onClick | Action | |
icon | Sprite |
PillButton.SetLabel(text) Change the label text.
text | string |
PillButton.SetInteractable(interactable) Enable/disable interaction (native disabled tint).
interactable | bool |
PillButton.Select() Move uGUI selection to this button.
PillButton.Destroy() Tear the button down. Safe to call more than once.
var b = PillButton.Create(panel.Content, "Consume", OnConsume, Glyph.Action(GameAction.Confirm)); Outcome of a capture attempt — see Poses.TryCapture.
PoseCaptureStatus.Refused Capture refused: the climber is mid-move (reaching, mantling, on the rope), off every wall hold, in a transitional state, or absent.
PoseCaptureStatus.Grounded The climber is standing on the ground — a valid spot, but there is no wall pose to store (ground placement needs only a position).
PoseCaptureStatus.OnWall The climber is in a stable climbing stance — a verbatim pose was captured.
PoseCaptureStatus.Falling The climber is falling — nothing meaningful to capture.
Capture and restore the local climber's verbatim pose. A captured CairnAPI.PawnPose stores the exact stance — body position and which limbs grip which holds, where — so a route or bookmark can put the climber back into it (one-arm hangs included). Restore places the body immediately through the game's own state restore, then tightens each limb to its exact recorded anchor over the following frames; where the world no longer supports an anchor, the game's own nearby pick stays and the approximation is logged once.
Poses.TryCapture(pose, reason) Capture the local climber's current stance. PoseCaptureStatus.OnWall fills pose with the verbatim on-wall pose (body + all four limbs); PoseCaptureStatus.Grounded also fills pose, with just the body position/rotation (no limbs — standing on the ground has nothing else to capture, but the facing is still worth restoring verbatim rather than losing it to a bare position); PoseCaptureStatus.Refused and PoseCaptureStatus.Falling leave pose null and set reason (a limb mid-move, on the rope, no wall hold gripped, falling, no climber).
pose | PawnPose | |
reason | string |
Poses.CanCapture() True when a capture would succeed right now: standing on the ground, or a stable climbing stance (steady on the wall with at least one limb on a real hold). False while falling, reaching, mantling, or on the rope — use it to gate capture verbs live.
Poses.Restoring True while a restore's per-limb pass is still running.
Ask the player to type something: message, input line, confirm/cancel buttons, in the game's dialog chrome. Enter or the confirm button submits; cancel (or a replacing Show) discards. Keyboard-first — gamepads can press the buttons but have no on-screen keyboard.
Prompt.Show(message, onSubmit, confirmLabel?, cancelLabel?, initial?, onClosed?) Show the prompt. Returns false when the game UI isn't loaded yet.
message | string | The question, centered over the input line. |
onSubmit | Action<string> | Receives the typed text (may be empty) on confirm/Enter. |
confirmLabel opt | string | |
cancelLabel opt | string | |
initial opt | string | |
onClosed opt | Action | Fires exactly once when the prompt's UI is torn down, for ANY reason — confirm, cancel, Esc/B under the modal, or a replacing Prompt.Show. On the confirm path it fires as part of the close, just before onSubmit runs. |
Prompt.Close() Dismiss the open prompt, if any (no submit).
Prompt.IsOpen Whether a prompt is currently on screen.
The MonoBehaviour behind ProximityPrompt.Show. Polls Aava's distance to the anchor each frame: in range → shows a CairnAPI.WorldPrompt; out of range → hides it; pressing the glyph button while in range fires the callback.
ProximityInteractable.Destroy() Remove this prompt and its GameObject.
ProximityPrompt.Show(anchor, distance, text, glyph?, onInteract?) Show a CairnAPI.WorldPrompt over anchor while Aava is within distance of it. onInteract fires on the glyph's button while in range. Returns the component; call ProximityInteractable.Destroy to remove it.
anchor | Transform | |
distance | float | |
text | string | |
glyph opt | InputAction | |
onInteract opt | Action |
The MonoBehaviour behind ReachPrompt.Show / ReachPrompt.Create. Trigger-driven: a limb sensor reaching into our collider shows a CairnAPI.WorldPrompt; leaving hides it; pressing the glyph button while reaching fires the callback.
ReachInteractable.Destroy() Remove this prompt and its GameObject.
ReachPrompt.Show(anchor, text, glyph?, onInteract?, radius?, localOffset?, hands?) Attach a reach prompt to a MOVING anchor (e.g. the climbot, an NPC, a carried prop). Parented to the anchor, so it tracks it automatically — pass the transform of the thing the player reaches toward. Shows a CairnAPI.WorldPrompt with text + glyph while a limb is REACHING into radius; onInteract fires on the glyph's button while reaching. localOffset shifts the trigger from the anchor's pivot to the actual grab point. hands true = only hands trigger it; false = any limb.
anchor | Transform | |
text | string | |
glyph opt | InputAction | |
onInteract opt | Action | |
radius opt | float | |
localOffset opt | Vector3 | |
hands opt | bool |
ReachPrompt.Create(position, text, glyph?, onInteract?, radius?, hands?) Spawn a reach prompt at a FIXED world position (a lever, a wall panel — something that doesn't move). For anything that moves, use ReachPrompt.Show instead.
position | Vector3 | |
text | string | |
glyph opt | InputAction | |
onInteract opt | Action | |
radius opt | float | |
hands opt | bool |
The single Il2Cpp-injected UI.CrossMenuActionHandler subclass. The game's CrossMenuUI stores one handler per CrossMenuActionType in its handlers dictionary and dispatches OnExecute/IsAvailable/ GetCount through the native vtable. We register ONE managed subclass and give each instance a synthetic type-int; the virtual overrides route to the managed CairnAPI.Registry by that int, so consumer mods never touch Il2Cpp. This is the load-bearing assumption of the whole library: that a native vtable call into the game's handler dict reaches these managed overrides. Proven shaped-correct live (base exposes an (IntPtr) injectable ctor and OnExecute is virtual); end-to-end dispatch is exercised by the in-game smoke test.
RoutingHandler.TypeValue The synthetic CrossMenuActionType int this instance answers for. Set right after construction (managed-side field; not visible to Il2Cpp, which is fine — only our overrides read it).
SaveSlotList.Root The list's root GameObject.
SaveSlotList.Create(parent, onPick, filter?) Build a native save-slot list under parent from the game's cached Story-save previews (title-screen context — the same source the native save select reads). onPick fires with the row index and its preview on click / Submit. filter (optional) keeps only matching previews. Returns null when no previews are cached (not at the title screen yet) or the row template is unavailable.
parent | RectTransform | |
onPick | Action<int, SavegameManager.SavePreviewInfo> | |
filter opt | Func<SavegameManager.SavePreviewInfo, bool> |
SaveSlotList.Count Number of rows.
SaveSlotList.FocusFirst() Focus the first row (gamepad/keyboard nav anchors here).
SaveSlotList.Destroy() Tear the list down. Safe to call more than once.
Screen.GameState GlobalGameManager.GameState enum value at the top of the state stack.
Screen.IsMenu The main menu system is active (GameState stack contains Menu).
Screen.IsInGame Gameplay is active (GameState stack contains InGame). This is true even when the pause menu or bivouac is on top.
Screen.IsCutscene A cutscene is playing (GameState stack contains Cutscene).
Screen.IsGameOver The game-over screen is up (GameState stack contains GameOver).
Screen.IsBivouac The bivouac rest menu is active (GameState == Bivouac).
Screen.PawnSpawned The pawn (Aava) is spawned in the world — the real "we are in live gameplay" test. Unlike LoadingState.GameStarted this is not sticky across menu returns.
Screen.LoadingState The game's detailed load pipeline stage. ⚠ Sticky: retains its last value (e.g. GameStarted=8) after returning to the menu. The authoritative "fully in gameplay" signal is PawnSpawned, not GameStarted.
Screen.IsTransitioning A cross-world / cross-zone / menu scene transition is in flight.
Screen.IsLoadingMenu Specifically a game→menu transition is in flight (subset of IsTransitioning).
Screen.CurrentMenu The foremost open Menu canvas, or null. Changes only at UIManager.OnMenuClosed / OnMenuStacked — observe via OnMenuChanged if you need a callback.
Screen.OnGameStateChanged Fires whenever GlobalGameManager.GameState changes. Arguments: (from, to). Sourced from GameEventManager.ChangeGameState — fires for every push/pop and direct set.
Screen.OnMenuChanged Fires when UIManager.CurrentMenu changes (a menu opens or the foreground menu closes). Argument is the NEW current menu (null when the stack empties).
Screen.OnCanvasOpened Fires when any BasicCanvasHandlerBehaviour finishes opening (OnOpened). Fires for menus AND HUDs. Cast the argument to check the concrete type.
Screen.OnCanvasClosed Fires when any BasicCanvasHandlerBehaviour finishes closing (OnClosed). Fires for menus AND HUDs. Cast the argument to check the concrete type.
Screen.OnTransitionStarted Fires when a game→menu or menu→game scene transition starts. Sourced from CairnSceneManager.OnGameUnloadingAboutToStart.
Screen.OnTransitionCompleted Fires when a scene transition completes and all new scenes are ready. Sourced from CairnSceneManager.OnGameScenesReady.
Screen.OnEnteringMenu Fires specifically when entering the main menu scene (game→menu path only), just before the menu scene itself loads. CairnSceneManager.OnPreparingToLoadMenu.
ScreenPrompt.Show(text, glyph?, parent?) Show a screen-space prompt. text is shown as-is, glyph is the button icon (see CairnAPI.Glyph, null = none). If parent is null the row goes under a mod-owned overlay Canvas — place it with ScreenPrompt.Move; if given, the row is parented there (self-sizes for a HorizontalLayoutGroup). Returns a handle, or ScreenPromptHandle.Invalid if a required game asset isn't loaded yet.
text | string | |
glyph opt | InputAction | |
parent opt | Transform |
ScreenPrompt.Move(handle, anchoredPos) Place an own-Canvas prompt anywhere on screen (its RectTransform's anchoredPosition). No-op for a prompt parented into your own layout (let the layout group place it).
handle | ScreenPromptHandle | |
anchoredPos | Vector2 |
ScreenPrompt.SetText(handle, text) Change a live prompt's text in place (set once; persists with no pump).
handle | ScreenPromptHandle | |
text | string |
ScreenPrompt.SetActive(handle, active) Show / hide the prompt (a layout group re-flows around a hidden one). Cheap — no re-register.
handle | ScreenPromptHandle | |
active | bool |
ScreenPrompt.Hide(handle) Destroy the prompt. Safe on an invalid handle.
handle | ScreenPromptHandle |
Opaque handle to a shown CairnAPI.ScreenPrompt. Pass it back to ScreenPrompt.Hide.
ScreenPromptHandle.Invalid A no-op handle returned when a required asset / the HUD wasn't available.
ScreenPromptHandle.SetActive(active) Show / hide the prompt (the layout group re-flows around a hidden one).
active | bool |
ScreenPromptHandle.Destroy() Destroy the prompt GameObject. Idempotent; on an already-dead row it just invalidates.
A global keybind acting on the selected row — the same cross-device InputSystem.InputAction (build one with Glyph.Custom) both renders the prompt-strip glyph and, polled, fires the verb. See ScrollList.SetKeyActions.
ScrollList.KeyAction.Label Prompt-strip label (e.g. "Rename").
ScrollList.KeyAction.Action Cross-device action — glyph AND trigger.
ScrollList.KeyAction.OnPerformed Runs with the selected row index when the action fires.
ScrollList.KeyAction.EnabledFor Per-row gate; null = every row. Returning false hides the strip prompt and swallows the key on that row.
One row: its label plus optional trailing action pills rendered inside the row's right edge. A row with actions treats click/Submit as "focus my first pill" (the verbs live there); a plain row fires the list's onConfirm.
ScrollList.Row.Value Right-aligned dim metadata column (e.g. a best time); null = none. Ignored on a row with Row.Actions — a pill tray owns the right edge.
A trailing pill on a ScrollList.Row (native pill chrome, disabled tint when off).
A scrollable, selectable list of text rows in the game's own visual language — each row is the native free-roam warp-point row (ordinal + label + selection band), Instantiated from the game's prefab and driven through its own bind method, hosted in a masked scroll view that auto-follows the selection. Handle-object: ScrollList.Create builds it under a parent (e.g. a MenuScreen.AddWidgetPage content area), ScrollList.Destroy tears it down. Rows navigate with the native Selectable chain (keyboard/gamepad), select on hover, and fire onConfirm(index) on click or Submit.
ScrollList.Create(parent, items, onConfirm) Build a scroll list filling parent. items are the row labels; onConfirm receives the row index on click or Submit. Rows are always the game's own warp-list rows: read from memory when their bundle is loaded (any gameplay context), else the owning prefab is asset-loaded through the game's Addressables (works on the title screen too).
parent | RectTransform | |
items | IReadOnlyList<string> | |
onConfirm | Action<int> |
ScrollList.Create(parent, items, onConfirm?) Build a scroll list of ScrollList.Rows — labels with optional trailing action pills.
parent | RectTransform | |
items | IReadOnlyList<ScrollList.Row> | |
onConfirm opt | Action<int> |
ScrollList.Valid True once built and still alive.
ScrollList.Cursor Index of the currently-selected row, or -1 when none of ours is selected.
ScrollList.SetItems(items) Replace the row labels. Rows are rebuilt to the new count; loc keys are reused per slot so repeated refreshes (e.g. a lobby list poll) don't grow the localization registry.
items | IReadOnlyList<string> |
ScrollList.SetItems(items) Replace the rows (labels + trailing action pills). Same slot-key reuse as the string form.
items | IReadOnlyList<ScrollList.Row> |
ScrollList.Count Number of rows currently shown.
ScrollList.TopRow The current top (first) row's Selectable (null when empty) — for wiring an outside widget's down-navigation INTO the list (so descending from a control above lands on the list, not past it).
ScrollList.BottomRow The current bottom row's Selectable (null when empty) — for wiring an outside widget's up-navigation back into the list.
ScrollList.SetNavigationOutside(before, after) Wire the list's outside neighbours. before = the control above/left (selectOnLeft on every row, selectOnUp on the first row); after = the control below/right (selectOnRight on pill-less rows — on pill rows the last pill's selectOnRight — plus selectOnDown on the last row). Null = that edge stays dead. Persisted — ScrollList.SetItems row rebuilds re-apply it.
before | Selectable | |
after | Selectable |
ScrollList.SetKeyActions(actions) Selected-row keybinds with a bottom glyph-prompt strip. Each ScrollList.KeyAction is polled while a row is selected (no modal up, no focused text field): the first enabled action whose cross-device KeyAction.Action fired this frame runs KeyAction.OnPerformed with the row index — one per frame. The strip shows one glyph+label per action (hidden per-row by KeyAction.EnabledFor) and follows selection. Persisted across ScrollList.SetItems; null/empty clears.
actions | ScrollList.KeyAction[] |
ScrollList.SetConfirmPrompt(label) Add a display-only prompt to the strip for the game's Confirm action (Submit = go). Null removes it.
label | string |
ScrollList.SetPromptHost(host) Render the keybind prompt strip inside host — a layout band the consumer owns (e.g. below the list frame) — instead of a reserved band inset into the list's own viewport. Null returns it to the in-list band. A live strip relocates. Set this before ScrollList.SetKeyActions for no churn.
host | RectTransform |
ScrollList.Select(index) Move UI focus to a row by index (clamped; no-op when empty).
index | int |
ScrollList.FocusFirst() Focus the first row (the CairnAPI.IMenuWidget page-open hook).
ScrollList.Destroy() Tear the list down and invalidate the handle. Safe to call more than once.
ScrollList.Tick() Per-frame pump for every live list's keybind polling + prompt strip — call once from OnUpdate.
The mod-launched gameplay-session lifecycle. A mod that launches its own session (summit run, custom level) arms this at launch-fire with Session.Begin; the session ends when the game is back at the title menu. Consumers gate session-scoped surfaces (pause entries, verbs, world mutations) on Session.Active/Session.Owner and reset per-session state from Session.Ended.
Session.Active A mod-launched session is live (armed at launch, cleared at the title menu).
Session.Owner The mod that launched the active session, or null.
Session.Ephemeral The active session is save-less: while it runs (pawn spawned), every save the game attempts is refused through the game's own CanSave gate — no save file is created or touched, and the player's save list is unaffected. Armed only by the ephemeral launch surface (LevelLoader.PlayEphemeral); cleared when the session ends.
Session.LaunchGuid Identity of the GameSetup the owning launch planted (its freshly-minted guid), for arrival verification: compare against GameSetup.GetCurrentGameSetup().guid once gameplay is up to prove the arrived session is the launched one. Null for launches without a planted setup.
Session.Ended Raised once when the active session ends (title menu reached, or the early menu-transition signal). Subscribers are isolated: one throwing handler cannot starve the others.
Session.ReachedGameplay The session has reached gameplay (pawn spawned at least once since launch). Latched — stays true through in-session despawn windows (retry reloads, travel) until the session ends.
Session.CurrentSetupGuid() The guid of the live session's GameSetup (every setup ctor mints a fresh one — a per-launch identity), or null while unreadable / still all-zeros. Compare with Session.LaunchGuid.
Session.Begin(owner) Arm the session at launch-fire time — call immediately after the launch mechanism has actually been invoked, before gameplay arrives.
owner | string |
Session.Cancel(reason) End the active session from the owning mod's side — for when the owner determines the gameplay that arrived is not the session it launched (identity check failed). Raises Session.Ended exactly like a natural end.
reason | string |
SettingsPage.Refresh() Re-run the page builder and show the result without leaving the page.
SettingsPage.SetFields(fields) Replace the page's visible rows with fields without leaving the page. Safe to call from inside a field callback — the swap is deferred to the next frame so the row that raised the event is not torn down mid-dispatch.
fields | Field[] |
SettingsPage.Dispose() Remove the rail entry. Pages normally live for the mod's lifetime.
Stamina.AddEffortScale(key, scale) Register (or replace) a global effort cost multiplier. Applied uniformly to all limbs via CurrentEffortCostMultiplier. 1.0 = no effect.
key | string | |
scale | float |
Stamina.RemoveEffortScale(key) Remove a registered global effort scale.
key | string |
Stamina.AddEffortScaleProvider(key, provider) Register (or replace) a per-limb effort scale provider. Callback receives the limb and returns a multiplier for that limb's CurrentEffortCostMultiplier. 1.0 = no effect.
key | string | |
provider | Func<ClimbingV2PawnLimb, float> |
Stamina.RemoveEffortScaleProvider(key) Remove a registered per-limb effort scale provider.
key | string |
Stamina.AddDrainScale(key, scale) Register (or replace) a global drain speed multiplier. Applied to every limb's _CurrentStaminaConsumptionSpeed after UpdateStaminaState computes it. Only scales positive (draining) values; gaining limbs are not affected. 1.0 = no effect.
key | string | |
scale | float |
Stamina.RemoveDrainScale(key) Remove a registered global drain scale.
key | string |
Stamina.AddDrainScaleProvider(key, provider) Register (or replace) a per-limb drain speed scale provider. Callback receives the limb and returns a multiplier for that limb's drain rate. Only applied when the limb is draining (consumptionSpeed > 0). 1.0 = no effect.
key | string | |
provider | Func<ClimbingV2PawnLimb, float> |
Stamina.RemoveDrainScaleProvider(key) Remove a registered per-limb drain scale provider.
key | string |
Stamina.Package The live ClimbingTweakablesPackage.Stamina for the local pawn. Fields: baseStamina, staminaGainSpeed, staminaLossSpeed, staminaLossCurve, criticalStaminaStateDuration, punishedCriticalStaminaStateDuration, effortExhaustionThreshold, handRestThreshold, footRestThreshold, handFreeEffortThreshold, footFreeEffortThreshold. Null if not in a session or the package isn't loaded.
Where AND how the pawn stands: a world position + facing + locomotion mode, or a verbatim captured pose (CairnAPI.PawnPose — on-wall stances), or the level's default spawn (Stance.Spawn). This is the destination TYPE handed to Teleport.To and Travel.To; placement itself is owned by the teleport pipeline (session gate → zone-ensure → readiness → place → arrive), never applied directly by callers.
Stance.Position Target world position (ignored when Stance.Pose is set — the pose carries its own).
Stance.Facing World forward to face on arrival; degenerate values fall back to +Z.
Stance.Mode Locomotion mode to arrive in (Walking / Climbing).
Stance.Pose Verbatim stance (a CairnAPI.Poses capture). When set, the pose restore owns placement.
Stance.Spawn The level's default spawn — where THIS session's pawn first spawned, placed through the game's own spawner verb (mode, on-wall start, climbbot handling reproduced natively). A shared sentinel; do not mutate its fields.
Stance.IsSpawn True when this is the Stance.Spawn sentinel.
Stance.TargetPosition Where this stance puts the pawn (a pose carries its own body position; the spawn sentinel resolves to the session's default spawn).
TabBar.Root The rail's root GameObject (a vertical column; size it via its RectTransform).
TabBar.Create(parent, labels, onPicked, onSelected?) Build a native selection rail under parent with one entry per label. onPicked fires with the entry index on click / gamepad Submit. onSelected (optional) fires when the highlight moves (hover / gamepad nav). Returns null when the game UI isn't up yet (no chevron/highlight assets to decorate with).
parent | RectTransform | |
labels | IReadOnlyList<string> | |
onPicked | Action<int> | |
onSelected opt | Action<int> |
TabBar.Valid True once built and still alive.
TabBar.Select(index) Move the native highlight (chevron + text slide) to an entry, as gamepad nav would.
index | int |
TabBar.FocusFirst() Focus the first entry (gamepad/keyboard nav anchors here).
TabBar.SetActiveTab(index) Pin an entry as the active tab (the picked-page look: highlight held while the selection roams). Picking an entry pins it automatically; -1 clears the pin.
index | int |
TabBar.ActiveTab The pinned tab's index (-1 when none is pinned yet).
TabBar.Destroy() Tear the rail down. Safe to call more than once.
THE move-the-pawn-within-this-session verb. Applies a CairnAPI.Stance to the local climber through one frame-ticked pipeline: session gate (wait for the pawn if a load is in flight) → zone-ensure (stream the destination's own sector) → readiness (settle + on-wall holds) → place (the fall-safe switcher transition / pose restore / native spawner, never a raw transform write) → arrive. One job is pending at a time; a new call supersedes it, and the session ending cancels it. A same-zone ground teleport collapses synchronously — TeleportOptions.OnArrived runs before Teleport.To returns. Cross-LEVEL travel is Travel.To, which lands the new session and then hands the arrival to this same pipeline.
Teleport.Pending A teleport (or a Travel launch riding this pipeline) is in flight.
Teleport.To(destination, opts?) Move the local climber to destination. Returns "OK" once the job is issued (or completed synchronously), "NOT_IN_SESSION" when there is no world at all, "TRAVEL_IN_FLIGHT" when a cross-level launch owns the slot, or "NO_STANCE" for a null destination. Supersedes any pending plain teleport.
destination | Stance | |
opts opt | TeleportOptions |
Teleport.Cancel() Cancel the pending job without firing its arrival callback. Refuses (no-op) when a Travel launch owns the slot — symmetric with Teleport.To's refusal, so a session-scoped caller (a Boulderdash run teardown) can never destroy an in-flight cross-level launch and strand it. Travel / session teardown that legitimately abandons the journey goes through Teleport.CancelAny.
Options for Teleport.To.
TeleportOptions.Placement When the stance is applied: TeleportPlacement.WhenReady (default) waits for the destination to settle (and, for an on-wall stance, for the holds to stream in) before placing; TeleportPlacement.Immediate places at once (for callers holding their own freeze) — but TeleportOptions.OnArrived still defers to readiness. Placement and arrival are separate edges.
TeleportOptions.BeforePlaced Runs on the same frame, immediately before the stance applies — for callers that must prepare the world first (e.g. freeze time so an on-wall placement doesn't fall while the holds subscene is still streaming). The stance is NOT applied yet when it runs.
TeleportOptions.OnArrived Runs when the destination is REAL: settled, and (for an on-wall stance) the holds have arrived. The stance is already applied when it fires.
TeleportOptions.OnFailed Runs when placement fails: Stance.Apply reported failure twice (once retried on the next tick). The job is cancelled before this fires; TeleportOptions.OnArrived will NOT run. Callers holding their own freeze wire this to stand it down.
Whether a CairnAPI.Teleport places the stance immediately or waits for the destination to be ready.
TeleportPlacement.WhenReady Wait for the destination to settle (and its holds, on-wall) before placing.
TeleportPlacement.Immediate Place at once, before readiness — for callers parking the pawn under their own freeze.
Show a message as one of the game's own corner toasts. In-game surface (GlobalUIs) — returns false when it isn't loaded (main menu very early, or no scene).
Toast.Show(text, icon?, background?, foreground?) Queue a toast. Optional icon and background/foreground tints ride the native toast fields; omitted = the toast's authored defaults.
text | string | |
icon opt | Sprite | |
background opt | Color? | |
foreground opt | Color? |
THE go-to-a-LEVEL verb, keyed by level + CairnAPI.Stance, valid from anywhere. Resolves "where is the player right now" itself so callers never branch on it: • already on the level (and no TravelOptions.Fresh) → hand off to Teleport.To in place (no reload, no loading screen), returns "SAME_MAP"; • else, an TravelSession.Ephemeral launch (default) → a NEW save-less session honoring difficulty/character, returns "FRESH_SESSION"; • else, a TravelSession.Preserve launch → native change-level travel with the session/save intact, returns "PRESERVE". A launch that lands hands its arrival to the SAME teleport pipeline (zone-ensure → readiness → place → arrive), so TravelOptions.BeforePlaced/TravelOptions.OnArrived fire from there. Returns the launch funnel's failure reason otherwise.
Options for Travel.To. Difficulty/character/owner shape the NEW session an Ephemeral launch starts; a same-map hop and a Preserve launch ignore them.
TravelOptions.Arrival Arrival stance; null = the level's default spawn.
TravelOptions.ArrivalZoneName Zone known to own the arrival position, captured when it was recorded; lets a menu launch load the destination's own zone when live resolution is impossible (at the title menu no zone colliders are registered, so a position→zone probe always fails and falls back to the entry zone).
TravelOptions.Fresh Force a NEW session even when already on the level (e.g. a mode/character change).
TravelOptions.Session Whether the launch starts a fresh save-less session (TravelSession.Ephemeral, default) or preserves the running session and its save (TravelSession.Preserve).
TravelOptions.Difficulty New-session difficulty (TravelSession.Ephemeral only).
TravelOptions.Character New-session character (TravelSession.Ephemeral only).
TravelOptions.Owner Session owner (Session.Owner of a launched ephemeral session).
TravelOptions.Placement Placement timing handed to the arrival's teleport pipeline (see CairnAPI.TeleportPlacement).
TravelOptions.BeforePlaced Fires right before the arrival stance is applied, on the same frame (e.g. freeze time so an on-wall start doesn't fall while the holds subscene is still streaming). Not applied yet when it runs.
TravelOptions.OnArrived Runs once the pawn stands on the destination — same call for a same-map hop, after arrival + settle (+ on-wall holds) for a launch. The stance is already applied when it fires.
TravelOptions.OnFailed Runs when the arrival placement fails (see TeleportOptions.OnFailed). The journey is cancelled before it fires; TravelOptions.OnArrived will NOT run.
Whether a CairnAPI.Travel launch starts a fresh save-less session or preserves the running one.
TravelSession.Ephemeral A NEW save-less session: no save is created or touched, and it ends at the title menu.
TravelSession.Preserve The running session and its save are kept — native change-level travel (a member warp, story progression), session and save intact.
Survival axes a CairnAPI.Vitals freeze can cover. Combine flags for a subset; VitalAxes.All freezes everything.
VitalAxes.None No axes.
VitalAxes.Hunger Hunger decay.
VitalAxes.Thirst Thirst decay.
VitalAxes.Cold Cold decay.
VitalAxes.Hp Hit points — over-time decay, damage (falls included), and any write that would lower HP.
VitalAxes.Exhaustion Exhaustion buildup from climbing exertion.
VitalAxes.Stamina Climbing limb stamina drain (regen is unaffected).
VitalAxes.All Every axis.
Freeze survival drain and stamina for the local pawn. Freezes are named so multiple mods coexist: an axis stays frozen while any registered key covers it, and the game's normal drain resumes when the last such key is removed.
Vitals.AddFreeze(key, axes?) Register (or replace) a named freeze covering the given axes. Frozen stats stop draining and cannot be lowered (damage included); raising writes — eating, drinking, warming, healing — still apply.
key | string | |
axes opt | VitalAxes |
Vitals.RemoveFreeze(key) Remove a registered freeze. Axes no longer covered by any key thaw and the game's own drain multipliers are restored.
key | string |
One destination a CairnAPI.IWarpSource contributes to the eagle-eye warp list: a named world position with an opaque payload the source recognizes on confirm/edit.
WarpEntry.Position The destination's world position (where the pin sorts and where confirm places the pawn).
WarpEntry.Name The row label shown in the eagle-eye list.
WarpEntry.Payload The source's own object behind this entry (a Bookmark, a Route, …) — passed back on confirm/edit.
Materializes the ACTIVE CairnAPI.IWarpSource's destinations as live Cairn.FreeRoamWarpPoints in the eagle-eye list, and routes selection back to the owning source (bypassing the native warp). Mods register sources; a toggle cycles which one the list shows. The materialization lifecycle (register on gameplay load, re-anchor on zone change, stand down before a scene unload) is the proven bookmark pattern, source-agnostic here.
WarpSources.Register(source, primary?) Register a warp source. Pass primary for the built-in default-active source (bookmarks) so it stays the active list regardless of mod load order; others append.
source | IWarpSource | |
primary opt | bool |
WarpSources.Active The active source (whose destinations the eagle-eye list currently shows), or null.
WarpSources.Count How many sources are currently AVAILABLE (a toggle is meaningful only when > 1) — an unavailable source (routes outside a Boulderdash session) is invisible here.
WarpSources.NextLabel() The label of the next AVAILABLE source WarpSources.Toggle would switch to, or null when fewer than two are available — for a "Show
WarpSources.Toggle() Cycle to the next AVAILABLE source and re-materialize its destinations. The open eagle-eye list re-pulls its rows via the Bookmarks.OnRegistryChanged subscription.
WarpSources.Invalidate() Force a re-materialize of the active source's destinations (call after its entries change).
WarpSources.Refresh() Immediately re-materialize the active source and tell an open list to re-pull — for in-view state flips (the native-entries toggle) where the player is looking at the list and a deferred settle would read as a dead keybind.
WarpSources.TryResolve(wp, source, entry) Resolve a live warp point back to its owning source + entry, or false for a point that isn't one of ours (a native destination — let the native warp run).
wp | FreeRoamWarpPoint | |
source | IWarpSource | |
entry | WarpEntry |
WarpSources.LocKeyOf(payload) The live loc key rendering a materialized entry's row (for in-view live-rename via Localization.Update), or default when it has no live point.
payload | object |
WarpSources.RefreshName(payload, newName) Live-rename a materialized entry's row without a rebuild (matches by payload identity).
payload | object | |
newName | string |
WarpSources.Despawn(payload) Tear down one materialized entry: unregister, drop its loc key, destroy its GO.
payload | object |
The weather machine, read and driven through the game's own systems. Weather is a per-zone state machine: a forecast of WeatherZoneData.WeatherType states, each bundling rain/thunder/fog/clouds components and a duration. Some zones drive weather from an authored time table instead — there weather is a pure function of the game clock (Weather.IsTableDriven), so change the CairnAPI.Clock to change the sky and Weather.Set declines. All reads fail soft (Undefined / zero) when the weather system isn't up yet, e.g. on the title screen.
Weather.Current The live weather state (forecast slot 0), or Undefined when no weather system is up.
Weather.Forecast The forecast (slot 0 = live state, later slots = the barometer's future). Empty when unavailable.
Weather.RemainingSeconds Seconds until the live weather state expires (counts down).
Weather.DurationSeconds Total duration of the live weather state, in seconds.
Weather.IsTableDriven Whether the current weather zone derives its weather from an authored time table instead of the forecast. In table zones weather is a pure function of the game clock — change the CairnAPI.Clock to change the sky; Weather.Set declines.
Weather.Changed Raised when a weather state is applied (state changes, zone changes, save loads), with the new live WeatherZoneData.WeatherType.
Weather.Set(type) Switch the live weather to type, resolved against the current zone's authored definitions and applied through the weather machine's own trigger — modules transition naturally and the forecast keeps advancing afterwards (nothing is latched). Returns false when the zone is table-driven, the zone can't express the type, or no weather system is up.
type | WeatherZoneData.WeatherType |
Weather.ApplySnapshot(types, remainingSeconds, durationSeconds) Apply a full weather snapshot — forecast types plus the live state's countdown — the way the game's own save-load does: each type is resolved against the LOCAL current zone, the trigger fires only when the live state actually changed, and the timer/duration are restored last. This is the replication verb (CairnCoop's world sync rides it); Weather.Set is the one-shot flavor. Returns false when nothing could be applied (table zone, no weather system, or slot 0 unresolvable in this zone).
types | WeatherZoneData.WeatherType[] | |
remainingSeconds | float | |
durationSeconds | float |
Weather.Rain The live state's rain component (None / Rain_Small / Rain_Heavy).
Weather.Thunder The live state's thunder component (None / Thunder_Far / Thunder_Close).
Weather.Fog The live state's fog component (None / Fog_InsideCloud).
Weather.Clouds The live state's clouds component (None / Clouds_Small / Clouds_Heavy).
Weather.SnowIntensity Live snow intensity, 0..1 (precipitation renders as snow at altitude/temperature).
Weather.SnowInsteadOfRain01 How far precipitation currently leans to snow instead of rain, 0..1.
Weather.ForcePrecipitation(mode) Force precipitation to render as snow or rain regardless of altitude/temperature, or None to restore the game's own choice.
mode | WeatherManager.SnowRainForceMode |
Weather.WindForce Live wind strength (the value gameplay and cloth react to).
Weather.WindGust Live gust multiplier layered on Weather.WindForce.
Weather.WindDirection Live wind direction (normalized, world-space).
Weather.BarometerScore The barometer's current score, 0 (storm) .. 1 (clear) — what the in-game barometer shows.
Weather.ForceFog(opacity, expOffset?, distOffset?) Force a fog layer over everything (opacity 0..1), independent of the weather state — the game's own forced-fog lever (it uses it on the avalanche summit). Call Weather.ClearForcedFog to release it.
opacity | float | |
expOffset opt | float | |
distOffset opt | float |
Weather.ClearForcedFog() Release the forced fog layer set by Weather.ForceFog.
World.Current The active world the StreamingManager is currently streaming, or null pre-gameplay.
World.CurrentMapKey The identity key of the current map — a shipped mountain's world name (e.g. "Kami"), or a custom level's "cml:" address. Null when not in a level. Map-bound data (bookmarks, routes) binds to this.
World.MapKeyOf(level) The identity key a level will have once loaded — the same rule as World.CurrentMapKey, resolved from the descriptor instead of the live world. Null for a null descriptor.
level | LevelDescriptor |
World.DefaultSpawnPosition Where this session's pawn first spawned — the level's default spawn (the switcher's SpawnedFrom). Null off-gameplay. Session-relative by design: it works in ANY session, not just a mod-launched one.
World.Worlds() Every authored world, resident even when only one is streamed (from StreamingTweakables).
World.Zones(world) Every zone of a world (its authored ZoneSceneData list).
world | WorldZoneData |
World.ResolveZone(world, zoneName) Find a zone by its asset name (e.g. "01_FirstRidge") within a world.
world | WorldZoneData | |
zoneName | string |
World.WorldOf(zone) The world that owns a zone (by identity scan over the catalog), or null.
zone | ZoneSceneData |
WorldPrompt.Show(anchor, text, glyph?, canInteract?, style?) Float a prompt over anchor. text is shown as-is, glyph is the button icon (see CairnAPI.Glyph, null = none). style tunes the float distance / wall-stick and whether it follows a moving anchor (null = the close default, ~1/3 of the game's wall-mount distance — live-tuned). Returns a handle for WorldPrompt.Hide. This drives our OWN widget, so a new Show replaces the previous mod prompt on it (one mod world prompt at a time); the game's own world prompts are untouched.
anchor | Transform | |
text | string | |
glyph opt | InputAction | |
canInteract opt | bool | |
style opt | WorldPromptStyle |
WorldPrompt.Hide(handle) Remove a world prompt. Safe on an invalid / already-hidden handle.
handle | WorldPromptHandle |
WorldPrompt.Ui OUR OWN world-prompt widget — a lazily-BUILT WorldGameplayPromptUI (from scratch, no clone), so a mod prompt coexists with the game's own in-world prompts instead of clobbering the single shared widget. Null before in-game UI init (the build needs the game's fonts/materials/sprites loaded).
WorldPromptBuilder.WorldTextStyle(tmp) Configure a world-prompt TMP so PLAIN text (written by us or the glyph component) routes to a TMP_SubMeshUI and renders through the after-image pass: fontStyle=Bold → Boxed-DemiBold SDF (index ≥1). A component-level property, so it survives the glyph's per-frame raw text writes — no tag-wrapping.
tmp | TextMeshProUGUI |
WorldPromptBuilder.Build() Construct a fresh, independent WorldGameplayPromptUI under GlobalUIs (DontDestroyOnLoad). Returns the live component (Awake/OnEnable have run; the widget self-hides until Display), or null pre-asset-load (the build needs the game's fonts/materials/sprites loaded) or on any construction failure.
Opaque handle to a shown CairnAPI.WorldPrompt. Pass it back to WorldPrompt.Hide.
How a CairnAPI.WorldPrompt floats over its anchor (distance / wall-stick). Maps to the game's WorldGameplayPromptParameters. Defaults are ~1/3 of the game's wall-mount distance (live-tuned to sit near the target rather than far on a wall with a long leader line). Tune any field for your prompt.
WorldPromptStyle.Radius Anchor radius. Game default 0.25; we use ~0.083.
WorldPromptStyle.WallOffset Wall-stick push offset. Game default 0.2; we use ~0.067 (small = stays near the anchor).
WorldPromptStyle.MaxHeight Max height it floats to. Game default 1.3; we use ~0.43.
WorldPromptStyle.HeightOffset Height above the anchor. Game default 0.2; we use ~0.067.
WorldPromptStyle.UpsideDown Flip vertically.
WorldPromptStyle.FollowsAnchor Whether the prompt follows a moving anchor. true → a per-frame position pump; false → zero pump.
WorldPromptStyle.Default The close default (~1/3 of the game's wall-mount distance).