import type { GameState } from '../core/GameState'; import type { Command, CommandExecutionResult } from '../commands/Command'; import { CommandExecutor } from '../commands/CommandExecutor'; import type { Rule, RuleContext, RuleResult, ValidationRule, EffectRule, TriggerRule, RuleLogEntry, } from './Rule'; import { isValidationRule, isEffectRule, isTriggerRule } from './Rule'; /** * 规则引擎配置 */ export interface RuleEngineOptions { /** 游戏类型 */ gameType?: string; /** 是否启用规则日志 */ enableLogging?: boolean; /** 是否自动执行触发规则 */ autoExecuteTriggers?: boolean; } /** * 规则引擎执行结果 */ export interface RuleEngineExecutionResult extends CommandExecutionResult { /** 执行的验证规则 */ validationRules: RuleLogEntry[]; /** 执行的效果规则 */ effectRules: RuleLogEntry[]; /** 触发的规则 */ triggerRules: RuleLogEntry[]; /** 触发的额外命令 */ triggeredCommands: Command[]; } /** * 规则引擎 * 负责在命令执行前后运行规则,并处理触发规则 */ export class RuleEngine { private gameState: GameState; private executor: CommandExecutor; private rules: Rule[] = []; private options: RuleEngineOptions; private logs: RuleLogEntry[] = []; private isExecuting: boolean = false; private triggerQueue: Command[] = []; constructor(gameState: GameState, options: RuleEngineOptions = {}) { this.gameState = gameState; this.executor = new CommandExecutor(gameState); this.options = { enableLogging: true, autoExecuteTriggers: true, ...options, }; } /** * 注册规则 */ registerRule(rule: Rule): void { // 如果指定了游戏类型,只有匹配时才注册 if (this.options.gameType && rule.gameType && rule.gameType !== this.options.gameType) { return; } this.rules.push(rule); // 按优先级排序 this.rules.sort((a, b) => a.priority - b.priority); } /** * 注册多个规则 */ registerRules(rules: Rule[]): void { for (const rule of rules) { this.registerRule(rule); } } /** * 移除规则 */ unregisterRule(ruleId: string): void { this.rules = this.rules.filter((r) => r.id !== ruleId); } /** * 清除所有规则 */ clearRules(): void { this.rules = []; } /** * 获取所有规则 */ getRules(): Rule[] { return [...this.rules]; } /** * 执行命令(带规则验证) */ async executeCommand(command: Command): Promise { if (this.isExecuting) { throw new Error('Rule engine is already executing a command'); } this.isExecuting = true; const validationLogs: RuleLogEntry[] = []; const effectLogs: RuleLogEntry[] = []; const triggerLogs: RuleLogEntry[] = []; const triggeredCommands: Command[] = []; try { // 创建规则上下文 const context: RuleContext = { gameState: this.gameState, command, metadata: {}, }; // 1. 执行验证规则 const validationRules = this.rules.filter(isValidationRule); for (const rule of validationRules) { if (!this.isRuleApplicable(rule, command)) { continue; } const result = await rule.validate(context); const logEntry = this.createLogEntry(rule, 'validation', result, command.id); validationLogs.push(logEntry); if (!result.success) { return this.createFailedResult(validationLogs, effectLogs, triggerLogs, triggeredCommands, result.error); } if (result.blockCommand) { return this.createFailedResult( validationLogs, effectLogs, triggerLogs, triggeredCommands, `Command blocked by rule: ${rule.name}` ); } // 应用状态更新 if (result.stateUpdates) { Object.assign(context.metadata, result.stateUpdates); } // 收集触发的命令 if (result.triggeredCommands) { triggeredCommands.push(...result.triggeredCommands); } } // 2. 执行命令 const executionResult = this.executor.execute(command); context.executionResult = executionResult; if (!executionResult.success) { return this.createFailedResult( validationLogs, effectLogs, triggerLogs, triggeredCommands, executionResult.error ); } // 3. 执行效果规则 const effectRules = this.rules.filter(isEffectRule); for (const rule of effectRules) { if (!this.isRuleApplicable(rule, command)) { continue; } const result = await rule.apply(context); const logEntry = this.createLogEntry(rule, 'effect', result, command.id); effectLogs.push(logEntry); if (!result.success) { // 效果规则失败不影响命令执行,只记录日志 continue; } // 应用状态更新 if (result.stateUpdates) { Object.assign(context.metadata, result.stateUpdates); } // 收集触发的命令 if (result.triggeredCommands) { triggeredCommands.push(...result.triggeredCommands); } } // 4. 执行触发规则 if (this.options.autoExecuteTriggers) { const triggerRules = this.rules.filter(isTriggerRule); for (const rule of triggerRules) { const shouldTrigger = await rule.condition(context); if (shouldTrigger) { const result = await rule.action(context); const logEntry = this.createLogEntry(rule, 'trigger', result, command.id); triggerLogs.push(logEntry); if (result.triggeredCommands) { triggeredCommands.push(...result.triggeredCommands); } } } } // 5. 执行触发的命令(在循环外执行,避免递归) } finally { this.isExecuting = false; } // 在主要执行完成后执行触发的命令 for (const triggeredCommand of triggeredCommands) { try { const triggerResult = await this.executeCommand(triggeredCommand); if (!triggerResult.success) { // 触发命令失败,记录但不影响主命令 this.logs.push({ timestamp: Date.now(), ruleId: 'triggered-command', ruleName: 'Triggered Command', ruleType: 'trigger', result: { success: false, error: `Triggered command ${triggeredCommand.id} failed: ${triggerResult.error}` }, commandId: triggeredCommand.id, }); } } catch (error) { // 忽略触发命令的异常 } } return { success: true, executedSteps: executionResult.executedSteps, totalSteps: executionResult.totalSteps, validationRules: validationLogs, effectRules: effectLogs, triggerRules: triggerLogs, triggeredCommands, }; } /** * 检查规则是否适用于当前命令 */ private isRuleApplicable( rule: ValidationRule | EffectRule, command: Command ): boolean { // 检查游戏类型 if (rule.gameType && rule.gameType !== this.options.gameType) { return false; } // 检查命令名称 if (rule.applicableCommands && !rule.applicableCommands.includes(command.name)) { return false; } return true; } /** * 创建日志条目 */ private createLogEntry( rule: Rule, ruleType: 'validation' | 'effect' | 'trigger', result: RuleResult, commandId: string ): RuleLogEntry { const entry: RuleLogEntry = { timestamp: Date.now(), ruleId: rule.id, ruleName: rule.name, ruleType, result, commandId, }; if (this.options.enableLogging) { this.logs.push(entry); } return entry; } /** * 创建失败结果 */ private createFailedResult( validationLogs: RuleLogEntry[], effectLogs: RuleLogEntry[], triggerLogs: RuleLogEntry[], triggeredCommands: Command[], error?: string ): RuleEngineExecutionResult { return { success: false, error, executedSteps: 0, totalSteps: 0, validationRules: validationLogs, effectRules: effectLogs, triggerRules: triggerLogs, triggeredCommands, }; } /** * 获取规则日志 */ getLogs(): RuleLogEntry[] { return [...this.logs]; } /** * 清除日志 */ clearLogs(): void { this.logs = []; } /** * 获取游戏状态 */ getGameState(): GameState { return this.gameState; } /** * 手动触发规则 */ async triggerRules(): Promise { const context: RuleContext = { gameState: this.gameState, command: { id: 'trigger-manual', name: 'manual-trigger', steps: [] }, metadata: {}, }; const logs: RuleLogEntry[] = []; const triggerRules = this.rules.filter(isTriggerRule); for (const rule of triggerRules) { const shouldTrigger = await rule.condition(context); if (shouldTrigger) { const result = await rule.action(context); const logEntry = this.createLogEntry(rule, 'trigger', result, 'manual'); logs.push(logEntry); } } return logs; } } /** * 创建规则引擎 */ export function createRuleEngine(gameState: GameState, options?: RuleEngineOptions): RuleEngine { return new RuleEngine(gameState, options); }