UNPKG

yoni-mcscripts-lib

Version:

为 Minecraft Script API 中的部分接口创建了 wrapper,并提供简单的事件管理器和任务管理器,另附有一些便于代码编写的一些小工具。

245 lines (244 loc) 7.91 kB
import { manager } from "./EventManager.js"; import { defaultOptionResolver } from "./lib/defaultOptionResolver.js"; import { EventPriorityIds } from "./EventPriority.js"; import { getExtendedClassesInList } from "./lib/getExtendedClassesInList.js"; export class EventRegistry { #throwIfRegistered() { if (this.#hasRegistered) throw new TypeError("Deny changing the event info as it was registered"); } throwIfNotRegistered() { if (!this.#hasRegistered) throw new TypeError("The event info is not registered"); } #displayName; /** * 该事件的便于区分的名字。 */ get eventName() { return this.#displayName ?? this.eventClass.name; } /** * 关联到的事件类。 */ eventClass; /** * 指定不扩展此事件的范围。 */ get noExtends() { return this.#noExtends; } set noExtends(v) { this.#throwIfRegistered(); this.#noExtends = v; } #noExtends = true; /** * 指定此事件使用额外参数在handler前过滤事件。 */ get extraOption() { return this.#extraOption; } set extraOption(v) { this.#throwIfRegistered(); this.#extraOption = v; } #extraOption = false; /** * 此事件在handler前过滤事件所使用的处理器。 */ get extraOptionResolver() { return this.#extraOptionResolver; } set extraOptionResolver(v) { this.#throwIfRegistered(); this.#extraOptionResolver = v; } #extraOptionResolver; /** * 此事件的兼容监听器。 */ get listeningAdapter() { return this.#listeningAdapter; } set listeningAdapter(v) { this.#throwIfRegistered(); this.#listeningAdapter = v; } #listeningAdapter; /** * 兼容监听器是否已经启用。 */ #adapterEnabled = false; /** * 处理兼容监听器。 */ #adapter(action) { if (!this.listeningAdapter) return false; if (action === "enable" && !this.#adapterEnabled) { this.listeningAdapter.listen(receiveEvent); this.#adapterEnabled = true; } else if (action === "disable" && this.#adapterEnabled) { if (this.listeningAdapter.remove()) { this.#adapterEnabled = false; } } else { return false; } const eventRegistry = this; function receiveEvent(event) { manager.callEvent(eventRegistry, event); } return true; } /** * will initialize on {@link EventRegistry##sortHandlers} */ #handlers; get #sorted() { return this.#handlers != undefined; } set #sorted(hasSorted) { if (!hasSorted) this.#handlers = undefined; } #sortHandlers() { if (this.#sorted) return; const sortedHandlersList = EventPriorityIds .sort((va, vb) => va - vb) .map(id => this.handlerslots.get(id)) .flat(); this.#handlers = sortedHandlersList; this.#sorted = true; } get handlers() { this.#sortHandlers(); return this.#handlers; } handlerslots = new Map( // 此处为每个事件优先级初始化一个用于存储事件处理器的列表 EventPriorityIds.map(prio => [ prio, [] ])); get hasRegistered() { return this.#hasRegistered; } #hasRegistered = false; constructor(eventClass) { // 多一次无用操作起码比类型报错好 this.eventClass = eventClass; Object.defineProperty(this, "eventClass", { value: eventClass }); } addHandler(handler, priority) { if (this.handlerslots.get(priority).includes(handler)) { throw new Error("registered"); } this.#sorted = false; this.handlerslots.get(priority)?.push(handler); //实际上不会也不应该出现空槽位结果,除非传入的priority不正确 this.#adapter("enable"); } removeHandler(handler, priority) { const handlers = this.handlerslots.get(priority); const location = handlers.indexOf(handler); if (location === -1) { return false; } this.#sorted = false; handlers.splice(location, 1); return true; } /** * 注销事件信息。 */ static unregister(eventClass) { if (eventClass instanceof EventRegistry) eventClass = eventClass.eventClass; if (!EventRegistry.#registries.has(eventClass)) { return false; } const registry = EventRegistry.#registries.get(eventClass); registry.handlerslots.clear(); //看上去这会破坏什么东西 registry.#sorted = false; registry.#adapter("disable"); registry.#hasRegistered = false; EventRegistry.#extendsClassesCache = undefined; EventRegistry.#registries.delete(eventClass); return true; } /** * 注册事件信息。 */ static register(eventClass, option) { let registry; if (eventClass instanceof EventRegistry) { registry = eventClass; eventClass = registry.eventClass; } else { registry = new EventRegistry(eventClass); } registry.#throwIfRegistered(); if (option) { EventRegistry.#setRegistryOption(registry, option); } if (registry.#adapter != null && !registry.#adapterEnabled && registry.handlers.length !== 0) { registry.#adapter("enable"); } registry.#hasRegistered = true; EventRegistry.#extendsClassesCache = undefined; EventRegistry.#registries.set(eventClass, registry /** 暂时不知道怎么解决 */); return registry; } static #setRegistryOption(eventRegistry, option) { eventRegistry.#throwIfRegistered(); eventRegistry.noExtends = option.noExtends ?? eventRegistry.noExtends; eventRegistry.extraOption = option.extraOption ?? eventRegistry.extraOption; eventRegistry.extraOptionResolver = option.extraOptionResolver ?? defaultOptionResolver; eventRegistry.listeningAdapter = option.listeningAdapter ?? eventRegistry.listeningAdapter; eventRegistry.#displayName = option.displayName ?? undefined; } /** * 获取一个事件所对应的事件信息对象。 */ static getRegistry(eventClass) { let registry = EventRegistry.#registries.get(eventClass); if (registry != null) { return registry; } const newRegistry = new EventRegistry(eventClass); EventRegistry.#registries.set(eventClass, newRegistry /* 不会写这个类型 */); return newRegistry; } static getExtends(registry) { const extendsClasses = EventRegistry.#extendsClasses; const matchedClasses = []; for (const clazz of extendsClasses) { if (getExtendedClassesInList(clazz, extendsClasses)) { matchedClasses.push(clazz); } } return matchedClasses.map(clazz => EventRegistry.getRegistry(clazz)); } static #registries = new Map(); static #extendsClassesCache; static get #extendsClasses() { if (EventRegistry.#extendsClassesCache != null) { return EventRegistry.#extendsClassesCache; } const extendsClasses = []; for (const er of EventRegistry.#registries.values()) { if (!er.noExtends) { extendsClasses.push(er.eventClass); } } EventRegistry.#extendsClassesCache = extendsClasses; return extendsClasses; } }