openplanet-plugin-dev
Create, debug, structure, and run Openplanet AngelScript plugins for Trackmania 2020 (TMNEXT) and ManiaPlanet 4 (TM2/MP4). Covers API quirks, AngelScript pitfalls, performance patterns, the launch/verify loop, MP4 API-mismatch fixes, and proven templates. Skill: openplanet-plugin-dev Owner: tomekdot Summary: Create, debug, structure, and run Openplanet AngelScript plugins for Trackmania 2020 (TMNEXT) and ManiaPlanet 4 (TM2/MP4). Covers API quirks, AngelScript pitfalls, performance patterns, the launch/verify loop, MP4 API-mismatch fixes, and proven templates. Tags: latest:3.0.0 Version history: v3.0.0 | 2026-08-17T11:58:33.878Z | user Removed all bundled API reference
Rank
62
Safety
84
Downloads
1.1k
Updated
Oct 11, 2026
Version
3.0.0
Source
CLAWHUB
About
What it does, and when to use it.
Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.
Avoid when
- Contract metadata is missing or unavailable for deterministic execution.
Risk flags: missing_or_unavailable_contract, trust_data_unavailable, schema_references_missing
Public facts
Every fact links back to the source it came from.
- Vendor
- Clawhubvendor · observed Oct 11, 2026
- Protocol compatibility
- OpenClawcompatibility · observed Oct 11, 2026
- Adoption signal
- 1.1K downloadsadoption · observed Oct 11, 2026
- Latest release
- 3.0.0release · observed Aug 17, 2026
- Handshake status
- UNKNOWNsecurity
Install and run
Setup complexity: low.
clawhub skill install s1714s261dv2y0nczy9vxs2bcd87fpcv:openplanet-plugin-dev- Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.
- Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data.
Contract: missing
curl -s "https://www.xpersona.co/api/v1/agents/clawhub-tomekdot-openplanet-plugin-dev/snapshot"
Documentation
CLAWHUB
150,015 characters of source documentation, loaded on request.
Extracted files
5 files captured from the source.
SKILL.md
---
name: openplanet-plugin-dev
description: Create, debug, structure, and run Openplanet AngelScript plugins for Trackmania 2020 (TMNEXT) and ManiaPlanet 4 (TM2/MP4). Covers API quirks, AngelScript pitfalls, performance patterns, the launch/verify loop, MP4 API-mismatch fixes, and proven templates. Use when building, debugging, reviewing, or launching Openplanet plugins.
version: 3.0.0
metadata:
openclaw:
tags: [openplanet, trackmania, angelscript, plugin, game-modding]
---
# Openplanet Plugin Development
Core guide for Openplanet AngelScript plugins on **TM2020 (TMNEXT)** and
**ManiaPlanet 4 (MP4/TM2)**. Deep material lives in `references/` — load only
what the task needs (index at the bottom).
## Golden rules
1. **Verify API members against the reflection DB before writing code.**
- **Game Nod classes** live in `<GameDir>/Openplanet4.json` under
`ns.Game.<Class>.m[]` (entries `n`=name, `t`=type, `p`=parent). Walk it with
the procedure in `references/static-verify-workflow.md`.
- **Openplanet script namespaces** (`UI::`, `IO::`, `Time::`, `Json::`,
`Math::`, `Text::`, `Net::`, `Audio::`, `Icons::`, `getExceptionInfo()`) are
**NOT in `Openplanet4.json`**. They live in **`OpenplanetCore.json`** (same
game dir) under `functions[]` (filter by `ns`), `classes[]`, `enums[]`.
Extraction recipes + verified signatures: `references/openplanet-core-json.md`.
**Before assuming a built-in exists (e.g. `IO::WriteFile`, `UI::ListBox`,
`Time::Format(string)`), grep `OpenplanetCore.json`** — false assumptions
here cost a full kill+relaunch recompile cycle each time.
- MP4 game-class specifics: `references/mp4-api-verified.md` (editor) and
`references/mp4-runtime-and-dev-memory.md` (in-race / playground).
- **A class can appear in the DB with an EMPTY `m[]`** (e.g.
`ns.Scene.CSceneVehicleVis` is `{"i":...,"s":3464}` with no members). That is
not a lookup failure — it means the class has no scriptable named members and
the only way in is raw `Dev::GetOffset*` / `Dev::SetOffset` against its byte
size. Report that honestly instead of inventing member names.
2. **Target game matters.** TM2020 examples often DON'T compile on MP4 (missing
UI overloads, missing members, wstring vs string). MP4 specifics:
`references/mp4-api-verified.md`, `references/mp4-api-mismatches.md`,
`references/mp4-supplement.md`, `references/mp4-ui-rendering.md`.
3. **Unsigned folder plugins need Developer signature mode.** Launch with
`ManiaPlanet.exe /openplanet:developer` (or F3 → Developer → Signature Mode).
Otherwise the log shows `Invalid file hash` + `not suitable for the current
signature mode` and the plugin silently doesn't appear.
4. **Debug via the log, not the GUI.** Clear `Openplanet.log`, launch, wait
~50 s, then grep for `ERR :` / `compilation failed` / `Loaded plugin`.
Full command recipes: `references/launch-and-verif_meta.json
{
"ownerId": "kn70db4t9jcx94v2xfcg0pymyd87f4nt",
"slug": "openplanet-plugin-dev",
"version": "3.0.0",
"publishedAt": 1786967913878
}references/api-namespaces.md
# Openplanet API Reference - Namespaces
Source: https://openplanet.dev/docs/api
## List of all namespaces (as of Openplanet 1.29.5)
| Namespace | Description |
|-----------|-------------|
| `// Global namespace` | Global functions |
| `namespace UI` | UI tools (ImGui) |
| `namespace nvg` | NanoVG drawing |
| `namespace Audio` | Audio playback |
| `namespace Auth` | Third-party API authentication |
| `namespace Crypto` | Cryptography and hashing |
| `namespace Display` | Display functions |
| `namespace Fids` | Game files and folders |
| `namespace IO` | Filesystem I/O |
| `namespace Icons` | Icon helpers |
| `namespace Json` | JSON serialization |
| `namespace Math` | Math functions |
| `namespace Net` | Networking and sockets |
| `namespace Path` | File path operations |
| `namespace Permissions` | Trackmania permission checks |
| `namespace Regex` | Regular expressions |
| `namespace SQLite` | SQLite database access |
| `namespace Settings` | Openplanet settings |
| `namespace Tests` | Testing utilities |
| `namespace Text` | Text parsing and formatting |
| `namespace Time` | Date and time |
| `namespace XML` | XML deserialization |
| `namespace mat3` | 3x3 matrix |
| `namespace mat4` | 4x4 matrix |
| `namespace string` | String static functions |
| `namespace Reflection` | Type reflection |
| `namespace Discord` | Discord rich presence |
| `namespace Meta` | Openplanet meta API |
| `namespace Import` | DLL import |
| `namespace Dev` | Advanced memory access |
| `namespace Internal` | Internal/built-in use only |
## UI Namespace - Key Functions (AngelScript)
From global namespace:
- `bool UI::Begin(string name, bool* open = nil, UI.WindowFlags flags = 0)` - Begin window
- `void UI::End()` - End window
- `bool UI::BeginChild(string id, vec2 size = {0,0}, bool border = false, UI.WindowFlags flags = 0)`
- `void UI::EndChild()`
- `void UI::Text(string text)`
- `void UI::TextColored(vec4 color, string text)` - NOTE: Does NOT exist in Openplanet AngelScript! Use PushStyleColor instead
- `void UI::TextDisabled(string text)`
- `void UI::TextWrapped(string text)`
- `void UI::LabelText(string label, string text)`
- `bool UI::Button(string label, vec2 size = {0,0})`
- `bool UI::SmallButton(string label)`
- `bool UI::Checkbox(string label, bool* value)`
- `bool UI::RadioButton(string label, bool active)`
- `bool UI::InputText(string label, string* buffer, int bufferSize, UI.InputTextFlags flags = 0)` - Returns true if text changed
- `bool UI::Combo(string label, int* currentItem, string[] items)`
- `bool UI::SliderFloat(string label, float* value, float min, float max, string format = "%.3f")`
- `bool UI::SliderInt(string label, int* value, int min, int max, string format = "%d")`
- `bool UI::DragFloat(string label, float* value, float speed = 1.0, float min = 0, float max = 0)`
- `bool UI::ColorEdit3(string label, float[3] color, UI.ColorEditFlags flags = 0)`
- `bool UI::ColorEdit4(string label, float[4] color, UI.ColorEditFlags flags = 0)`
- `bool Ureferences/api-quirks-and-pitfalls.md
## 🚨 CRITICAL — API Quirks & Pitfalls
### 🔤 AngelScript Language Quirks
These bite everyone. AngelScript ≠ C++, ≠ C#, ≠ Java.
#### 🔢 Integer literal suffixes
`u`, `l`, `ul`, `ull` suffixes are **not supported**.
```angelscript
// ❌ ERR: Unexpected token '<identifier>'
const uint64 MASK = 0x3FFFFFFu;
const int BIG = 1ul;
// ✅ OK: bare literal; compiler picks the type
const uint64 MASK = 0x3FFFFFF;
const int BIG = 1;
const uint64 KEY = uint64(0x123); // explicit cast
```
#### 📐 `const` on value-type arrays
`const` works for primitives, but **NOT for fixed-size arrays of value types** like `int2[]` or `vec3[]`.
```angelscript
// ❌ ERR: Expected '('
const int2 EDGES[12] = { int2(0,1), ... };
const vec3 CORNERS[8] = { ... };
// ✅ OK: dynamic, no const
int2[] g_Edges = { int2(0,1), ... };
```
Also: `const` on `array<T>` is unreliable — keep globals un-`const` and use a `g_` prefix instead.
#### 📏 Fixed-size local arrays
**Local fixed-size arrays are not supported**:
```angelscript
void Foo() {
// ❌ ERR: Expected ';' Instead found identifier 'pts'
vec2 pts[8];
float depth[8];
}
// ✅ WORKAROUND: individual variables
void Foo() {
vec2 p0, p1, p2, p3, p4, p5, p6, p7;
// compiler will register-allocate them
}
```
Or use dynamic arrays:
```angelscript
vec2[] GetCorners() {
vec2[] cs = { vec2(0,0), vec2(1,0), ... };
return cs;
}
```
#### 🗝️ `dictionary` key types
**Most surprising limitation**: `dictionary` only accepts `const string&in` keys.
```angelscript
dictionary d;
// ❌ ERR: No matching signatures to 'dictionary::Exists(uint64)'
d[uint64(123)] = true;
d[int(456)] = true;
// ✅ OK: build a string key
d["123"] = true;
d[gx + "," + gy + "," + gz] = true;
```
If you need a fast non-string key, roll your own hash table (parallel arrays + linear scan, or small open-addressed probe table). For most plugins, `string` keys are fine.
#### 🔀 `uint` vs `int` in comparisons
`array<T>.Length` returns `uint`. Comparing a signed `int` loop counter produces a warning treated as error in strict mode:
```angelscript
// ⚠️ WARN: Signed/Unsigned mismatch
for (int e = 0; e < arr.Length; e++) { ... }
// ✅ CLEAN:
for (uint e = 0; e < arr.Length; e++) { ... }
```
#### 📤 `out` parameter naming
Match the parameter name **exactly**:
```angelscript
// ❌ ERR: No matching symbol 'outDepth'
bool Project(vec3 &in p, vec2 &out screen, float &out depth) {
outDepth = 0.0f;
}
// ✅ OK:
bool Project(vec3 &in p, vec2 &out screen, float &out depth) {
depth = 0.0f;
}
```
#### 🎨 `int2`, `vec2`, `vec3`, `vec4` constructors
```angelscript
int2 a = int2(1, 2);
vec3 v = vec3(1.0f, 2.0f, 3.0f);
vec4 red = vec4(1.0f, 0.0f, 0.0f, 0.5f);
```
They are value types — no `@` needed for storage.
#### 🔄 `&inout` on primitive types is NOT allowed
```angelscript
// ❌ ERR:
void ConfigRow(const string &in label, bool &inout value) { }
// ✅ OK:
void ConfigRow(const string &in label, bool value) { }
```
#### 📊 Array initialireferences/blockable-input-callbacks-mp4.md
# BlockableInputCallbacks (BIC) on ManiaPlanet 4 — verified facts (2026-08)
The `ackepta/BlockableInputCallbacks` optimizer (already shipped as
`Plugins/BlockableInputCallbacks.op`, siteid 893, v0.1.0) is the input layer used
by trainers (e.g. `TrackmaniaTrainer`). Facts verified by unpacking the `.op`
(zip) before using it:
## manifest shape (uses `[script]` module/exports, NOT `dependencies`)
```toml
[meta]
name = "BlockableInputCallbacks"
author = "achepta"
version = "0.1.0"
siteid = 893
[script]
module = "BlockableInputCallbacks"
exports = [ "Export.as" ]
shared_exports = [ "Shared.as" ]
```
Dependency plugin window: a plugin that imports it writes
`[script] dependencies = ["BlockableInputCallbacks"]` in ITS info.toml.
## import surface (Export.as)
```angelscript
namespace BlockableInputCallbacks {
import int RegisterCallback(const string &in name, IInputCallback@ callback) from "BlockableInputCallbacks";
import int RegisterCallback(const string &in name, IInputCallback@ callback, float activationThreshold) from "BlockableInputCallbacks";
import void UnregisterCallback(int id) from "BlockableInputCallbacks";
import void UnregisterCallbacks(const string &in name) from "BlockableInputCallbacks";
import void SetInputBlocked(PadInput input, bool blocked) from "BlockableInputCallbacks";
import void SetInputBlocked(KeyboardInput input, bool blocked) from "BlockableInputCallbacks";
import KeyboardInput VirtualKeyToKeyboardInput(VirtualKey key) from "BlockableInputCallbacks";
import VirtualKey KeyboardInputToVirtualKey(KeyboardInput input) from "BlockableInputCallbacks";
}
```
## verified enum values (Shared.as)
- `PadInput`: `None = 255`, then per-pad buttons.
- `KeyboardInput`: `None = 0x00`; function keys **F5 = 0x3F, F6 = 0x40, F8 = 0x42**
(F7 = 0x41 by sequence).
- `InputDecision`, `PadInputEvent` shared enums — usable in the importing plugin.
## pitfalls
- Do NOT assume TM2020's REML can't bind F5/F6/F8 the same way: verify the enum
against `Shared.as` in THIS plugin's `.op` before relying on it (values above
are for v0.1.0).
- The callbacks are into-game with a `IInputCallback@` interface — if the plugin
is missing from `Plugins/` at runtime the import fails the whole plugin pencil.
- Simpler zero-dependency fallback for a trainer: plain `OnKeyPress(bool down,
VirtualKey key)` with `[Setting hidden] VirtualKey` — no BIC needed unless the
key must also be BLOCKED from reaching the game.AionUi
Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!
activepieces
AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents
cherry-studio
AI productivity studio with smart chat, autonomous agents, and 300+ assistants.
CopilotKit
The Frontend for Agents & Generative UI. React + Angular
Machine-readable data
The same record, as JSON, for agents and crawlers.
{
"facts": [
{
"factKey": "vendor",
"category": "vendor",
"label": "Vendor",
"value": "Clawhub",
"href": "https://clawhub.ai/tomekdot/skills/openplanet-plugin-dev",
"sourceUrl": "https://clawhub.ai/tomekdot/skills/openplanet-plugin-dev",
"sourceType": "profile",
"confidence": "medium",
"observedAt": "2026-10-11T06:05:19.302Z",
"isPublic": true
},
{
"factKey": "protocols",
"category": "compatibility",
"label": "Protocol compatibility",
"value": "OpenClaw",
"href": "https://www.xpersona.co/api/v1/agents/clawhub-tomekdot-openplanet-plugin-dev/contract",
"sourceUrl": "https://www.xpersona.co/api/v1/agents/clawhub-tomekdot-openplanet-plugin-dev/contract",
"sourceType": "contract",
"confidence": "medium",
"observedAt": "2026-10-11T06:05:19.302Z",
"isPublic": true
},
{
"factKey": "traction",
"category": "adoption",
"label": "Adoption signal",
"value": "1.1K downloads",
"href": "https://clawhub.ai/tomekdot/openplanet-plugin-dev",
"sourceUrl": "https://clawhub.ai/tomekdot/openplanet-plugin-dev",
"sourceType": "profile",
"confidence": "medium",
"observedAt": "2026-10-11T06:05:19.302Z",
"isPublic": true
},
{
"factKey": "latest_release",
"category": "release",
"label": "Latest release",
"value": "3.0.0",
"href": "https://clawhub.ai/tomekdot/openplanet-plugin-dev",
"sourceUrl": "https://clawhub.ai/tomekdot/openplanet-plugin-dev",
"sourceType": "release",
"confidence": "medium",
"observedAt": "2026-08-17T11:58:33.878Z",
"isPublic": true
},
{
"factKey": "handshake_status",
"category": "security",
"label": "Handshake status",
"value": "UNKNOWN",
"href": "https://www.xpersona.co/api/v1/agents/clawhub-tomekdot-openplanet-plugin-dev/trust",
"sourceUrl": "https://www.xpersona.co/api/v1/agents/clawhub-tomekdot-openplanet-plugin-dev/trust",
"sourceType": "trust",
"confidence": "medium",
"observedAt": null,
"isPublic": true
}
],
"events": [
{
"eventType": "release",
"title": "Release 3.0.0",
"description": "Removed all bundled API reference, changelog, and template files to streamline the skill package. - Deleted 10 files, including API reference material, changelogs, implementation notes, and sample templates. - Core guidance and best practices remain in the primary documentation. - Users now refer to external resources or official documentation for in-depth API and template details.",
"href": "https://clawhub.ai/tomekdot/openplanet-plugin-dev",
"sourceUrl": "https://clawhub.ai/tomekdot/openplanet-plugin-dev",
"sourceType": "release",
"confidence": "medium",
"observedAt": "2026-08-17T11:58:33.878Z",
"isPublic": true
}
]
}Record generated Oct 11, 2026.
