Files
flutter_lua_runtime/docs/architecture.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

126 lines
4.0 KiB
Markdown

# Architecture
`flame_lua_runtime` separates generic runtime infrastructure from game-specific Lua packages.
## Boundary
```text
RuntimeEvent -> Lua -> GameDiff / RuntimeCommand -> Flame
```
- Dart receives input, lifecycle, resource, and host events.
- Dart forwards white-listed runtime events to Lua.
- Lua returns a `GameDiff` and/or `RuntimeCommand` list.
- Dart validates and applies diffs/commands to Flame-owned components.
## Responsibilities
### Dart / Flutter / Flame owns
- Rendering tree and `Component` lifecycle.
- Resource loading and cache ownership.
- Audio playback.
- Spine and particle object creation.
- Input/event dispatch.
- Package validation and activation.
- Runtime command execution.
- Diagnostics and error reporting.
### Lua owns
- Game state transitions.
- UI tree description.
- Layout calculation.
- Event handling decisions.
- Command/node table construction.
Lua should only describe desired runtime state. It must not receive or retain Dart/Flame object references.
## Key Dart areas
```text
lib/runtime/models/ Protocol data models
lib/runtime/protocol/ Protocol validation/parsing
lib/runtime/scripting/ Lua engine boundary
lib/runtime/packages/ Manifest/package loading and activation
lib/runtime/rendering/ Flame render tree adapter
lib/runtime/commands/ Runtime command execution
lib/runtime/resources/ Resource loading and cache management
lib/runtime/events/ Event dispatch and gates
lib/runtime/lifecycle/ Async/session/task safety
```
## Package loading
Game packages are manifest-driven. Bundled assets and remote/downloaded packages should flow through the same package abstraction where possible.
Shared Runtime Lua modules are loaded from `RuntimeOptions.runtimeLuaRoot`.
Default source-tree root:
```text
assets/runtime/lua
```
Package dependency root:
```text
packages/flame_lua_runtime/assets/runtime/lua
```
### Multi-package loading
The runtime supports loading multiple packages in sequence, with module merging:
```text
RuntimeOptions.basePackages = ['_framework']
-> load _framework package (modules: app, diff, ids, net, ...)
-> load game package (modules: state, rules, main, ...)
-> merge into flat _moduleScripts map
-> game modules override framework modules on name collision
-> execute game entry script
```
Key classes:
- `RuntimeOptions.basePackages` — ordered list of framework package IDs.
- `PackageActivationController._prepareCandidate()` — loads base packages first, then game package, passes combined list to `ScriptEngine.loadPackages()`.
- `LuaDardoScriptEngine.loadPackages()` — iterates all packages, merges `manifest.modules` into `_moduleScripts`, executes entry from last package.
- `GamePackageManifest.base` — optional metadata field declaring framework dependency.
Module resolution is flat: `runtime.import("xxx")` looks up `_moduleScripts[xxx]`. Game modules and framework modules share the same namespace. Later-loaded packages win on collision.
## Safety model
- Lua module loading is manifest-declared.
- `runtime.import(moduleName)` is the only intended module import API.
- `runtime:` module paths are restricted to `runtime:*.lua`.
- Package-local scripts are restricted to `scripts/*.lua`.
- Runtime protocol fields are white-listed.
- Invalid diffs/commands should fail clearly instead of being silently ignored.
## Extension guidance
When adding features, prefer this order:
1. Lua helper composition if it can be represented by existing nodes/commands.
2. Generic protocol field if multiple games need the capability.
3. Generic Runtime node/command if it requires Dart/Flame ownership.
4. Avoid game-specific Dart code.
Examples of valid generic runtime features:
- `listView` node.
- `particle` node.
- `toast` command.
- `copy_text` command.
- `play_spine_animation` command.
- Button image states.
Examples that should stay Lua-side:
- Game board rules.
- Game-specific dialog composition.
- Showcase category/menu behavior.
- Ludo/flight-specific animation choices.