yoni-mcscripts-lib
Version:
为 Minecraft Script API 中的部分接口创建了 wrapper,并提供简单的事件管理器和任务管理器,另附有一些便于代码编写的一些小工具。
245 lines (244 loc) • 7.91 kB
JavaScript
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;
}
}