import { Disposable } from '@gedit/utils'; import { Transition, CustomScript, GameStart } from '@gedit/runtime-types'; import { ScriptPrinter, SpecScriptPrinter } from './common'; import { GameObjectData, GameResource } from '@gedit/render-engine'; import type { SceneActions } from '@gedit/runtime-types'; export const MAIN_SCRIPT_ID = Symbol('main'); /** * import a from 'xxx'; */ export interface ScriptImport { scriptId: Symbol; defaultName?: string; identifiers?: string[]; alias?: string[]; } /** * export a; */ export interface ScriptExport { identifier: string; isDefault: boolean; } /** * Component, * Event, * Transition, * Resource, */ export interface ScriptContent { start: GameStart, // 开始的loading loading: GameStart // 加载的loading components: GameObjectData[], resources: GameResource[]; transitions: Transition[]; actions: SceneActions; customScripts: CustomScript[]; } export interface ScriptReference { index: number; id: Symbol; content: ScriptContent; name?: string, code?: string; imports: ScriptImport[]; exports: ScriptExport[]; } export interface ScriptAst { [key: string]: ScriptReference; } export interface Scripts { [key: string]: ScriptReference; } export class ScriptContext { static COUNT = 1; readonly ref: ScriptReference; readonly printer: ScriptPrinter; readonly spec: SpecScriptPrinter; constructor(id: Symbol) { this.ref = { index: ScriptContext.COUNT++, id, imports: [], exports: [], content: { start: { sceneId: '', }, loading: { sceneId: '' }, components: [], resources: [], transitions: [], actions: { main: '', transitions: [], actions: [], }, customScripts: [], }, }; this.printer = new ScriptPrinter(); this.spec = new SpecScriptPrinter(this.printer); } identifier(...args: string[]): string { return args.join('_') + '_' + this.ref.index; } } export class ScriptManager implements Disposable { private _refs: Map; private _current: Symbol; constructor() { this._refs = new Map(); this._current = MAIN_SCRIPT_ID; // 默认创建 main script this.addScript(MAIN_SCRIPT_ID); } private _checkNotFound(id: Symbol): void { if (!this._refs.get(id)) { throw new Error(`script ${id.toString()} not found!`); } } get main(): ScriptContext { return this.getScript(MAIN_SCRIPT_ID); } get current(): ScriptContext { return this.getScript(this._current); } addScript(id?: Symbol): Symbol { const scriptId = id || Symbol(); const context = new ScriptContext(scriptId); this._refs.set(scriptId, context); return scriptId; } exportValue(identifier: string, isDefault: boolean): void { const script = this.current; if (isDefault) { const scriptExport = script.ref.exports.find(v => v.isDefault); if (scriptExport) { throw new Error('can only have one default export!'); } } script.ref.exports.push({ identifier, isDefault }); } importValue(scriptId: Symbol, defaultName: string = '', identifiers: string[] = [], alias: string[] = []): void { const script = this.current; script.ref.imports.push({ scriptId, defaultName, identifiers, alias, }); } getScript(id: Symbol): ScriptContext { const context = this._refs.get(id); this._checkNotFound(id); return context!; } changeToScript(next: Symbol): void { this._current = next; } resetToMain(): void { this._current = MAIN_SCRIPT_ID; } dispose(): void { this._refs.clear(); } }