Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

manifold:game 0.1.0

Contract reference · Payloads · contract.json (crates/manifold-wasm-abi/wit/contract.json)

Status: legacy contract 0.1: linked by the mod’s [caps] until migration steps M2 and M3 move its interfaces into the contract packages.

InterfaceKind
asset-sourceimport
clockimport
persistent-storageimport
pluginexport
texttypes-only
uiimport

Interface asset-source

import · since 0.1.0

AssetSource capability: host-provided file read for bundled mod assets. Covers 18 std::fs::read_* violations from the audit. Sync (no async) — assets are small RON/WGSL/JSONL files read at startup. In dev mode the host reads loose files; in prod reads from .mod archive.

Functions

read

read: func(mod-id: string, path: string) -> result<list<u8>, asset-error>

Read a mod asset by path. The mod-id scopes the read to this mod’s asset bundle; future third-party mods get their own isolated scope. Path uses forward slashes and must not contain parent-dir components; the host validates this to prevent bundle escape. Returns the raw bytes of the file.

Types

asset-error (enum)

Error returned when an asset path cannot be resolved.

IndexCaseAbout
0not-foundThe file does not exist in this mod’s asset bundle.
1io-errorThe file exists but could not be decoded (permissions, corrupt, etc.).

Interface clock

import · since 0.1.0

Clock capability: host-provided time access. Covers 12 wall-clock violations from the audit. Two methods to cover both use cases found in the codebase:

  • monotonic nanos for profiling (Instant::now replacement)
  • wallclock millis for log timestamps and double-tap detection

Functions

now-instant

now-instant: func() -> u64

Monotonic nanoseconds since an unspecified epoch (wasm-host construction). Replaces Instant::now(). Not guaranteed to be wall-clock aligned. The epoch is consistent within one host process lifetime.

now-system-millis

now-system-millis: func() -> u64

Wallclock milliseconds since UNIX epoch. Replaces SystemTime::now(). Not monotonically guaranteed across system clock adjustments, but matches the semantics callers expect for log timestamps and double-tap detection (where sub-second precision matters but cross-session monotonicity does not).

Interface persistent-storage

import · since 0.1.0

PersistentStorage capability: host-provided scoped persistent writes. Covers 4 std::fs::write/create_dir_all violations from the audit. Scope is per-mod (host validates paths cannot escape the mod’s directory). This is intentionally separate from the save-stack (redb+postcard+zstd); game_settings, keybinds, and console history are user config, not save data.

Functions

append-history

append-history: func(line: string) -> result<_, storage-error>

Append one history line (without trailing newline; host adds ‘\n’).

append-log

append-log: func(bytes: list<u8>) -> result<_, storage-error>

Append bytes to the session log. Does not add newline separators; callers are responsible for framing (typically line-delimited JSON).

read-config

read-config: func(scope: string, key: string) -> result<option<list<u8>>, storage-error>

Read a config value for this mod. scope identifies the config domain (e.g., “settings”, “keybinds”); key names the entry within that domain. Returns None if the entry does not exist.

read-history

read-history: func() -> result<list<u8>, storage-error>

Read the console history file (line-delimited JSONL).

read-log

read-log: func() -> result<list<u8>, storage-error>

Read the entire session log accumulated so far. Returns an empty list if no log exists yet.

write-config

write-config: func(scope: string, key: string, bytes: list<u8>) -> result<_, storage-error>

Write a config value. Creates or overwrites the entry.

Types

storage-error (enum)

Error returned by storage operations.

IndexCaseAbout
0invalid-pathThe key path contains illegal characters or escapes the mod scope.
1io-errorThe underlying storage backend failed (disk full, permissions, etc.).

Interface plugin

export · since 0.1.0

The UI half of the contract 0.1 plugin export, until migration step M2 moves it to manifold:ui/plugin-ui (contract foundation spec §6.1). The lifecycle and system calls moved to manifold:core/plugin-lifecycle and manifold:ecs/plugin-systems (M1b). Optional: only a mod that authors UI exports it.

Functions

build-ui-state

build-ui-state: func(ui-key: u64, entity: u64, bundle: borrow<ui-read-bundle>) -> result<list<u8>, ui-error>

build-ui-state: called by the server BUI phase (dirty-gated) to produce a UiStateMap for the given ui-key and subscription entity. ui-key: u64 identifying which registered UI to build state for. entity: u64 identifying the subscription entity (bundle’s entity target). bundle: read-only snapshot of the entity’s declared components + resources. Returns postcard-encoded UiStateMap bytes, or ui-error on failure.

handle-ui-event

handle-ui-event: func(ui-key: u64, entity: u64, event: list<u8>, bundle: borrow<ui-rw-bundle>) -> result<_, ui-error>

handle-ui-event: called by the server when a client emits a UiEvent. ui-key: u64 identifying which registered UI received the action. entity: u64 identifying the subscription entity. event: postcard-encoded UiEvent bytes. bundle: read+write snapshot; guest validates the event and writes mutations. Writes land in the host only if this returns ok(_).

