← Mods

CairnAPI

lib

v0.1.0 · ldlework

Shared C# layer the other mods build on.

Stable wrappers over Cairn's IL2CPP internals — items, inventory, world interaction, prompts, teleport — so mods don't re-derive the plumbing.

Features

  • Item lookup + inventory manipulation
  • Screen-space and world-space prompts with glyphs
  • Proximity and reach-gated interactables
  • Streaming-aware teleport (local zone + cross-world)
  • Story beat enumeration
  • World/zone catalog
  • Screen state + transition events

Requires

MelonLoader only.

Download — not released yet · Install guide

Items

Read-only catalog of every item in the game.

Items.All IReadOnlyList<ItemInfo>

Every item in the game (315 entries). Cached after first access.

Items.Get(id) ItemInfo

Resolve a single item config by enum id.

id InventoryItemStringIdEnum The item's enum identifier.
ItemInfo

Per-item metadata.

.Id InventoryItemStringIdEnum Enum identifier.
.Name string Display name.
.StoredIn StorageType Which storage slot holds this item.
.MaxStack int Maximum stack count.
.UnitWeight float Weight per unit. NaN for non-physical items.
Example
foreach (var info in Items.All)
    MelonLogger.Msg($"{info.Name}  stored={info.StoredIn}  w={info.UnitWeight:F2}");

var rope = Items.Get(InventoryItemStringIdEnum.Rope_Standard);

Inventory

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 int How many to add.
AddResult

Return value from Inventory.Add.

.Ok bool True if all requested items were added.
.Added int How many were actually added.
.Error string Failure reason when Ok is false.
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.

Example
var result = Inventory.Add(InventoryItemStringIdEnum.Food_Nuts, 3);
if (!result.Ok) MelonLogger.Warning(result.Error);
else MelonLogger.Msg($"Added {result.Added}");

int count = Inventory.Count(InventoryItemStringIdEnum.Food_Nuts);
float load = Inventory.StorageWeight(StorageType.Bag);

Teleport

Warp the climber to any position in the current zone or across zones.

Teleport.Busy bool

True while a warp is in flight.

Teleport.To(position, done)

Warp the climber to a world position in the current zone.

position Vector3 Target world position.
done Action<bool> Callback — receives true on success.
Teleport.ToZone(zone, position, done)

Cross-zone warp. Streams the target zone if needed, then warps.

zone ZoneSceneData Target zone. Use World to resolve.
position Vector3 Target world position inside that zone.
done Action<bool> Callback — receives true on success.
Example
Teleport.To(targetPos, ok => {
    if (!ok) MelonLogger.Warning("warp failed or busy");
});

var zone = World.ResolveZone(World.Current, "03_TheNeedle");
Teleport.ToZone(zone, targetPos, ok => { });

World

Enumerate authored worlds and zones, resolve zone assets by name.

World.Current WorldZoneData

The active world currently being streamed.

World.Worlds() IEnumerable<WorldZoneData>

Every authored world in the game.

World.Zones(world) IEnumerable<ZoneSceneData>

All zones belonging to a world.

world WorldZoneData World to enumerate.
World.ResolveZone(world, name) ZoneSceneData

Find a zone by its asset name.

world WorldZoneData World to search within.
name string Zone asset name, e.g. "01_FirstRidge".
World.WorldOf(zone) WorldZoneData

Reverse-map a zone back to its owning world.

zone ZoneSceneData Zone to look up.
Example
foreach (var world in World.Worlds())
    foreach (var zone in World.Zones(world))
        MelonLogger.Msg($"{world.name}/{zone.name}");

var zone = World.ResolveZone(World.Current, "01_FirstRidge");
var owningWorld = World.WorldOf(zone);

Beats

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<Beat>

Every story-beat sensor in the current scene, sorted by label. Pure — no caching.

Beat

A story-beat sensor location.

