workspaces folders

This commit is contained in:
azykov@mail.ru
2026-06-12 11:46:14 +03:00
parent 88b36988ff
commit 36f76efdd7
102 changed files with 0 additions and 0 deletions
+112
View File
@@ -0,0 +1,112 @@
import type { Game, RuntimeGameScene, RuntimeScene, World } from "../types";
import type { GameEventContext, GameEventHandler, GeneratorEventHandler, InternalGameEventBus } from "../types/runtime/gameBus";
import { clone } from "../utils";
import { populateRuntimeScene } from "../utils/runtime";
import { ObjectApi } from "../utils/runtime/objectApi";
import type { GameScheduler, YieldCommand } from "./gameScheduler";
export class GameEventBus {
private handlers = new Map<string, GameEventHandler[]>();
on(event: string, handler: GameEventHandler): void {
console.log('subscribing to ' + event, handler);
let set = this.handlers.get(event);
if (!set) {
set = [];
this.handlers.set(event, set);
}
if (!set.includes(handler))
set.push(handler);
}
off(event: string, handler: GameEventHandler): void {
console.log('unubscribing from ' + event, handler);
const handlers = this.handlers.get(event);
if (!handlers)
return;
this.handlers.set(event, handlers.filter((h) => h !== handler));
}
emit(event: string, context: GameEventContext): void {
console.log('emitting ' + event);
this.handlers.get(event)
?.forEach((handler) => handler(context));
}
}
export class GameFactory {
public static create(world: World): Game {
const scene = populateRuntimeScene(clone(world.initialScene), world);
const game = {
paused: false,
time: 0,
scene: GameFactory.initGameScene(scene),
};
return game;
}
public static load(): Game | undefined {
const json = localStorage.getItem("game");
if (json) {
return JSON.parse(json) as Game;
}
}
public static save(game: Game): void {
localStorage.setItem("game", JSON.stringify(game));
}
private static initGameScene(scene: RuntimeScene): RuntimeGameScene {
return scene as RuntimeGameScene;
}
public static evalGameScripts(
world: World,
scene: RuntimeGameScene,
eventBus: GameEventBus,
scheduler: GameScheduler,
): void {
const handlerWrappers = new WeakMap<GeneratorEventHandler, GameEventHandler>();
const wait = (seconds: number): YieldCommand => ({ type: 'waitSeconds', seconds });
const waitFrames = (frames: number): YieldCommand => ({ type: 'waitFrames', frames });
const waitUntil = (condition: () => boolean): YieldCommand => ({ type: 'waitUntil', condition });
const internalBus: InternalGameEventBus = {
onGameEvent(event, genFn) {
const wrapper: GameEventHandler = (ctx) => scheduler.startCoroutine(genFn(ctx) as Generator<YieldCommand, void, void>);
handlerWrappers.set(genFn, wrapper);
eventBus.on(event, wrapper);
},
offGameEvent(event, genFn) {
const wrapper = handlerWrappers.get(genFn);
if (wrapper) {
eventBus.off(event, wrapper);
handlerWrappers.delete(genFn);
}
},
};
try {
Object.values(world.objectTypes)
.filter((ot) => ot.javascript)
.forEach((ot) => {
const gameScript = eval(`(function gameScript({onGameEvent, offGameEvent, wait, waitFrames, waitUntil}, {api, object, objectType}) {${ot.javascript}})`);
Object.values(scene.objects)
.filter((o) => o.typeId == ot.id)
.forEach((o) => {
const api = new ObjectApi(o, ot, world, scene);
gameScript({ ...internalBus, wait, waitFrames, waitUntil }, { api, object: o, objectType: ot });
});
});
}
catch (err) {
console.log('Error running game script:\n' + err);
}
}
}