Files
flutter_lua_runtime/docs/lua-package-format.md
gem 8ddc3be3a7 feat: multi-package loading with base framework support
- Add RuntimeOptions.basePackages for loading framework packages before game package
- Add ScriptEngine.loadPackages() for multi-package module merging
- LuaDardoScriptEngine merges modules from all packages, game overrides framework
- PackageActivationController loads base packages first, then game package
- GamePackageManifest parses optional 'base' field
- Update docs: README, quick-start, lua-package-format, architecture
- Update all test mocks with loadPackages() implementation
2026-06-10 00:04:00 +08:00

158 lines
3.5 KiB
Markdown

# Lua game package format
A game package is a manifest plus Lua scripts and optional assets.
Typical structure:
```text
assets/games/<gameId>/
manifest.json
scripts/
main.lua
state.lua
ui.lua
runtime_defs.lua
assets/
image.png
audio/
click.wav
```
## Manifest modules
Lua modules must be declared in `manifest.json`.
```json
{
"id": "template",
"version": "0.1.0",
"entry": "main",
"modules": {
"main": "scripts/main.lua",
"state": "scripts/state.lua",
"ui": "scripts/ui.lua",
"runtime_ui": "runtime:runtime_ui.lua",
"runtime_widgets": "runtime:runtime_widgets.lua",
"runtime_commands": "runtime:runtime_commands.lua",
"layout": "runtime:layout.lua"
}
}
```
Lua imports by module name:
```lua
local ui = runtime.import("ui")
local widgets = runtime.import("runtime_widgets")
```
Do not use `require`, `package`, `dofile`, `loadfile`, or `os`.
## Path rules
Package-local module paths:
```text
scripts/*.lua
```
Runtime shared module paths:
```text
runtime:*.lua
```
`runtime:` paths must not contain `/`, `..`, or an empty filename.
## Base packages
A game manifest can declare a `base` field to indicate it depends on a framework package:
```json
{
"gameId": "ludo",
"base": "_framework",
"modules": { ... }
}
```
The `base` field is metadata. Actual loading is controlled by `RuntimeOptions.basePackages`:
```dart
LuaGameWidget(
gameId: 'ludo',
runtimeOptions: const RuntimeOptions(
basePackages: ['_framework'],
),
)
```
Loading order:
1. Base packages are loaded first, in `basePackages` order.
2. The game package is loaded last.
3. All modules are merged into a flat map.
4. Later packages override earlier packages on name collision.
5. The entry script always comes from the last (game) package.
This means a game can override any framework module by declaring a module with the same name in its own manifest.
## Multi-package module resolution
When Lua code calls `runtime.import("xxx")`:
1. Look up `xxx` in the merged module map (game modules first, then framework).
2. If not found, throw `FormatException: Lua module is not declared in manifest.modules`.
Framework modules are transparent to game code:
```lua
local app = runtime.import("app") -- resolved from framework
local state = runtime.import("state") -- resolved from game
```
## Entry module
The manifest `entry` module should expose lifecycle/event functions expected by the script engine. Keep game-specific state in Lua modules and return runtime diffs/commands through the approved protocol.
## Runtime helper modules
Shared helpers are provided by the runtime package:
```text
assets/runtime/lua/runtime_ui.lua
assets/runtime/lua/runtime_widgets.lua
assets/runtime/lua/runtime_commands.lua
assets/runtime/lua/layout.lua
```
Use helpers for authoring convenience, but remember helpers must normalize into supported Runtime protocol nodes/commands before Dart validation.
## Generated Lua definitions
`runtime_defs.lua` files are generated from common definitions. After changing helper APIs, run:
```bash
dart run tool/generate_lua_runtime_defs.dart
```
Check without rewriting:
```bash
dart run tool/generate_lua_runtime_defs.dart --check
```
## Package validation
A host repository can validate a game package with:
```bash
dart run tool/check_runtime_package.dart assets/games/template packages/flame_lua_runtime/assets/runtime/lua
```
Within this package repo, example game packages live under:
```text
example/assets/games/
```