boardgame-core/src/core/context.ts

95 lines
2.8 KiB
TypeScript
Raw Blame History

import {createModel, Signal, signal} from '@preact/signals-core';
import {createEntityCollection} from "../utils/entity";
import {Part} from "./part";
import {Region} from "./region";
import {RuleDef, RuleRegistry, RuleContext, RuleEngineHost, dispatchCommand as dispatchRuleCommand} from "./rule";
export type Context = {
type: string;
}
export const GameContext = createModel((root: Context) => {
const parts = createEntityCollection<Part>();
const regions = createEntityCollection<Region>();
const rules = signal<RuleRegistry>(new Map());
const ruleContexts = signal<RuleContext<unknown>[]>([]);
const contexts = signal<Signal<Context>[]>([]);
contexts.value = [signal(root)];
function pushContext(context: Context) {
const ctxSignal = signal(context);
contexts.value = [...contexts.value, ctxSignal];
return context;
}
function popContext() {
if (contexts.value.length > 1) {
contexts.value = contexts.value.slice(0, -1);
}
}
function latestContext<T extends Context>(type: T['type']): Signal<T> | undefined {
for(let i = contexts.value.length - 1; i >= 0; i--){
if(contexts.value[i].value.type === type){
return contexts.value[i] as Signal<T>;
}
}
return undefined;
}
function registerRule(name: string, rule: RuleDef<unknown, RuleEngineHost>) {
const newRules = new Map(rules.value);
newRules.set(name, rule);
rules.value = newRules;
}
function unregisterRule(name: string) {
const newRules = new Map(rules.value);
newRules.delete(name);
rules.value = newRules;
}
function addRuleContext(ctx: RuleContext<unknown>) {
ruleContexts.value = [...ruleContexts.value, ctx];
}
function removeRuleContext(ctx: RuleContext<unknown>) {
ruleContexts.value = ruleContexts.value.filter(c => c !== ctx);
}
function dispatchCommand(this: GameContextInstance, input: string) {
return dispatchRuleCommand({
rules: rules.value,
ruleContexts: ruleContexts.value,
addRuleContext,
removeRuleContext,
pushContext,
popContext,
latestContext,
parts,
regions,
} as any, input);
}
return {
parts,
regions,
rules,
ruleContexts,
contexts,
pushContext,
popContext,
latestContext,
registerRule,
unregisterRule,
dispatchCommand,
}
})
/** 创建游戏上下文实<E69687>?*/
export function createGameContext(root: Context = { type: 'game' }) {
return new GameContext(root);
}
export type GameContextInstance = ReturnType<typeof createGameContext>;