boardgame-core/src/core/rule.ts

81 lines
1.9 KiB
TypeScript
Raw Normal View History

2026-04-01 21:44:20 +08:00
import {Context} from "./context";
2026-04-01 13:36:16 +08:00
import {Command} from "../utils/command";
import {effect} from "@preact/signals-core";
export type RuleContext<T> = Context & {
actions: Command[];
handledActions: number;
invocations: RuleContext<unknown>[];
resolution?: T;
}
2026-04-01 17:34:21 +08:00
/**
*
* @param pushContext -
* @param type -
* @param rule -
* @returns
*/
export function invokeRuleContext<T>(
2026-04-01 21:44:20 +08:00
pushContext: (context: Context) => void,
type: string,
2026-04-01 17:34:21 +08:00
rule: Generator<string, T, Command>
): RuleContext<T> {
2026-04-01 13:36:16 +08:00
const ctx: RuleContext<T> = {
type,
actions: [],
handledActions: 0,
invocations: [],
resolution: undefined,
2026-04-01 17:34:21 +08:00
};
2026-04-01 21:44:20 +08:00
let disposed = false;
2026-04-01 17:34:21 +08:00
const executeRule = () => {
2026-04-01 21:44:20 +08:00
if (disposed || ctx.resolution !== undefined) return;
2026-04-01 17:34:21 +08:00
try {
const result = rule.next();
2026-04-01 21:44:20 +08:00
2026-04-01 17:34:21 +08:00
if (result.done) {
ctx.resolution = result.value;
return;
}
const actionType = result.value;
2026-04-01 21:44:20 +08:00
if (actionType) {
// 暂停于 yield 点,等待外部处理动作
// 当外部更新 actions 后effect 会重新触发
2026-04-01 17:34:21 +08:00
}
} catch (error) {
throw error;
}
};
2026-04-01 13:36:16 +08:00
const dispose = effect(() => {
2026-04-01 17:34:21 +08:00
if (ctx.resolution !== undefined) {
2026-04-01 13:36:16 +08:00
dispose();
2026-04-01 21:44:20 +08:00
disposed = true;
2026-04-01 13:36:16 +08:00
return;
}
2026-04-01 17:34:21 +08:00
executeRule();
2026-04-01 13:36:16 +08:00
});
2026-04-01 17:34:21 +08:00
pushContext(ctx);
return ctx;
2026-04-01 13:36:16 +08:00
}
2026-04-01 17:34:21 +08:00
/**
*
* @param type -
* @param fn -
*/
export function createRule<T>(
type: string,
fn: (ctx: RuleContext<T>) => Generator<string, T, Command>
2026-04-01 21:44:20 +08:00
): (ctx: RuleContext<T>) => Generator<string, T, Command> {
return fn;
2026-04-01 17:34:21 +08:00
}