커맨드 엔진 실행에서 alternative 추가

This commit is contained in:
2026-01-08 14:39:45 +00:00
parent bc9c0fd717
commit e91fe06762
4 changed files with 196 additions and 2 deletions
+12 -1
View File
@@ -97,6 +97,10 @@ export type GeneralActionEffect<TriggerState extends GeneralTriggerState = Gener
export interface GeneralActionOutcome<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
effects: GeneralActionEffect<TriggerState>[];
alternative?: {
commandKey: string;
args: unknown;
};
}
export interface GeneralActionResolver<TriggerState extends GeneralTriggerState = GeneralTriggerState, Args = unknown> {
@@ -127,6 +131,10 @@ export interface GeneralActionResolution {
cityId?: CityId;
nationId?: NationId;
};
alternative?: {
commandKey: string;
args: unknown;
};
}
export const createGeneralPatchEffect = <TriggerState extends GeneralTriggerState = GeneralTriggerState>(
@@ -205,6 +213,7 @@ export const resolveGeneralAction = <TriggerState extends GeneralTriggerState =
};
const pendingEffects: GeneralActionEffect[] = [];
let outcome: GeneralActionOutcome<TriggerState> | undefined;
const [nextWorld, worldPatches] = produceWithPatches(
{
general: context.general,
@@ -252,9 +261,10 @@ export const resolveGeneralAction = <TriggerState extends GeneralTriggerState =
}
};
const outcome = resolver.resolve(
outcome = resolver.resolve(
{
...context,
// ...
general: castDraft(draft.general),
city: castDraft(draft.city),
nation: castDraft(draft.nation),
@@ -345,6 +355,7 @@ export const resolveGeneralAction = <TriggerState extends GeneralTriggerState =
nextTurnAt,
logs,
effects: pendingEffects,
...(outcome?.alternative ? { alternative: outcome.alternative } : {}),
};
if (nextWorld.city) {
resolution.city = nextWorld.city as City;
@@ -0,0 +1,53 @@
import type {
GeneralActionResolution,
GeneralActionResolveInputContext,
GeneralActionResolver,
TurnScheduleContext,
} from '../engine.js';
import { resolveGeneralAction } from '../engine.js';
import type { GeneralTriggerState } from '@sammo-ts/logic/domain/entities.js';
export interface CommandLoader<TriggerState extends GeneralTriggerState = GeneralTriggerState> {
load(key: string): Promise<GeneralActionResolver<TriggerState> | null>;
}
import type { LogEntryDraft } from '@sammo-ts/logic/logging/types.js';
export const processGeneralActionWithFallback = async <TriggerState extends GeneralTriggerState = GeneralTriggerState>(
initialResolver: GeneralActionResolver<TriggerState>,
context: GeneralActionResolveInputContext<TriggerState>,
scheduleContext: TurnScheduleContext,
initialArgs: unknown,
commandLoader: CommandLoader<TriggerState>
): Promise<GeneralActionResolution> => {
let currentResolver = initialResolver;
let currentArgs = initialArgs;
let loopLimit = 5; // Prevent infinite loops
const accumulatedLogs: LogEntryDraft[] = [];
while (loopLimit > 0) {
loopLimit--;
const resolution = resolveGeneralAction(currentResolver, context, scheduleContext, currentArgs);
if (resolution.alternative) {
accumulatedLogs.push(...resolution.logs);
const { commandKey, args } = resolution.alternative;
const nextResolver = await commandLoader.load(commandKey);
if (nextResolver) {
currentResolver = nextResolver;
currentArgs = args;
continue;
}
}
// Prepend accumulated logs to the final resolution
if (accumulatedLogs.length > 0) {
resolution.logs.unshift(...accumulatedLogs);
}
return resolution;
}
throw new Error('Command fallback loop limit exceeded');
};
@@ -336,7 +336,13 @@ export class ActionDefinition<
`<G><b>${targetName}</b></>${josaRoTarget} 가는 도중 <G><b>${destCity.name}</b></>을 거치기로 합니다.`
);
}
return { effects: [] };
return {
effects: [],
alternative: {
commandKey: 'che_이동',
args: { destCityId: destCity.id },
},
};
}
if (finalTargetCity.id !== destCity.id) {