152 lines
4.7 KiB
Markdown
152 lines
4.7 KiB
Markdown
# Runtime protocol
|
||
|
||
The runtime protocol is the stable boundary between Lua and Dart.
|
||
|
||
```text
|
||
RuntimeEvent -> Lua -> GameDiff / RuntimeCommand -> Flame
|
||
```
|
||
|
||
## RuntimeEvent
|
||
|
||
Dart sends white-listed events to Lua. Events represent input, lifecycle, command/resource outcomes, and host/runtime notifications.
|
||
|
||
Lua should treat events as data and return explicit state changes.
|
||
|
||
## GameDiff
|
||
|
||
A `GameDiff` describes desired changes to the runtime render tree.
|
||
|
||
Typical operations include creating, updating, and removing runtime nodes. Dart validates node fields before applying them to Flame components.
|
||
|
||
## RuntimeNode
|
||
|
||
Runtime nodes are generic render descriptions. They are not Flame objects.
|
||
|
||
Supported node concepts include:
|
||
|
||
- Containers/panels.
|
||
- Text.
|
||
- Sprites/images.
|
||
- Buttons.
|
||
- List views.
|
||
- Particles.
|
||
- Spine nodes.
|
||
|
||
Lua may compose higher-level widgets, but those widgets must normalize into supported runtime nodes.
|
||
|
||
### Color and alpha
|
||
|
||
`RuntimeNode.color` supports `#RRGGBB` and `#AARRGGBB`. When the alpha channel is present in the color, it is multiplied with `RuntimeNode.alpha` and any runtime animation alpha.
|
||
|
||
```text
|
||
Final opacity = color alpha × node alpha × runtime animation alpha
|
||
```
|
||
|
||
`#RRGGBB` colors behave as fully opaque colors. `#00000000` is fully transparent.
|
||
|
||
### Text shadow
|
||
|
||
Text-capable nodes may use flat shadow fields:
|
||
|
||
- `textShadowColor`: `#RRGGBB` or `#AARRGGBB` shadow color.
|
||
- `textShadowOffsetX` / `textShadowOffsetY`: shadow offset in runtime pixels.
|
||
- `textShadowBlur`: non-negative blur radius.
|
||
|
||
The shadow color alpha is multiplied by `RuntimeNode.alpha` and any runtime animation alpha.
|
||
|
||
### Image regions and nine-slice
|
||
|
||
Image-capable nodes (`image`, `sprite`, and image-backed `button`) may draw only part of an asset.
|
||
|
||
For manual atlas regions, set source fields in image pixels:
|
||
|
||
- `sourceX` / `sourceY`: top-left source position inside the loaded image.
|
||
- `sourceWidth` / `sourceHeight`: source region size.
|
||
|
||
For TexturePacker JSON atlases, declare `atlas` on an image resource and set `frame` on the node. Image-backed buttons may also use `pressedFrame` and `disabledFrame`. The runtime supports TexturePacker JSON Hash and JSON Array `frames` formats with non-rotated frames. `rotated: true` frames are rejected.
|
||
|
||
When frame/source fields are omitted, the full image is used.
|
||
|
||
Image-capable nodes may also use nine-slice scaling with source-pixel insets:
|
||
|
||
- `sliceLeft` / `sliceTop` / `sliceRight` / `sliceBottom`.
|
||
|
||
Nine-slice keeps corners unscaled, stretches edges on one axis, and stretches the center on both axes. Insets are clamped to the selected source region and destination size.
|
||
|
||
## Runtime network API
|
||
|
||
Lua may use runtime-owned async networking without blocking script execution:
|
||
|
||
- `runtime.http_request({ id?, method?, url, headers?, body?, timeout? })`
|
||
- `runtime.ws_connect({ id?, url, protocols? })`
|
||
- `runtime.ws_send(id, message)`
|
||
- `runtime.ws_close(id)`
|
||
|
||
HTTP requests support `http` and `https` URLs. WebSocket connections support `ws` and `wss` URLs.
|
||
|
||
Network results are delivered back to Lua through `on_event(event)`:
|
||
|
||
- `network_http`: HTTP request completed or failed. `event.data` includes `id`, `url`, `method`, `ok`, and either `status`/`headers`/`body` or `error`.
|
||
- `network_ws_open`: WebSocket connection opened.
|
||
- `network_ws_message`: WebSocket message received.
|
||
- `network_ws_error`: WebSocket connection or stream error.
|
||
- `network_ws_close`: WebSocket connection closed.
|
||
|
||
## RuntimeCommand
|
||
|
||
Runtime commands request generic side effects owned by Dart/Flame.
|
||
|
||
Examples:
|
||
|
||
- `move_path`
|
||
- `move_to`
|
||
- `fade_to`
|
||
- `scale_to`
|
||
- `rotate_to`
|
||
- `remove_node`
|
||
- `sequence`
|
||
- `parallel`
|
||
- `delay`
|
||
- `toast`
|
||
- `play_sound`
|
||
- `play_bgm`
|
||
- `pause_bgm`
|
||
- `resume_bgm`
|
||
- `stop_bgm`
|
||
- `preload_resources`
|
||
- `evict_resources`
|
||
- `cancel_commands`
|
||
- `play_spine_animation`
|
||
- `copy_text`
|
||
|
||
Commands must remain generic. Do not add commands like `roll_ludo_dice` or `move_airplane_piece`; those belong in Lua game logic.
|
||
|
||
## Validation expectations
|
||
|
||
- Unknown protocol fields should not become implicit behavior.
|
||
- Required fields should fail clearly when absent.
|
||
- Helper-only aliases must be normalized before Dart protocol validation.
|
||
- Runtime code should not silently convert invalid game state into fake success.
|
||
|
||
## Where to change protocol code
|
||
|
||
```text
|
||
lib/runtime/models/ Data models
|
||
lib/runtime/protocol/ Protocol validation
|
||
lib/runtime/commands/ Command validation/execution
|
||
lib/runtime/rendering/ Runtime node to Flame component mapping
|
||
assets/runtime/lua/ Lua helper constructors/aliases
|
||
```
|
||
|
||
When protocol changes affect Lua authoring, update:
|
||
|
||
```text
|
||
tool/lua_runtime_defs_common.lua
|
||
```
|
||
|
||
Then run:
|
||
|
||
```bash
|
||
dart run tool/generate_lua_runtime_defs.dart
|
||
```
|