/* eslint-disable @typescript-eslint/no-explicit-any */ import { injectable } from 'inversify'; import type { Able, AbleRegistry } from './able'; import type { Entity } from './entity'; import { AbleChangedEvent, EntityAbles } from './entity-ables'; import { Disposable, DisposableCollection, Emitter, iterToArray } from '@gedit/utils'; import { getPayloadMetadata } from './playground-decorator-helper'; import { PlaygroundSchedule } from './playground-schedule'; export interface AbleDispatchEvent

{ payloadKey: string | Symbol, payload: P, entityChangedKeys: string[] } @injectable() export class AbleManager implements Disposable { readonly toDispose = new DisposableCollection(); private schedule = new PlaygroundSchedule(); protected onAbleChangedEmitter = new Emitter(); protected onAbleDispatchEmitter = new Emitter(); /** * Able的类缓存,便于在fromJSON时候查找对应的类 */ protected registryMap: Map = new Map; /** * ableType -> Set */ protected entityDataMapByAble: Map = new Map; /** * payload -> Set */ protected payloadAbleMap: Map = new Map; /** * able对应的类型被更改 */ readonly onAbleChanged = this.onAbleChangedEmitter.event; readonly onAbleDispatch = this.onAbleDispatchEmitter.event; constructor() { this.toDispose.pushAll([ this.schedule, this.onAbleChangedEmitter, this.onAbleDispatchEmitter ]); } createAble(Registry: AbleRegistry, entity: Entity): Able { this.registerAble(Registry); return new Registry(entity); } /** * 存储Able注册器 * @param Registry */ registerAble(Registry: AbleRegistry): void { // if (!Registry.type) throw new Error(`Able Registry ${Registry.name} need a type`) const oldRegistry = this.registryMap.get(Registry.type); if (oldRegistry) { if (oldRegistry !== Registry) { throw new Error(`Able registry ${Registry.name} need a new type`); } return; } const payload = getPayloadMetadata(Registry); if (payload) { if (!this.payloadAbleMap.has(payload)) { this.payloadAbleMap.set(payload, []); } const arr = this.payloadAbleMap.get(payload)!; arr.push(Registry); } this.registryMap.set(Registry.type, Registry); } getRegistryByType(type: string): AbleRegistry | undefined { return this.registryMap.get(type); } /** * 触发able,如果命中entity并使得entity数据变化,则返回true * @param payloadKey * @param payload * @return 修改的 entity id */ dispatch

(payloadKey: string | Symbol, payload: P): string[] { const hitAbles = this.payloadAbleMap.get(payloadKey); if (!hitAbles) return []; const emptySet: Entity[] = []; const dispatchedEntities: Entity[] = []; const entityChangedKeys: string[] = []; hitAbles .filter(able => { const entities = this.entityDataMapByAble.get(able.type) || emptySet; if ((able as any).globalBefore) { payload = (able as any).globalBefore(iterToArray(entities.values()), payload); return payload !== undefined; } return true; }) .forEach(able => { const entities = this.entityDataMapByAble.get(able.type) || emptySet; for (const entity of entities.values()) { // 可能两个able同时注册到同一个实体 if (!dispatchedEntities.includes(entity)) { const preVersion = entity.version; entity.ables.dispatchAbles

(hitAbles, payload); dispatchedEntities.push(entity); if (entity.version !== preVersion) { entityChangedKeys.push(entity.id); } } } if ((able as any).globalAfter) { return (able as any).globalAfter(iterToArray(entities.values()), payload); } }); this.onAbleDispatchEmitter.fire({ payloadKey, payload, entityChangedKeys }); return entityChangedKeys; } createAbleMap(entity: Entity): EntityAbles { const ables = new EntityAbles(entity, this); ables.onAbleChanged((event: AbleChangedEvent) => { const ableTypes = event.ableTypes; ableTypes.forEach(ableType => { // 子节点不存储到全局 if (event.entity.savedInManager) { let entities = this.entityDataMapByAble.get(ableType); switch (event.type) { case 'delete': if (!entities) return; const idex = entities.indexOf(event.entity); if (idex !== -1) entities.splice(idex, 1); break; case 'add': if (!entities) { entities = []; this.entityDataMapByAble.set(ableType, entities); } entities.push(event.entity); break; } } this.fireAbleChanged(ableType); }); }); return ables; } /** * 通过able查找entity * @param registry */ getEntitiesByAble(registry: AbleRegistry): T[] { return (this.entityDataMapByAble.get(registry.type) || []) as T[]; } getEntitiesByAbles(...registries: AbleRegistry[]): T[] { if (registries.length === 0) return[]; const entities = (this.entityDataMapByAble.get(registries[0].type) || []) as T[]; return entities.filter(e => e.hasAbles(...registries.slice(1))); } /** * 获取单个实体 * @param registry */ getEntityByAble(registry: AbleRegistry): T | undefined { return (this.entityDataMapByAble.get(registry.type) || [])[0] as T; } protected fireAbleChanged(type: string): void { this.schedule.push(type, () => { this.onAbleChangedEmitter.fire(type); }); } dispose(): void { this.toDispose.dispose(); } }