Initial flame_lua_runtime package

This commit is contained in:
gem
2026-06-07 22:53:58 +08:00
commit 733b2fb798
262 changed files with 28439 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
import '../diagnostics/runtime_diagnostics.dart';
import '../lifecycle/runtime_serial_queue.dart';
import '../lifecycle/runtime_session.dart';
import '../models/game_diff.dart';
import '../models/runtime_event.dart';
import '../scripting/script_engine.dart';
import 'runtime_event_gate.dart';
class RuntimeEventDispatcher {
RuntimeEventDispatcher({
required RuntimeSession session,
required ScriptEngine scriptEngine,
required bool Function(String id) isScopeAlive,
bool Function(String id, int epoch)? isNodeEpochAlive,
required void Function(GameDiff diff) applyDiff,
RuntimeDiagnostics? diagnostics,
void Function(Object error)? onError,
}) : _scriptEngine = scriptEngine,
_applyDiff = applyDiff,
_diagnostics = diagnostics,
_onError = onError,
_gate = RuntimeEventGate(
session: session,
isScopeAlive: isScopeAlive,
isNodeEpochAlive: isNodeEpochAlive,
) {
_queue = RuntimeSerialQueue<RuntimeEvent>(
shouldContinue: () => !_disposed && session.isActive,
onItem: _dispatch,
);
}
final ScriptEngine _scriptEngine;
final void Function(GameDiff diff) _applyDiff;
final RuntimeDiagnostics? _diagnostics;
final void Function(Object error)? _onError;
final RuntimeEventGate _gate;
late final RuntimeSerialQueue<RuntimeEvent> _queue;
bool _disposed = false;
int get pendingEventCount => _queue.pendingCount;
void enqueue(RuntimeEvent event) {
if (_disposed || !_gate.session.isActive) {
return;
}
_queue.enqueue(_gate.attachSession(event));
}
void dispose() {
_disposed = true;
_queue.dispose();
}
void _dispatch(RuntimeEvent event) {
if (!_gate.accepts(event)) {
return;
}
try {
final diff = _scriptEngine.dispatchEvent(event);
if (_disposed || !_gate.session.isActive || !_gate.accepts(event)) {
return;
}
_applyDiff(diff);
} catch (error) {
_diagnostics?.record(
type: RuntimeDiagnosticType.luaEventError,
message: 'Lua event dispatch failed',
error: error,
context: {
'eventType': event.type,
if (event.target != null) 'target': event.target,
if (event.handler != null) 'handler': event.handler,
},
);
_onError?.call(error);
}
}
}

View File

@@ -0,0 +1,47 @@
import '../lifecycle/runtime_session.dart';
import '../models/runtime_event.dart';
class RuntimeEventGate {
const RuntimeEventGate({
required this.session,
required bool Function(String id) isScopeAlive,
bool Function(String id, int epoch)? isNodeEpochAlive,
}) : _isScopeAlive = isScopeAlive,
_isNodeEpochAlive = isNodeEpochAlive;
final RuntimeSession session;
final bool Function(String id) _isScopeAlive;
final bool Function(String id, int epoch)? _isNodeEpochAlive;
RuntimeEvent attachSession(RuntimeEvent event) {
return event.withLifecycle(sessionId: event.sessionId ?? session.id);
}
bool accepts(RuntimeEvent event) {
final eventSessionId = event.sessionId;
if (eventSessionId != null && !session.accepts(eventSessionId)) {
return false;
}
final target = event.target;
final targetEpoch = event.targetEpoch;
final epochChecker = _isNodeEpochAlive;
if (target != null && targetEpoch != null && epochChecker != null) {
if (!epochChecker(target, targetEpoch)) {
return false;
}
}
final scope = event.scope;
if (scope != null && !_isScopeAlive(scope)) {
return false;
}
final scopeEpoch = event.scopeEpoch;
if (scope != null && scopeEpoch != null && epochChecker != null) {
if (!epochChecker(scope, scopeEpoch)) {
return false;
}
}
return true;
}
}