ui-manifest

ui-manifest: func() -> list<u8>

ui-manifest: called once at mod load to declare all UI registrations. Returns postcard-encoded Vec<UiRegistration>. The host allocates the mod’s NamespaceId, resolves tree bindings, and caches the schema + tree. A broken binding fails this specific UiKey at load time (fail-soft: mod keeps running).

Types

ui-error (alias)

= game/ui.ui-error

ui-read-bundle (alias)

= game/ui.ui-read-bundle

ui-rw-bundle (alias)

= game/ui.ui-rw-bundle

Interface text

types-only · since 0.1.0

Player-facing text: a message key plus typed arguments, never a finished sentence. Each client resolves it through the catalogs of its player’s language, so players on one server each read their own language. Mirrors manifold_l10n_types::LocalizedText. Keys are <mod-id>.<segment>...; a mod’s catalogs live at locales/<bcp47>/*.ftl in its package.

Types

currency-amount (record)

A currency amount in minor units (cents) with its ISO 4217 code.

FieldTypeAbout
minors64
codestring

loc-arg (variant)

IndexCasePayloadAbout
0strstringUntranslated text (bidi-isolated when substituted).
1ints64
2floatf64
3keystringAnother message key, resolved without arguments.
4itemstringA namespaced item or block id; resolves to its display name.
5playerstringA player’s display name (user text, isolated).
6duration-msu64
7timestamp-mss64Milliseconds since the Unix epoch, UTC.
8currencycurrency-amount

loc-entry (record)

FieldTypeAbout
namestring
valueloc-arg

localized-text (record)

FieldTypeAbout
keystring
argslist<loc-entry>

Interface ui

import · since 0.1.0

Ui capability: per-UI-key entity-component + resource snapshot. Coarse-grained crossing: host stages the subscription entity’s declared read-components and declared read-resources before calling build-ui-state; the guest accumulates writes in the rw-bundle which the host applies after handle-ui-event returns.

Two bundle resources: ui-read-bundle — read-only snapshot passed to build-ui-state. ui-rw-bundle — read+write snapshot passed to handle-ui-event.

The guest-exported entry points (ui-manifest, build-ui-state, handle-ui-event) are declared in the plugin interface, which uses these resource types via use ui.{...} — mirroring how run-system uses resource-bundle-handle.

Resources: ui-read-bundle, ui-rw-bundle.

Functions

[method]ui-read-bundle.read-entity-component

[method]ui-read-bundle.read-entity-component: func(self: borrow<ui-read-bundle>, type-id: u64) -> option<list<u8>>

Read an entity component from the bundle by its type-id. type-id is the u64 FNV-1a hash of the fully-qualified Rust type name. Returns None if the component was not included in the declared read-set or is not present on the entity. Returned bytes are postcard-encoded.

[method]ui-read-bundle.read-resource

[method]ui-read-bundle.read-resource: func(self: borrow<ui-read-bundle>, type-id: u64) -> option<list<u8>>

Read a resource from the bundle by its type-id. Returns None if the resource was not declared in the read-set or is absent. Returned bytes are postcard-encoded.

[method]ui-rw-bundle.read-entity-component

[method]ui-rw-bundle.read-entity-component: func(self: borrow<ui-rw-bundle>, type-id: u64) -> option<list<u8>>

Read an entity component from the bundle by its type-id.

[method]ui-rw-bundle.read-resource

[method]ui-rw-bundle.read-resource: func(self: borrow<ui-rw-bundle>, type-id: u64) -> option<list<u8>>

Read a resource from the bundle by its type-id.

[method]ui-rw-bundle.write-entity-component

[method]ui-rw-bundle.write-entity-component: func(self: borrow<ui-rw-bundle>, type-id: u64, bytes: list<u8>)

Write a component back to the bundle by its type-id. The bytes must be postcard-encoded. Writing a type not declared in the UI’s write_components set causes a host trap. Bounded to the subscription entity; cross-entity writes are rejected.

[method]ui-rw-bundle.write-resource

[method]ui-rw-bundle.write-resource: func(self: borrow<ui-rw-bundle>, type-id: u64, bytes: list<u8>)

Write a resource back to the bundle by its type-id. The bytes must be postcard-encoded. Writing a type not declared in the UI’s write_resources set causes a host trap.

Types

ui-error (record)

Error returned when a UI call fails gracefully.

FieldTypeAbout
messagestring

ui-read-bundle (resource)

Read-only bundle: snapshot of the subscription entity’s declared read-components and read-resources for one build-ui-state invocation. The host drops it after build-ui-state returns.

resource

ui-rw-bundle (resource)

Read+write bundle: snapshot passed to handle-ui-event. The guest may read staged bytes and write back mutations; the host applies declared writes after handle-ui-event returns.

resource