- 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
4.0 KiB
Architecture
flame_lua_runtime separates generic runtime infrastructure from game-specific Lua packages.
Boundary
RuntimeEvent -> Lua -> GameDiff / RuntimeCommand -> Flame
- Dart receives input, lifecycle, resource, and host events.
- Dart forwards white-listed runtime events to Lua.
- Lua returns a
GameDiffand/orRuntimeCommandlist. - Dart validates and applies diffs/commands to Flame-owned components.
Responsibilities
Dart / Flutter / Flame owns
- Rendering tree and
Componentlifecycle. - 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
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:
assets/runtime/lua
Package dependency root:
packages/flame_lua_runtime/assets/runtime/lua
Multi-package loading
The runtime supports loading multiple packages in sequence, with module merging:
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 toScriptEngine.loadPackages().LuaDardoScriptEngine.loadPackages()— iterates all packages, mergesmanifest.modulesinto_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 toruntime:*.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:
- Lua helper composition if it can be represented by existing nodes/commands.
- Generic protocol field if multiple games need the capability.
- Generic Runtime node/command if it requires Dart/Flame ownership.
- Avoid game-specific Dart code.
Examples of valid generic runtime features:
listViewnode.particlenode.toastcommand.copy_textcommand.play_spine_animationcommand.- 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.