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

103 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}