.Label string Authored beat name.
.Position Vector3 World-space center of the sensor trigger.
Example
if (Beats.Available)
{
    var beats = Beats.Snapshot();
    foreach (var b in beats)
        MelonLogger.Msg($"{b.Label}  @{b.Position}");

    if (beats.Count > 0)
        Teleport.To(beats[0].Position, _ => { });
}

Screen

Query game state and subscribe to screen-lifecycle events.

Screen.PawnSpawned bool

True when the climber pawn is live. The reliable "in gameplay" check.

Screen.IsMenu bool

True while the main menu is active.

Screen.IsInGame bool

True while in a gameplay state, including when a pause menu overlaps.

Screen.IsCutscene bool

True during a cutscene.

Screen.IsGameOver bool

True on the game-over screen.

Screen.IsBivouac bool

True while the bivouac (rest) screen is active.

Screen.CurrentMenu Menu?

Foreground menu canvas, or null when no menu is open.

Screen.MainMenuStep int

Current sub-step within the main menu flow.

Screen.OnGameStateChanged event

Fires on every GameState push or pop.

from GameState Previous state.
to GameState New state.
Screen.OnMenuChanged event

Fires when the foreground menu changes. Receives null when the stack empties.

menu Menu? New foreground menu, or null.
Screen.OnCanvasOpened event

Fires when any menu or HUD canvas opens.

canvas Canvas The opened canvas.
Screen.OnCanvasClosed event

Fires when any menu or HUD canvas closes.

canvas Canvas The closed canvas.
Screen.OnTransitionStarted event

Fires at the start of any scene transition.

Screen.OnTransitionCompleted event

Fires when a scene transition finishes.

Screen.OnEnteringMenu event

Fires on the game→menu path, before the menu scene loads.

Example
if (Screen.IsMenu)      MelonLogger.Msg($"step={Screen.MainMenuStep}");
if (Screen.PawnSpawned) MelonLogger.Msg("live in gameplay");

Screen.OnGameStateChanged += (from, to) => MelonLogger.Msg($"{from} -> {to}");
Screen.OnMenuChanged      += menu => MelonLogger.Msg(menu?.name ?? "no menu");
Screen.OnTransitionStarted   += () => MelonLogger.Msg("transition started");
Screen.OnTransitionCompleted += () => MelonLogger.Msg("transition done");
Screen.OnCanvasOpened += c => MelonLogger.Msg($"opened {c.GetType().Name}");

Prompts

Four prompt types for different interaction contexts. All take a string label and an optional Glyph; all return a handle.

ScreenPrompt

Fixed screen-space prompt row rendered above the HUD.

ScreenPrompt.Show(text, glyph, parent?) PromptHandle

Render a [glyph] label row on the screen overlay. Pass parent to place it inside your own layout.

text string Label text.
glyph InputAction Button icon from Glyph, or null.
parent opt Transform Parent into a custom layout group.
ScreenPrompt.Move(handle, pos)

Reposition on the screen overlay. Coordinates are screen-center-relative.

handle PromptHandle Handle from Show.
pos Vector2 Anchored position.
ScreenPrompt.SetActive(handle, active)

Show or hide without destroying. Layout re-flows automatically.

handle PromptHandle Handle from Show.
active bool Visible state.
ScreenPrompt.Hide(handle)

Destroy the prompt.

handle PromptHandle Handle from Show.
Example
var h = ScreenPrompt.Show("Open the hatch", Glyph.Action(GameAction.Interact));
ScreenPrompt.Move(h, new Vector2(0, -120));

var h2 = ScreenPrompt.Show("Confirm", Glyph.Key("e"), parent: myRow.transform);

ScreenPrompt.SetActive(h, false);
ScreenPrompt.Hide(h);

WorldPrompt

Floating world-space prompt that billboards to the camera.

WorldPrompt.Show(anchor, text, glyph, style?) PromptHandle

Float a [glyph] label over a world transform.

