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,50 @@
class RuntimeAsyncGate {
RuntimeAsyncGate({bool initiallyClosed = false}) : _closed = initiallyClosed;
int _generation = 0;
bool _closed;
int get generation => _generation;
bool get isOpen => !_closed;
bool get isClosed => _closed;
RuntimeAsyncToken get token => RuntimeAsyncToken._(this, _generation);
RuntimeAsyncToken activate() {
_closed = false;
_generation++;
return token;
}
RuntimeAsyncToken advance() {
_generation++;
return token;
}
RuntimeAsyncToken close() {
_closed = true;
_generation++;
return token;
}
bool accepts(RuntimeAsyncToken token) {
return !_closed &&
identical(token._gate, this) &&
token.generation == _generation;
}
bool acceptsGeneration(int generation) {
return !_closed && generation == _generation;
}
}
class RuntimeAsyncToken {
const RuntimeAsyncToken._(this._gate, this.generation);
final RuntimeAsyncGate _gate;
final int generation;
bool get isAccepted => _gate.accepts(this);
}

View File

@@ -0,0 +1,77 @@
import 'dart:async' as async;
class RuntimeSerialQueue<T> {
RuntimeSerialQueue({required this.onItem, bool Function()? shouldContinue})
: _shouldContinue = shouldContinue;
final void Function(T item) onItem;
final bool Function()? _shouldContinue;
final List<T> _queue = [];
int _head = 0;
bool _disposed = false;
bool _draining = false;
int get pendingCount => _queue.length - _head;
bool get isDraining => _draining;
bool get isDisposed => _disposed;
void enqueue(T item) {
if (_disposed || !_canContinue()) {
return;
}
_queue.add(item);
_scheduleDrain();
}
void clear() {
_queue.clear();
_head = 0;
}
void dispose() {
_disposed = true;
clear();
}
void _scheduleDrain() {
if (_draining) {
return;
}
_draining = true;
async.scheduleMicrotask(_drain);
}
void _drain() {
try {
while (pendingCount > 0 && !_disposed && _canContinue()) {
onItem(_queue[_head++]);
_compactIfNeeded();
}
} finally {
_draining = false;
}
if (pendingCount > 0 && !_disposed && _canContinue()) {
_scheduleDrain();
}
}
void _compactIfNeeded() {
if (_head == 0) {
return;
}
if (_head == _queue.length) {
clear();
return;
}
if (_head < 32 || _head * 2 < _queue.length) {
return;
}
_queue.removeRange(0, _head);
_head = 0;
}
bool _canContinue() => _shouldContinue?.call() ?? true;
}

View File

@@ -0,0 +1,71 @@
enum RuntimeSessionState { created, loading, active, disposing, disposed }
class RuntimeSession {
RuntimeSession({required this.gameId}) : id = _nextId++;
static int _nextId = 1;
final int id;
final String gameId;
RuntimeSessionState _state = RuntimeSessionState.created;
RuntimeSessionState get state => _state;
bool get isLoading => _state == RuntimeSessionState.loading;
bool get isActive => _state == RuntimeSessionState.active;
bool get isDisposing => _state == RuntimeSessionState.disposing;
bool get isDisposed => _state == RuntimeSessionState.disposed;
bool get acceptsWork =>
_state != RuntimeSessionState.disposing &&
_state != RuntimeSessionState.disposed;
void beginLoading() {
_transition(
RuntimeSessionState.loading,
allowedFrom: const {RuntimeSessionState.created},
);
}
void activate() {
_transition(
RuntimeSessionState.active,
allowedFrom: const {
RuntimeSessionState.created,
RuntimeSessionState.loading,
},
);
}
void beginDisposing() {
if (_state == RuntimeSessionState.disposed ||
_state == RuntimeSessionState.disposing) {
return;
}
_state = RuntimeSessionState.disposing;
}
void dispose() {
_state = RuntimeSessionState.disposed;
}
bool accepts(int sessionId) => isActive && id == sessionId;
bool acceptsWorkFor(int sessionId) => acceptsWork && id == sessionId;
void _transition(
RuntimeSessionState next, {
required Set<RuntimeSessionState> allowedFrom,
}) {
if (_state == next) {
return;
}
if (!allowedFrom.contains(_state)) {
throw StateError('Invalid runtime session transition: $_state -> $next');
}
_state = next;
}
}

View File

@@ -0,0 +1,129 @@
import 'dart:async' as async;
class RuntimeTaskRegistry<T> {
RuntimeTaskRegistry({required this.cancelledValue});
final T cancelledValue;
final Set<RuntimeTask<T>> _tasks = {};
final Map<String, Set<RuntimeTask<T>>> _tasksByScope = {};
bool _disposed = false;
int get activeTaskCount => _tasks.length;
int scopedTaskCount(String scope) => _tasksByScope[scope]?.length ?? 0;
RuntimeTask<T> create({String? scope}) {
if (_disposed) {
throw StateError('RuntimeTaskRegistry has been disposed');
}
late final RuntimeTask<T> task;
task = RuntimeTask<T>._(
scope: scope,
cancelledValue: cancelledValue,
onComplete: _unregister,
);
_tasks.add(task);
if (scope != null) {
_tasksByScope.putIfAbsent(scope, () => {}).add(task);
}
return task;
}
void cancelScope(String scope) {
final tasks = _tasksByScope[scope]?.toList(growable: false) ?? const [];
for (final task in tasks) {
task.cancel();
}
}
void dispose() {
if (_disposed) {
return;
}
_disposed = true;
final tasks = _tasks.toList(growable: false);
for (final task in tasks) {
task.cancel();
}
_tasks.clear();
_tasksByScope.clear();
}
void _unregister(RuntimeTask<T> task) {
_tasks.remove(task);
final scope = task.scope;
if (scope == null) {
return;
}
final scopedTasks = _tasksByScope[scope];
scopedTasks?.remove(task);
if (scopedTasks != null && scopedTasks.isEmpty) {
_tasksByScope.remove(scope);
}
}
}
class RuntimeTask<T> {
RuntimeTask._({
required this.scope,
required this.cancelledValue,
required void Function(RuntimeTask<T> task) onComplete,
}) : _onComplete = onComplete;
final String? scope;
final T cancelledValue;
final void Function(RuntimeTask<T> task) _onComplete;
final async.Completer<T> _completer = async.Completer<T>();
final Set<async.Timer> _timers = {};
final List<void Function()> _cancelCallbacks = [];
bool _cancelled = false;
Future<T> get future => _completer.future;
bool get isCancelled => _cancelled;
void addTimer(async.Timer timer) {
if (_cancelled) {
timer.cancel();
return;
}
_timers.add(timer);
}
void removeTimer(async.Timer timer) {
_timers.remove(timer);
}
void addCancelCallback(void Function() callback) {
if (_cancelled) {
callback();
return;
}
_cancelCallbacks.add(callback);
}
void complete(T result) {
if (_completer.isCompleted) {
return;
}
_completer.complete(result);
_onComplete(this);
}
void cancel() {
if (_cancelled) {
return;
}
_cancelled = true;
for (final timer in _timers) {
timer.cancel();
}
_timers.clear();
for (final callback in _cancelCallbacks) {
callback();
}
_cancelCallbacks.clear();
complete(cancelledValue);
}
}