boardgame-phaser/packages/framework/src/input/PromptHandler.ts

103 lines
2.6 KiB
TypeScript
Raw Normal View History

2026-04-04 00:48:44 +08:00
import type { IGameContext, PromptEvent } from 'boardgame-core';
export interface PromptHandlerOptions {
commands: IGameContext<any>['commands'];
onPrompt: (prompt: PromptEvent) => void;
onCancel: (reason?: string) => void;
}
export class PromptHandler {
private commands: IGameContext<any>['commands'];
private onPrompt: (prompt: PromptEvent) => void;
private onCancel: (reason?: string) => void;
private activePrompt: PromptEvent | null = null;
private isListening = false;
private pendingInput: string | null = null;
constructor(options: PromptHandlerOptions) {
this.commands = options.commands;
this.onPrompt = options.onPrompt;
this.onCancel = options.onCancel;
}
start(): void {
this.isListening = true;
this.listenForPrompt();
}
private listenForPrompt(): void {
if (!this.isListening) return;
this.commands.promptQueue.pop()
.then((promptEvent) => {
this.activePrompt = promptEvent;
// 如果有等待的输入,自动提交
if (this.pendingInput) {
const input = this.pendingInput;
this.pendingInput = null;
const error = this.activePrompt.tryCommit(input);
if (error === null) {
this.activePrompt = null;
this.listenForPrompt();
} else {
// 提交失败,把 prompt 交给 UI 显示错误
this.onPrompt(promptEvent);
}
return;
}
this.onPrompt(promptEvent);
})
.catch((reason) => {
this.activePrompt = null;
this.onCancel(reason?.message || 'Cancelled');
});
}
/**
* Submit an input string to the current prompt.
* @returns null on success (input accepted), error string on validation failure
*/
submit(input: string): string | null {
if (!this.activePrompt) {
// 没有活跃 prompt保存为待处理输入
this.pendingInput = input;
return null;
}
const error = this.activePrompt.tryCommit(input);
if (error === null) {
this.activePrompt = null;
this.listenForPrompt();
}
return error;
}
cancel(reason?: string): void {
if (this.activePrompt) {
this.activePrompt.cancel(reason);
this.activePrompt = null;
}
this.onCancel(reason);
}
stop(): void {
this.isListening = false;
if (this.activePrompt) {
this.activePrompt.cancel('Handler stopped');
this.activePrompt = null;
}
}
destroy(): void {
this.stop();
}
}
export function createPromptHandler(
options: PromptHandlerOptions,
): PromptHandler {
return new PromptHandler(options);
}