anchor Transform World-space anchor.
text string Label text.
glyph InputAction Button icon, or null.
style opt WorldPromptStyle Tune float radius, wall offset, max height, and anchor tracking.
WorldPrompt.Hide(handle)

Destroy the prompt.

handle PromptHandle Handle from Show.
WorldPromptStyle

Display options for WorldPrompt.

.Radius float Float distance from the anchor.
.WallOffset float Offset from the wall surface.
.MaxHeight float Maximum vertical position.
.FollowsAnchor bool Track a moving anchor each frame.
Example
var h = WorldPrompt.Show(thing.transform, "Activate", Glyph.Key("e"));

var style = new WorldPromptStyle { Radius = 0.5f, FollowsAnchor = false };
var h2 = WorldPrompt.Show(fixedAnchor, "Examine", null, style: style);

WorldPrompt.Hide(h);

ProximityPrompt

World prompt gated on the climber being within range on the ground (Walking mode only).

ProximityPrompt.Show(anchor, distance, text, glyph, onInteract) ProximityInteractable

Show a prompt and fire a callback when the button is pressed in range.

anchor Transform World-space anchor.
distance float Detection radius in metres.
text string Label text.
glyph InputAction Button icon, or null.
onInteract Action Called when the button is pressed in range.
ProximityInteractable.Destroy()

Remove the prompt and interactable.

Example
var p = ProximityPrompt.Show(
    chest.transform, 3f,
    "Loot", Glyph.Action(GameAction.Interact),
    onInteract: () => OpenChest());

p.Destroy();

ReachPrompt

World prompt gated on a hand physically reaching into the trigger sphere (Climbing mode only).

ReachPrompt.Show(anchor, text, glyph, onInteract, radius?, localOffset?) ReachInteractable

Show a prompt and fire a callback when a hand enters the sphere and the button is pressed.

anchor Transform Moving anchor (e.g. a partner climber).
text string Label text.
glyph InputAction Button icon, or null.
onInteract Action Called when triggered.
radius opt float Detection sphere radius.
localOffset opt Vector3 Offset from anchor in local space.
ReachPrompt.Create(position, text, glyph, onInteract, radius?) ReachInteractable

Fixed world-point variant.

position Vector3 Fixed world position.
text string Label text.
glyph InputAction Button icon, or null.
onInteract Action Called when triggered.
radius opt float Detection sphere radius.
ReachInteractable.Destroy()

Remove the prompt and interactable.

Example
var r = ReachPrompt.Show(partner.transform, "Rope up",
    Glyph.Action(GameAction.Interact),
    onInteract: () => AttachRope(),
    radius: 0.5f, localOffset: Vector3.up * 0.2f);

var r2 = ReachPrompt.Create(leverPos, "Pull", Glyph.Key("e"),
    onInteract: () => PullLever());

r.Destroy();

Glyph

Produces InputAction objects for prompt icons. Icons resolve per-device (keyboard vs. gamepad) automatically.

Glyph.Action(action) InputAction

The player's live binding for a named game action. Respects their rebinds.

action GameAction The game action to look up.
Glyph.Key(key) InputAction

A specific keyboard key.

key string Key name, e.g. "f" or "space".
Glyph.Path(path) InputAction

A raw Unity Input System control path.

path string Control path, e.g. "&lt;Gamepad&gt;/buttonSouth".
Glyph.Custom(name, ...paths) InputAction

A multi-binding action usable as both a glyph icon and a polled input trigger.

name string Action name (arbitrary).
paths string[] One or more control paths.
Example
var g  = Glyph.Action(GameAction.Interact);
var g2 = Glyph.Key("f");
var g3 = Glyph.Path("<Gamepad>/buttonSouth");

var g4 = Glyph.Custom("MyAction", "<Keyboard>/g", "<Gamepad>/buttonWest");
if (g4.WasPerformedThisFrame()) DoThing();