UNPKG

@zenithcore/core

Version:

Core functionality for ZenithKernel framework

1,546 lines (1,532 loc) 1.58 MB
var __create = Object.create; var __getProtoOf = Object.getPrototypeOf; var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __toESM = (mod, isNodeMode, target) => { target = mod != null ? __create(__getProtoOf(mod)) : {}; const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target; for (let key of __getOwnPropNames(mod)) if (!__hasOwnProp.call(to, key)) __defProp(to, key, { get: () => mod[key], enumerable: true }); return to; }; var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true, configurable: true, set: (newValue) => all[name] = () => newValue }); }; var __legacyDecorateClassTS = function(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1;i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res); // src/core/Messenger.ts class Messenger { queues = new Map; register(id) { this.queues.set(id, []); } unregister(id) { this.queues.delete(id); } send(targetId, message) { const queue = this.queues.get(targetId); if (queue) queue.push(message); } receive(id) { const queue = this.queues.get(id); return queue ? queue.splice(0, queue.length) : []; } } // src/core/BaseSystem.ts class BaseSystem { ecs; kernel; constructor(kernel) { this.kernel = kernel; this.ecs = kernel.getECS(); } query(component) { return this.ecs.getEntitiesWith(component); } } // src/core/Scheduler.ts var Scheduler; var init_Scheduler = __esm(() => { Scheduler = class Scheduler extends BaseSystem { static id = "Scheduler"; static instance = null; static getInstance(ecsManager) { if (!Scheduler.instance) { Scheduler.instance = new Scheduler(ecsManager); } return Scheduler.instance; } onLoad() {} onUnload() {} update() { this.tick(); } updateQueue = new Map; schedule(id, generatorFactory) { this.updateQueue.set(id, generatorFactory); } unschedule(id) { this.updateQueue.delete(id); } tick() { for (const [_, factory] of this.updateQueue) { const gen = factory(); gen.next(); } } }; }); // src/core/utils/EventEmitter.ts class EventEmitter { events = new Map; on(event, listener) { if (!this.events.has(event)) { this.events.set(event, []); } this.events.get(event).push(listener); return this; } once(event, listener) { const onceWrapper = (...args) => { listener(...args); this.off(event, onceWrapper); }; return this.on(event, onceWrapper); } off(event, listener) { if (!this.events.has(event)) { return this; } const listeners = this.events.get(event); const index = listeners.indexOf(listener); if (index !== -1) { listeners.splice(index, 1); } return this; } removeAllListeners(event) { if (event) { this.events.delete(event); } else { this.events.clear(); } return this; } emit(event, ...args) { if (!this.events.has(event)) { return false; } const listeners = this.events.get(event); for (const listener of listeners) { listener(...args); } return true; } listenerCount(event) { return this.events.get(event)?.length || 0; } listeners(event) { return this.events.get(event) || []; } } // src/core/signals.ts class SignalECSComponent { data; constructor(data) { this.data = data; } } class Signal { _value; _id; _name; _equals; _subscribers = new Set; _ecsEntity; _ecsManager; _debug; _scheduler; _errorHandler; _disposed = false; _accessCount = 0; _updateCount = 0; _lastAccess; _lastUpdate; _createdAt; constructor(initialValue, options = {}) { this._value = initialValue; this._id = ++signalIdCounter; this._name = options.name; this._equals = options.equals || Object.is; this._ecsEntity = options.ecsEntity; this._ecsManager = options.ecsManager; this._debug = options.debug || debugMode; this._scheduler = options.scheduler || "sync"; this._errorHandler = options.errorHandler; this._createdAt = Date.now(); debugLog(`Created signal ${this._id}`, { name: this._name, value: initialValue, scheduler: this._scheduler }); if (typeof this._ecsEntity === "number" && this._ecsManager && typeof this._ecsManager.addComponent === "function") { try { const componentData = { signalId: this._id, value: initialValue, type: "signal", name: this._name || `signal_${this._id}`, created: this._createdAt }; const signalComponentInstance = new SignalECSComponent(componentData); this._ecsManager.addComponent(this._ecsEntity, SignalECSComponent, signalComponentInstance); debugLog(`Signal ${this.id} registered with ECS entity ${this._ecsEntity}`); } catch (error) { this._handleError(new SignalError(`Failed to register with ECS: ${error.message}`, this._id, this._name)); } } } get value() { if (this._disposed) { throw new SignalError(`Cannot access disposed signal ${this._name || this._id}`, this._id, this._name); } this._accessCount++; this._lastAccess = Date.now(); if (currentComputation && !currentComputation.isDisposed) { this._subscribers.add(currentComputation); currentComputation.dependencies.add(this); debugLog(`Tracked dependency: signal ${this._id} (${this._name}) -> computation ${currentComputation.name || "anonymous"}`); } return this._value; } set value(newValue) { if (this._disposed) { throw new SignalError(`Cannot update disposed signal ${this._name || this._id}`, this._id, this._name); } if (!this._equals(this._value, newValue)) { const oldValue = this._value; this._value = newValue; this._updateCount++; this._lastUpdate = Date.now(); debugLog(`Signal ${this._id} (${this._name}) updated`, { oldValue, newValue, subscribers: this._subscribers.size }); this._notifySubscribers(); if (typeof this._ecsEntity === "number" && this._ecsManager && typeof this._ecsManager.addComponent === "function") { try { const componentData = { signalId: this._id, value: newValue, lastUpdated: this._lastUpdate, updateCount: this._updateCount, type: "signal", name: this._name || `signal_${this._id}`, created: this._createdAt }; const signalComponentInstance = new SignalECSComponent(componentData); this._ecsManager.addComponent(this._ecsEntity, SignalECSComponent, signalComponentInstance); debugLog(`Signal ${this.id} updated ECS entity ${this._ecsEntity}`); } catch (error) { this._handleError(new SignalError(`Failed to update ECS: ${error.message}`, this._id, this._name)); } } } } _notifySubscribers() { if (this._scheduler === "sync" && batchDepth === 0) { this._flushNotifications(); return; } if (!currentBatch) { currentBatch = new Set; } currentBatch.add(this); if (batchDepth === 0) { if (this._scheduler === "raf") { scheduleRafUpdate(); } else { scheduleMicrotaskUpdate(); } } } _flushNotifications() { if (this._subscribers.size === 0) return; debugLog(`Flushing notifications for signal ${this.id} (${this.name}) to ${this._subscribers.size} subscribers`); const subscribers = Array.from(this._subscribers); for (const computation of subscribers) { if (!computation.isDisposed) { try { computation.execute(); } catch (error) { this._handleError(new SignalError(`Computation error during flush for signal ${this.id}: ${error.message}`, this._id, this._name)); } } } } peek() { return this._value; } get id() { return this._id; } get name() { return this._name; } get subscriberCount() { return this._subscribers.size; } get isDisposed() { return this._disposed; } get accessCount() { return this._accessCount; } get updateCount() { return this._updateCount; } get lastAccess() { return this._lastAccess; } get lastUpdate() { return this._lastUpdate; } dispose() { if (this._disposed) return; debugLog(`Disposing signal ${this._id}`, { name: this._name, subscribers: this._subscribers.size }); this._disposed = true; const subscribersToNotify = Array.from(this._subscribers); this._subscribers.clear(); for (const comp of subscribersToNotify) { comp.dependencies.delete(this); if (!comp.isDisposed) { comp.execute(); } } if (typeof this._ecsEntity === "number" && this._ecsManager && typeof this._ecsManager.removeComponent === "function") { try { this._ecsManager.removeComponent(this._ecsEntity, SignalECSComponent); debugLog(`Signal ${this.id} removed from ECS entity ${this._ecsEntity}`); } catch (error) { this._handleError(new SignalError(`Failed to cleanup ECS: ${error.message}`, this._id, this._name)); } } } _handleError(error) { if (this._errorHandler) { this._errorHandler(error, this); } else { console.error(error.message, error.signalId ? `(Signal ID: ${error.signalId})` : "", error.signalName ? `(Name: ${error.signalName})` : ""); } } map(mapper, options) { return new ComputedSignal(() => mapper(this.value), { name: this._name ? `${this._name}.map` : undefined, debug: this._debug, scheduler: this._scheduler, errorHandler: this._errorHandler ? (err, sig) => this._errorHandler(err, this) : undefined, ...options }); } filter(predicate, options) { return new ComputedSignal(() => predicate(this.value) ? this.value : undefined, { name: this._name ? `${this._name}.filter` : undefined, debug: this._debug, scheduler: this._scheduler, errorHandler: this._errorHandler ? (err, sig) => this._errorHandler(err, this) : undefined, ...options }); } } class Computation { dependencies = new Set; _fn; _cleanup; _name; _disposed = false; _executing = false; _executionCount = 0; _lastExecution; _errorHandler; _isEffect = true; _recentExecutions = []; _pendingExecution = false; constructor(fn, options = {}, isEffect = true) { this._fn = fn; this._name = options.name; this._errorHandler = options.errorHandler; this._isEffect = isEffect; debugLog(`Created computation ${this._name || "anonymous"}`, { isEffect }); if (!options.defer) { this.execute(); } } execute() { if (this._disposed) { debugLog(`Attempted to execute disposed computation ${this._name || "anonymous"}`); return; } if (this._executing && this._isEffect) { this._pendingExecution = true; debugLog(`Computation ${this._name || "anonymous"} (effect) already executing, marking for re-execution.`); return; } if (this._isEffect) { const now = Date.now(); this._recentExecutions = this._recentExecutions.filter((time) => now - time < EXECUTION_TIME_WINDOW); if (this._recentExecutions.length >= MAX_EFFECT_EXECUTIONS_PER_COMPUTATION) { debugLog(`Effect execution limit reached (${MAX_EFFECT_EXECUTIONS_PER_COMPUTATION} in ${EXECUTION_TIME_WINDOW}ms), preventing infinite loop for ${this._name || "anonymous"}`); return; } this._recentExecutions.push(now); } this._executing = true; this._executionCount++; this._lastExecution = Date.now(); debugLog(`Executing computation ${this._name || "anonymous"}`, { count: this._executionCount, recentExecutions: this._recentExecutions.length }); for (const signal of this.dependencies) { signal._subscribers.delete(this); } this.dependencies.clear(); if (this._cleanup) { try { this._cleanup(); } catch (error) { this._handleError(error); } this._cleanup = undefined; } const prevComputation = currentComputation; currentComputation = this; try { const result = this._fn(); if (typeof result === "function") { this._cleanup = result; } } catch (error) { this._handleError(error); } finally { currentComputation = prevComputation; this._executing = false; if (this._pendingExecution && !this._disposed) { this._pendingExecution = false; debugLog(`Computation ${this._name || "anonymous"} has pending execution, running again.`); this.execute(); } } } dispose() { if (this._disposed) return; this._disposed = true; debugLog(`Disposing computation ${this._name || "anonymous"}`); for (const signal of this.dependencies) { signal._subscribers.delete(this); } this.dependencies.clear(); if (this._cleanup) { try { this._cleanup(); } catch (e) { this._handleError(e); } this._cleanup = undefined; } } get name() { return this._name; } get isDisposed() { return this._disposed; } get isExecuting() { return this._executing; } get executionCount() { return this._executionCount; } get lastExecution() { return this._lastExecution; } get dependencyCount() { return this.dependencies.size; } _handleError(error) { if (this._errorHandler) { this._errorHandler(error); } else { console.error(`Computation error in ${this._name || "anonymous"}:`, error); } } } function signal(initialValue, options) { return new Signal(initialValue, options); } function computed(fn, options) { return new ComputedSignal(fn, options); } function asyncSignal(loadFn, options) { return new AsyncSignal(undefined, loadFn, { initialState: "idle", ...options }); } function asyncSignalWithInitial(initialValue, loadFn, options) { return new AsyncSignal(initialValue, loadFn, { initialState: "idle", ...options }); } function effect(fn, options) { return new Computation(fn, options, true); } function resource(loadFn, options) { const asyncSig = new AsyncSignal(undefined, loadFn, { ...options, initialState: "loading" }); const valueSignal = computed(() => asyncSig.value, { name: options?.name ? `${options.name}.$value` : undefined, scheduler: options?.scheduler || "sync" }); const loadingSignal = computed(() => asyncSig.loading, { name: options?.name ? `${options.name}.$loadingState` : undefined, scheduler: "sync" }); const errorSignal = computed(() => asyncSig.error, { name: options?.name ? `${options.name}.$errorState` : undefined, scheduler: "sync" }); return [ valueSignal, { loading: loadingSignal, error: errorSignal, reload: () => asyncSig.reload() } ]; } function batch(fn) { if (batchDepth > 0) { debugLog("Nested batch call"); return fn(); } batchDepth++; debugLog(`Batch started (depth: ${batchDepth})`); const isOuterMostBatch = currentBatch === null; if (isOuterMostBatch) { currentBatch = new Set; } let result; try { result = fn(); if (batchDepth === 1) { debugLog(`Top-level batch finished, flushing updates...`); flushUpdates(); } } finally { batchDepth--; debugLog(`Batch ended (depth: ${batchDepth})`); if (batchDepth === 0) { if (isOuterMostBatch && currentBatch !== null) { currentBatch = null; debugLog("Global batch context explicitly cleared post-outermost batch."); } } } return result; } function untrack(fn) { const prevComputation = currentComputation; currentComputation = null; try { return fn(); } finally { currentComputation = prevComputation; } } function ecsSignal(initialValue, ecsEntity, ecsManager, options) { return new Signal(initialValue, { ...options, ecsEntity, ecsManager }); } function signalObject(obj, options) { const result = {}; for (const [key, value] of Object.entries(obj)) { result[key] = signal(value, { ...options, name: options?.name ? `${options.name}.${key}` : key }); } return result; } function createStore(initialState, options) { const signals = signalObject(initialState, options); const store = {}; for (const [key, signalInstance] of Object.entries(signals)) { Object.defineProperty(store, key, { get: () => signalInstance.value, set: (value) => { signalInstance.value = value; }, enumerable: true, configurable: true }); store[`$${key}`] = signalInstance; } return store; } function getCurrentComputation() { return currentComputation; } function isInBatch() { return batchDepth > 0; } function setDebugMode(enabled) { debugMode = enabled; debugLog(`Debug mode ${enabled ? "enabled" : "disabled"}`); } function getSignalRegistry() { console.warn("getSignalRegistry: Global signal registry not implemented in this version."); return new Map; } function resolve(value) { return value instanceof Signal ? value.value : value; } function isSignal(value) { return value instanceof Signal; } function derived(source, mapper, options) { return computed(() => mapper(source.value), { ...options, name: options?.name || (source.name ? `${source.name}.derived` : undefined) }); } function derivedWithSetter(source, getter, setter, options) { const derivedSignal = signal(getter(source.peek()), options); let internalUpdate = false; effect(() => { if (internalUpdate) return; const newDerivedValue = getter(source.value); internalUpdate = true; derivedSignal.value = newDerivedValue; internalUpdate = false; }); effect(() => { if (internalUpdate) return; const newSourceValue = setter(derivedSignal.value, source.peek()); internalUpdate = true; source.value = newSourceValue; internalUpdate = false; }); return derivedSignal; } function combine(signals, options) { return computed(() => signals.map((s) => s.value), options); } function fromPromise(promise, options) { const asyncOptions = { initialState: "loading", scheduler: "sync", ...options }; return new AsyncSignal(undefined, () => promise, asyncOptions); } function fromEvent(emitter, event, initialValue, mapper, options) { const sig = signal(initialValue, options); const handler = (data) => { sig.value = mapper ? mapper(data) : data; }; emitter.addEventListener(event, handler); return sig; } var currentComputation = null, currentBatch = null, batchDepth = 0, scheduledUpdate = null, MAX_EFFECT_EXECUTIONS_PER_COMPUTATION = 1000, EXECUTION_TIME_WINDOW = 100, signalIdCounter = 0, debugMode = false, debugLog = (message, ...args) => { if (debugMode) console.log(`[Signals] ${message}`, ...args); }, SignalError, scheduleRafUpdate = () => { if (scheduledUpdate === null) { scheduledUpdate = requestAnimationFrame(() => { scheduledUpdate = null; flushUpdates(); }); } }, scheduleMicrotaskUpdate = () => { if (scheduledUpdate === null) { scheduledUpdate = 1; Promise.resolve().then(() => { if (scheduledUpdate === 1) { scheduledUpdate = null; flushUpdates(); } }); } }, flushUpdates = () => { if (!currentBatch) return; const uniqueComputationsToRun = new Set; const batchToProcess = Array.from(currentBatch); currentBatch = null; for (const signal of batchToProcess) { for (const comp of signal._subscribers) { if (!comp.isDisposed) { uniqueComputationsToRun.add(comp); } } } debugLog(`Flushing updates for ${uniqueComputationsToRun.size} computations from ${batchToProcess.length} signals.`); for (const comp of uniqueComputationsToRun) { if (!comp.isDisposed) { comp.execute(); } } }, AsyncSignal, ComputedSignal; var init_signals = __esm(() => { SignalError = class SignalError extends Error { signalId; signalName; constructor(message, signalId, signalName) { super(message); this.signalId = signalId; this.signalName = signalName; this.name = "SignalError"; } }; AsyncSignal = class AsyncSignal extends Signal { _loadingSignal; _errorSignal; _timeout; _retryCount; _retryDelay; _currentRetry = 0; _loadFn; _currentLoadPromise = null; constructor(initialValue, loadFn, options = {}) { const baseOptions = { name: options.name, ecsEntity: options.ecsEntity, ecsManager: options.ecsManager, debug: options.debug, scheduler: options.scheduler || "sync", errorHandler: options.errorHandler, equals: options.equals }; super(initialValue, baseOptions); this._loadFn = loadFn; this._timeout = options.timeout; this._retryCount = options.retryCount || 0; this._retryDelay = options.retryDelay || 1000; const isLoadingInitially = options.initialState === "loading"; this._loadingSignal = signal(isLoadingInitially, { name: options.name ? `${options.name}.$loading` : undefined, scheduler: "sync" }); this._errorSignal = signal(null, { name: options.name ? `${options.name}.$error` : undefined, scheduler: "sync" }); if (isLoadingInitially) { this.reload().catch((err) => { debugLog(`AsyncSignal ${this.id} (${this.name}) initial reload() call resulted in error: `, err); if (this._errorSignal.peek() === null) { this._errorSignal.value = err instanceof Error ? err : new SignalError(String(err), this.id, this.name); } if (this._loadingSignal.peek()) { this._loadingSignal.value = false; } }); } } get loading() { return this._loadingSignal.value; } get error() { return this._errorSignal.value; } get isSuccess() { return !this._loadingSignal.peek() && !this._errorSignal.peek() && this.peek() !== undefined; } async reload() { if (this._loadingSignal.peek() && this._currentLoadPromise) { debugLog(`AsyncSignal ${this.id} (${this.name}) reload called while already loading.`); return this._currentLoadPromise; } this._loadingSignal.value = true; this._errorSignal.value = null; this._currentRetry = 0; this._currentLoadPromise = this._attemptLoad(); return this._currentLoadPromise; } async _attemptLoad() { let result = undefined; let caughtError = null; debugLog(`AsyncSignal ${this.id} (${this.name}) attempting load (attempt ${this._currentRetry + 1}).`); try { let loadPromise = this._loadFn(); if (this._timeout) { const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new SignalError(`Timeout after ${this._timeout}ms`, this.id, this.name)), this._timeout); }); loadPromise = Promise.race([loadPromise, timeoutPromise]); } result = await loadPromise; } catch (error) { caughtError = error instanceof Error ? error : new SignalError(String(error), this.id, this.name); } const updateSignalStates = () => { if (this.isDisposed) { debugLog(`AsyncSignal ${this.id} (${this.name}) disposed during load/retry. Aborting state update.`); return; } if (caughtError) { if (this._currentRetry < this._retryCount) { this._currentRetry++; debugLog(`AsyncSignal ${this.id} (${this.name}) retrying load... (${this._currentRetry}/${this._retryCount})`, { error: caughtError }); this._loadingSignal.value = true; this._errorSignal.value = null; setTimeout(() => { if (!this.isDisposed) this._attemptLoad(); }, this._retryDelay * Math.pow(2, this._currentRetry - 1)); } else { debugLog(`AsyncSignal ${this.id} (${this.name}) load failed after all retries.`, { error: caughtError }); this._errorSignal.value = caughtError; this._loadingSignal.value = false; } } else { debugLog(`AsyncSignal ${this.id} (${this.name}) loaded successfully.`, { value: result }); this.value = result; this._errorSignal.value = null; this._loadingSignal.value = false; } }; if (this._scheduler === "sync" && batchDepth === 0) { updateSignalStates(); } else { batch(updateSignalStates); } if (!caughtError || this._currentRetry >= this._retryCount) { this._currentLoadPromise = null; } } dispose() { this._loadingSignal.dispose(); this._errorSignal.dispose(); super.dispose(); } }; ComputedSignal = class ComputedSignal extends Signal { _computation; _fn; constructor(fn, options = {}) { const { defer, errorHandler, ...baseSignalOptions } = options; super(undefined, baseSignalOptions); this._fn = fn; let adaptedComputationErrorHandler = undefined; if (errorHandler) { adaptedComputationErrorHandler = (err) => errorHandler(err, this); } else if (this._errorHandler) { adaptedComputationErrorHandler = (err) => this._errorHandler(err, this); } this._computation = new Computation(() => { const newValue = this._fn(); if (this._computation.executionCount === 1 && this._value === undefined && newValue !== undefined || !this._equals(this._value, newValue)) { this._value = newValue; this._notifySubscribers(); } }, { defer: true, name: options.name || (this._fn && this._fn.name ? `computed(${this._fn.name})` : "computed"), errorHandler: adaptedComputationErrorHandler }, false); if (!defer) { this._computation.execute(); } } get value() { if (this._disposed) { throw new SignalError(`Cannot access disposed computed signal ${this.name || this.id}`); } if (this._computation.executionCount === 0 && !this._computation.isDisposed) { debugLog(`Computed signal ${this.id} (${this.name}) accessed, running initial/deferred computation.`); this._computation.execute(); } return super.value; } set value(_) { throw new SignalError("Cannot set value of computed signal", this.id, this.name); } dispose() { this._computation.dispose(); super.dispose(); } }; }); // src/core/ECSManager.ts var exports_ECSManager = {}; __export(exports_ECSManager, { Query: () => Query, ECSManager: () => ECSManager }); class SparseSet { sparse; dense; _count = 0; constructor(capacity = DEFAULT_ENTITY_POOL_SIZE) { this.sparse = new Uint32Array(capacity); this.dense = new Uint32Array(capacity); } add(id) { if (id >= this.sparse.length) { this.resize(Math.max(id + 1, this.sparse.length * 2)); } if (this.has(id)) return false; this.dense[this._count] = id; this.sparse[id] = this._count; this._count++; return true; } remove(id) { if (!this.has(id)) return false; const denseIndex = this.sparse[id]; const lastId = this.dense[this._count - 1]; this.dense[denseIndex] = lastId; this.sparse[lastId] = denseIndex; this.dense[this._count - 1] = 0; this._count--; return true; } has(id) { return id < this.sparse.length && this.sparse[id] < this._count && this.dense[this.sparse[id]] === id; } get count() { return this._count; } get entities() { return this.dense.subarray(0, this._count); } resize(newCapacity) { logDebug(`SparseSet resizing sparse from ${this.sparse.length} to ${newCapacity}`); const newSparse = new Uint32Array(newCapacity); newSparse.set(this.sparse); this.sparse = newSparse; if (newCapacity > this.dense.length) { logDebug(`SparseSet resizing dense from ${this.dense.length} to ${newCapacity}`); const newDense = new Uint32Array(newCapacity); newDense.set(this.dense); this.dense = newDense; } } } class Query { _id; _required = []; _excluded = []; _entities; _dirty = true; _bitflags = new Map; _requiredMask = 0; _excludedMask = 0; constructor(id, required = [], excluded = []) { this._id = id; this._required = [...required]; this._excluded = [...excluded]; this._entities = new SparseSet; } get id() { return this._id; } get required() { return [...this._required]; } get excluded() { return [...this._excluded]; } get entities() { return this._entities.entities; } get count() { return this._entities.count; } setBitflags(componentName, flag) { this._bitflags.set(componentName, flag); this._recalculateMasks(); this._dirty = true; } _recalculateMasks() { this._requiredMask = 0; for (const compName of this._required) { this._requiredMask |= this._bitflags.get(compName) || 0; } this._excludedMask = 0; for (const compName of this._excluded) { this._excludedMask |= this._bitflags.get(compName) || 0; } } matches(entityMask) { const matchesRequired = (entityMask & this._requiredMask) === this._requiredMask; const matchesExcluded = (entityMask & this._excludedMask) === 0; return matchesRequired && matchesExcluded; } addEntity(entityId) { this._entities.add(entityId); } removeEntity(entityId) { this._entities.remove(entityId); } hasEntity(entityId) { return this._entities.has(entityId); } markDirty() { this._dirty = true; } isDirty() { return this._dirty; } markClean() { this._dirty = false; } } var DEFAULT_ENTITY_POOL_SIZE = 1e4, DEBUG_ECS = false, logDebug = (message, ...args) => { if (DEBUG_ECS) console.log(`[ECSManager DEBUG] ${message}`, ...args); }, ECSManager; var init_ECSManager = __esm(() => { init_signals(); ECSManager = class ECSManager extends EventEmitter { componentTypes = new Map; componentSerializers = new Map; componentDeserializers = new Map; components = new Map; nextEntityId = 0; removedEntities = []; entities = new SparseSet(DEFAULT_ENTITY_POOL_SIZE); entityMasks = new Map; entityComponentNames = new Map; componentNameBitflags = new Map; nextComponentBitflag = 1; queries = new Map; kernelRef; systems = []; entityNames = new Map; constructor() { super(); } setKernel(kernel) { this.kernelRef = kernel; } getSystems() { return [...this.systems]; } get kernel() { if (!this.kernelRef) throw new Error("ECSManager: Kernel reference not set."); return this.kernelRef; } addSystem(system) { if (!system) { console.warn("[ECSManager] Attempted to add undefined system"); return; } this.systems.push(system); if (typeof system.init === "function") { system.init(); } else { logDebug(`System ${system.constructor.name} has no init method`); } } registerSystem(system) { if (!system) { console.warn("[ECSManager] Attempted to register undefined system"); return; } if (this.systems.includes(system)) { console.warn("[ECSManager] System already registered", system); return; } this.addSystem(system); logDebug(`Registered system: ${system.constructor.name}`); } updateSystems() { for (const system of this.systems) { system.update(); } } createEntity() { const entityId = this.removedEntities.length > 0 ? this.removedEntities.pop() : this.nextEntityId++; this.entities.add(entityId); this.entityMasks.set(entityId, 0); this.entityComponentNames.set(entityId, new Set); logDebug(`Entity created: ${entityId}`); this.emit("entityCreated", entityId); return entityId; } destroyEntity(entity) { if (!this.entities.has(entity)) { logDebug(`Attempted to destroy non-existent entity: ${entity}`); return; } const componentNames = this.entityComponentNames.get(entity); if (componentNames) { [...componentNames].forEach((compName) => this.removeComponentByTypeName(entity, compName, true)); } this.entities.remove(entity); this.entityMasks.delete(entity); this.entityComponentNames.delete(entity); this.removedEntities.push(entity); logDebug(`Entity destroyed: ${entity}`); this.emit("entityRemoved", entity); } _getComponentTypeName(type) { return type.typeName || type.name; } addComponent(entity, type, instance) { const typeName = this._getComponentTypeName(type); if (!this.entities.has(entity)) { logDebug(`Entity ${entity} not tracked, adding implicitly with component ${typeName}.`); this.entities.add(entity); this.entityMasks.set(entity, 0); this.entityComponentNames.set(entity, new Set); if (entity >= this.nextEntityId) { this.nextEntityId = entity + 1; } } let componentMap = this.components.get(typeName); if (!componentMap) { componentMap = new Map; this.components.set(typeName, componentMap); } const existingInstance = componentMap.get(entity); componentMap.set(entity, instance); if (!this.componentNameBitflags.has(typeName)) { const bitflag2 = this.nextComponentBitflag; this.nextComponentBitflag <<= 1; if (this.nextComponentBitflag === 0) { console.error("ECSManager: Component bitflag overflow! Too many component types."); } this.componentNameBitflags.set(typeName, bitflag2); logDebug(`Assigned bitflag ${bitflag2} to component type ${typeName}`); this.queries.forEach((query) => query.markDirty()); } const entityComponentsSet = this.entityComponentNames.get(entity); const hadComponentBefore = entityComponentsSet.has(typeName); entityComponentsSet.add(typeName); const bitflag = this.componentNameBitflags.get(typeName); const currentMask = this.entityMasks.get(entity); const newMask = currentMask | bitflag; if (currentMask !== newMask) { this.entityMasks.set(entity, newMask); this._updateEntityQueries(entity); } logDebug(`Component ${typeName} ${existingInstance ? "updated on" : "added to"} entity ${entity}. Mask: ${newMask.toString(2)}`); this.emit("componentAdded", { entity, componentType: typeName, instance }); if (typeName === "EntityNameComponent" && instance && typeof instance.name === "string") { const entityName = instance.name; if (this.entityNames.has(entityName) && this.entityNames.get(entityName) !== entity) { logDebug(`Warning: Entity name "${entityName}" was already registered to entity ${this.entityNames.get(entityName)}. Re-registering to ${entity}.`); } this.entityNames.set(entityName, entity); logDebug(`Entity ${entity} named "${entityName}"`); } return instance; } updateComponent(entity, type, updatedData) { const typeName = this._getComponentTypeName(type); const componentMap = this.components.get(typeName); if (!componentMap || !componentMap.has(entity)) { logDebug(`Update failed: Component ${typeName} not found on entity ${entity}.`); return false; } const currentInstance = componentMap.get(entity); if (currentInstance instanceof SignalECSComponent && typeof currentInstance.data === "object" && currentInstance.data !== null) { Object.assign(currentInstance.data, updatedData); logDebug(`Component ${typeName} (SignalECSComponent data) updated on entity ${entity}.`); } else if (typeof currentInstance === "object" && currentInstance !== null) { Object.assign(currentInstance, updatedData); logDebug(`Component ${typeName} (generic object) updated on entity ${entity}.`); } else { console.warn(`ECSManager: Component ${typeName} on entity ${entity} is not an updatable object.`); return false; } this.emit("componentUpdated", { entity, componentType: typeName, instance: currentInstance }); return true; } getComponent(entity, type) { const typeName = this._getComponentTypeName(type); const instance = this.components.get(typeName)?.get(entity); logDebug(`getComponent ${typeName} for entity ${entity}: ${instance ? "found" : "not found"}`); return instance; } removeComponent(entity, type) { const typeName = this._getComponentTypeName(type); return this.removeComponentByTypeName(entity, typeName); } removeComponentByTypeName(entity, typeName, isDestroyingEntity = false) { if (!this.entities.has(entity)) { logDebug(`Remove failed: Entity ${entity} not found.`); return false; } const componentMap = this.components.get(typeName); const existedInMap = componentMap?.delete(entity) || false; if (componentMap && componentMap.size === 0) { this.components.delete(typeName); } const entityComponents = this.entityComponentNames.get(entity); let existedInEntitySet = false; if (entityComponents?.delete(typeName)) { existedInEntitySet = true; const bitflag = this.componentNameBitflags.get(typeName); if (bitflag !== undefined) { const currentMask = this.entityMasks.get(entity) || 0; this.entityMasks.set(entity, currentMask & ~bitflag); if (!isDestroyingEntity) { this._updateEntityQueries(entity); } } logDebug(`Component ${typeName} removed from entity ${entity}.`); this.emit("componentRemoved", { entity, componentType: typeName }); } return existedInMap || existedInEntitySet; } _updateEntityQueries(entity) { const mask = this.entityMasks.get(entity) || 0; logDebug(`Updating queries for entity ${entity} with mask ${mask.toString(2)}`); this.queries.forEach((query) => { const wasInQuery = query.hasEntity(entity); const shouldBeInQuery = query.matches(mask); if (shouldBeInQuery && !wasInQuery) { query.addEntity(entity); logDebug(`Entity ${entity} added to query ${query.id}`); } else if (!shouldBeInQuery && wasInQuery) { query.removeEntity(entity); logDebug(`Entity ${entity} removed from query ${query.id}`); } }); } removeSystem(system) { const index = this.systems.indexOf(system); if (index !== -1) this.systems.splice(index, 1); logDebug(`System removed: ${system.constructor.name}`); } getEntitiesWith(type) { const typeName = this._getComponentTypeName(type); const map = this.components.get(typeName); return map ? Array.from(map.entries()) : []; } defineQuery(id, requiredNames = [], excludedNames = []) { if (this.queries.has(id)) throw new Error(`Query ${id} already exists`); const query = new Query(id, requiredNames, excludedNames); logDebug(`Defining query ${id}: Required [${requiredNames.join(", ")}], Excluded [${excludedNames.join(", ")}]`); const allQueryComponentNames = new Set([...requiredNames, ...excludedNames]); allQueryComponentNames.forEach((compName) => { if (!this.componentNameBitflags.has(compName)) { const bitflag = this.nextComponentBitflag; this.nextComponentBitflag <<= 1; if (this.nextComponentBitflag === 0) console.error("ECSManager: Component bitflag overflow!"); this.componentNameBitflags.set(compName, bitflag); logDebug(`Assigned new bitflag ${bitflag} to component type ${compName} for query ${id}`); } query.setBitflags(compName, this.componentNameBitflags.get(compName)); }); for (let i = 0;i < this.entities.count; i++) { const entityId = this.entities.entities[i]; const mask = this.entityMasks.get(entityId) || 0; if (query.matches(mask)) query.addEntity(entityId); } this.queries.set(id, query); logDebug(`Query ${id} defined with ${query.count} initial entities.`); return query; } getQuery(id) { return this.queries.get(id); } removeQuery(id) { this.queries.delete(id); logDebug(`Query ${id} removed.`); } dumpComponentMap() { return this.components; } getEntitiesWithQuery(queryId) { const query = this.queries.get(queryId); if (!query) throw new Error(`Query ${queryId} does not exist`); if (query.isDirty()) { logDebug(`Query ${queryId} was dirty, re-evaluating.`); this.entities.entities.forEach((entityId) => { const mask = this.entityMasks.get(entityId) || 0; const matches = query.matches(mask); const hasEntityInQuery = query.hasEntity(entityId); if (matches && !hasEntityInQuery) query.addEntity(entityId); else if (!matches && hasEntityInQuery) query.removeEntity(entityId); }); query.markClean(); } return Array.from(query.entities); } hasComponent(entity, type) { const typeName = this._getComponentTypeName(type); return this.entityComponentNames.get(entity)?.has(typeName) || false; } getEntityComponents(entity) { return this.entities.has(entity) ? Array.from(this.entityComponentNames.get(entity)) : []; } registerComponentType(typeName, componentType, serializer, deserializer) { if (componentType && typeof componentType === "function") { if (!componentType.typeName) { componentType.typeName = typeName; } this.componentTypes.set(typeName, componentType); if (DEBUG_ECS) { console.log(`[ECSManager] Registered component type: ${typeName}`); } if (serializer) { this.componentSerializers.set(typeName, serializer); } if (deserializer) { this.componentDeserializers.set(typeName, deserializer); } } else { throw new Error(`Invalid component type provided for ${typeName}`); } } getComponentType(typeName) { return this.componentTypes.get(typeName); } serializeComponent(typeName, component) { const serializer = this.componentSerializers.get(typeName); if (serializer) { return serializer(component); } return component; } deserializeComponent(typeName, data) { const deserializer = this.componentDeserializers.get(typeName); if (deserializer) { return deserializer(data); } const componentType = this.componentTypes.get(typeName); if (componentType) { try { return new componentType(data); } catch (e) { console.error(`Error deserializing component ${typeName}:`, e); } } return data; } getEntitiesWithComponent(componentTypeName) { const queryId = `__internal_query_for_${componentTypeName}`; if (!this.queries.has(queryId)) { this.defineQuery(queryId, [componentTypeName]); } return this.getEntitiesWithQuery(queryId); } getEntityCount() { return this.entities.count; } getComponentTypeCount() { return this.componentNameBitflags.size; } getAllEntities() { return Array.from(this.entities.entities); } getPerformanceStats() { return { entities: this.entities.count, components: this.componentNameBitflags.size, queries: this.queries.size, recycledEntities: this.removedEntities.length }; } static get SparseSet() { return SparseSet; } }; }); // src/decorators/RegisterSystem.ts function RegisterSystem(id, dependsOn = []) { return function(target) { if (registered.has(target)) return; registered.add(target); systemRegistry.push({ id, dependsOn, cls: target }); }; } function getRegisteredSystems() { return systemRegistry; } var systemRegistry, registered; var init_RegisterSystem = __esm(() => { systemRegistry = []; registered = new Set; }); // src/core/SystemManager.ts var SystemManager; var init_SystemManager = __esm(() => { init_RegisterSystem(); SystemManager = class SystemManager extends BaseSystem { onLoad() { throw new Error("Method not implemented."); } onUnload() { throw new Error("Method not implemented."); } systems = new Map; loadOrder = []; constructor(ecs) { super(ecs); } init() { const registry = getRegisteredSystems(); const visited = new Set; const stack = new Set; const resolve2 = (id) => { if (stack.has(id)) throw new Error(`Cyclic dependency: ${id}`); if (visited.has(id)) return; stack.add(id); const entry = registry.find((r) => r.id === id); if (!entry) throw new Error(`Unknown system id: ${id}`); for (const dep of entry.dependsOn) resolve2(dep); visited.add(id); stack.delete(id); this.loadOrder.push(id); }; for (const { id } of registry) resolve2(id); for (const id of this.loadOrder) { const entry = registry.find((r) => r.id === id); const instance = new entry.cls(this.ecs); instance.init?.(); this.systems.set(id, instance); } } update() { for (const id of this.loadOrder) { console.log("Updating", id); this.systems.get(id).update(); } } dispose() { for (const id of [...this.loadOrder].reverse()) { this.systems.get(id)?.dispose?.(); } } }; }); // src/core/ZenithKernel.ts var exports_ZenithKernel = {}; __export(exports_ZenithKernel, { ZenithKernel: () => ZenithKernel }); class ZenithKernel { enableDiagnostics() { console.log("Diagnostics enabled"); } enableHotReload() { console.log("Hot reload enabled"); } setLogLevel(logLevel) { console.log(`Log level set to: ${logLevel}`); } initialize() { console.log("ZenithKernel initialized"); return this; } getSystem(systemId) { return this.dynamicSystems.get(systemId); } startLoop() { console.log("Kernel loop started"); return this; } setOnlineStatus(isOnline) { console.log(`Online status set to: ${isOnline}`); return this; } stop() { console.log("Kernel stopped"); } modules = new Map; messenger = new Messenger; scheduler; ecs = new ECSManager; systemManager = new SystemManager(this.ecs); dynamicSystems = new Map; router; islands = new Map; hydratedIslands = new WeakMap; messageHandlers = new Map; debug = true; constructor() { this.messenger.register("kernel"); } getECS() { return this.ecs; } getRouter() { return this.router; } setRouter(router) { this.router = router; } unregisterSystem(systemId) { const system = this.dynamicSystems.get(systemId); if (!system) { console.warn(`⚠️ System "${systemId}" not found.`); return; } this.dynamicSystems.delete(systemId); this.ecs.removeSystem(system); if (this.debug) { console.info(`[ZenithKernel] Unregistered system: ${systemId}`); } } hotSwapSystem(systemId, NewCtor) { this.unregisterSystem(systemId); const instance = new NewCtor(this); this.registerSystem(systemId, instance); if (this.debug) { console.info(`[ZenithKernel] Hot-swapped system: ${systemId}`); } } registerMessageHandler(messageType, handler) { if (!this.messageHandlers.has(messageType)) { this.messageHandlers.set(messageType, []); } const handlers = this.messageHandlers.get(messageType); if (handlers) { handlers.push(handler); } if (this.debug) { console.info(`[ZenithKernel] Registered message handler for type: ${messageType}`); } } send(targetId, message) { this.messenger.send(targetId, message); if (this.debug) { console.info(`[ZenithKernel] Sent message to ${targetId}:`, message); } } sendMessage(messageType, payload = {}) { const handlers = this.messageHandlers.get(messageType); if (handlers && handlers.length > 0) { const message = { type: messageType, payload, timestamp: Date.now() }; handlers.forEach((handler) => { try { handler(message); } catch (error) { console.error(`[ZenithKernel] Error in message handler for ${messageType}:`, error); } }); } } g