yoni-mcscripts-lib
Version:
为 Minecraft Script API 中的部分接口创建了 wrapper,并提供简单的事件管理器和任务管理器,另附有一些便于代码编写的一些小工具。
85 lines (84 loc) • 3.63 kB
JavaScript
import { MinecraftSystem as system } from "../basis.js";
import { CommandList } from "./CommandList.js";
import { config } from "../config.js";
export class AsyncCommandExecutor {
static #logger;
static log(...data) {
if (AsyncCommandExecutor.#logger)
AsyncCommandExecutor.#logger.trace(...data);
else
system.run(async function initLogger() {
const { Logger } = await import("../util/Logger");
AsyncCommandExecutor.#logger = new Logger("AsyncCommandExecutor");
AsyncCommandExecutor.log(...data);
});
}
executingCommand = null;
commandList = new CommandList();
start() {
if (this.#scheduleId !== null)
throw new Error("executor already started");
this.#scheduleId = system.runInterval(this.#run.bind(this));
}
constructor(autoStart) {
if (arguments.length > 0)
if (autoStart)
this.start();
}
#scheduleId = null;
stop() {
if (this.#scheduleId !== null) {
system.clearRun(this.#scheduleId);
this.#scheduleId = null;
}
}
add(priv, command) {
this.commandList.add(priv, command);
}
#run() {
if (!config.getBoolean("command.asyncExecutor.re-execute-when-no-promise", false))
this.executingCommand = null;
let executeQueueCount = 0;
while (this.commandList.hasNext()
|| this.executingCommand !== null) {
let commandQueue = this.executingCommand ?? this.commandList.next();
executeQueueCount += 1;
//如果executingCommand不为null,说明上次执行的时候可能出现了什么错误
//保存以便于后边处理的时候给出更多结果
let lastFailedCommand;
if (this.executingCommand !== null)
lastFailedCommand = commandQueue;
else
lastFailedCommand = null;
//开始执行,保存正在执行的命令
this.executingCommand = commandQueue;
let commandPromise;
const { sender, command } = commandQueue;
try {
commandPromise = sender.runCommandAsync(command);
}
catch (err) {
if (commandQueue === lastFailedCommand) {
//调用方法失败,并且上次也是这一条命令失败
lastFailedCommand.reject(err);
AsyncCommandExecutor.log("队列中的命令执行失败 /{}\n", lastFailedCommand.command, err);
continue; //这种情况多半是因为 sender 无法使用,所以可以直接跳过这一条
}
else {
//不确定失败原因,可能是调用失败或者队列已满
AsyncCommandExecutor.log("队列已满或出现其他错误,"
+ "如果下次该命令仍然推入错误,"
+ "将会不执行此命令,"
+ "已成功推入 {} 条命令,"
+ "还有 {} 条正在等待\n", executeQueueCount, 1 + this.commandList.count(), //lastFailedCommand 也还没执行
err);
break; //这种情况可能是由于队列满了,所以应该结束本次命令循环
}
}
//执行完成
commandQueue.resolveResult(commandPromise);
executeQueueCount += 1;
this.executingCommand = null;
}
}
}