import { Compare, Event } from '@gedit/utils'; import { Disposable, DisposableCollection, Emitter } from '@gedit/utils'; import { PlaygroundContext } from './playground-context'; import type { Able, AbleRegistry } from './able'; import type { EntityManager } from './entity-manager'; import type { EntityAbles, AbleChangedEvent } from './entity-ables'; import type { EntityData, EntityDataProps, EntityDataRegistry } from './entity-data'; import type { AbleManager } from './able-manager'; import { nanoid } from 'nanoid'; /** * 注册类 */ export interface EntityRegistry { new( opts: EntityOpts ): E readonly type: E['type'], } /** * 持久化数据 */ export interface EntityJSON { type: string, id: string, ableList?: string[] dataList: object[] } /* eslint-disable @typescript-eslint/no-explicit-any */ const ObjectProto = (Object as any).__proto__; export interface EntityChildChangedEvent { type: 'add' | 'delete' | 'update' entity: T } export interface EntityDataChangedEvent { type: 'add' | 'delete' | 'update' data: EntityData entity: T } export interface EntityOpts { entityManager: EntityManager, id?: string, ables?: AbleRegistry[] // 添加的able datas?: { registry: EntityDataRegistry, data: EntityDataProps}[] savedInManager?: boolean // 是否存储到 manager上, 默认true } let _version = 0; export class Entity implements Disposable { static type = 'Entity'; private readonly onEntityChangedEmitter = new Emitter(); private readonly onDataChangedEmitter = new Emitter(); private readonly onChildrenChangedEmitter = new Emitter(); private readonly initializeDataKeys: string[] = []; // 初始化的 protected readonly dataManager: Map = new Map; // 存储的数据 readonly onBeforeAbleDispatchedEmitter = new Emitter(); readonly onAfterAbleDispatchedEmitter = new Emitter(); /** * 销毁事件管理 */ readonly toDispose = new DisposableCollection(); /** * able管理 */ readonly ables: EntityAbles; /** * 修改会触发 */ readonly onEntityChanged = this.onEntityChangedEmitter.event; /** * able触发之前 */ readonly onBeforeAbleDispatched = this.onBeforeAbleDispatchedEmitter.event; /** * able触发之后 */ readonly onAfterAbleDispatched = this.onAfterAbleDispatchedEmitter.event; /** * 子节点变化 */ readonly onChildrenChanged = this.onChildrenChangedEmitter.event; /** * 数据更改事件 */ readonly onDataChanged = this.onDataChangedEmitter.event; /** * able数据更改 */ readonly onAbleChanged: Event; /** * 由上下文注入的数据 */ context: PlaygroundContext; /** * 初始化的data */ getDefaultAbleRegistries(): AbleRegistry[] { return []; } /** * 初始化的able */ getDefaultDataRegistries(): EntityDataRegistry[] { return []; } private _pauseChangedTimes = 0; protected isInitialized: boolean = true; private _id: string; private _version: number = _version++; // 每次创建都有一个新version,避免id相同的entity频繁创建销毁导致碰撞 private _parent?: Entity; // 父节点 private _children?: Entity[]; // 子节点 private _savedInManager: boolean = true; readonly ableManager: AbleManager; /** * 暂停更新开关 * @protected */ protected get pauseChanged(): boolean { return this._pauseChangedTimes > 0; } protected set pauseChanged(pauseChanged) { this._pauseChangedTimes = pauseChanged ? (this._pauseChangedTimes + 1) : (this._pauseChangedTimes - 1); if (this._pauseChangedTimes < 0) this._pauseChangedTimes = 0; } /** * 实体类型 */ get type(): string { if (!(this.constructor as any).type) { throw new Error('Entity Registry need a type: ' + this.constructor.name); } return (this.constructor as any).type; } /** * 全局的entity管理器 */ readonly entityManager: EntityManager; constructor( opts: OPTS, ) { this.entityManager = opts.entityManager; this._id = opts.id || nanoid(); this._savedInManager = opts.savedInManager === undefined ? true : opts.savedInManager; this.ableManager = this.entityManager.ableManager; this.context = this.entityManager.context; this.isInitialized = true; this.ables = this.entityManager.ableManager.createAbleMap(this); this.ables.onAbleChanged(event => { // 只需要监听删除,add和update都由entityData去监听 if (event.type === 'delete') { this.fireChanged(); } }); this.toDispose.push(this.onEntityChangedEmitter); this.toDispose.push(this.onBeforeAbleDispatchedEmitter); this.toDispose.push(this.onAfterAbleDispatchedEmitter); this.toDispose.push(this.onDataChangedEmitter); this.toDispose.push(this.ables); this.onAbleChanged = this.ables.onAbleChanged; this.register(); if (opts.ables) { opts.ables.forEach(able => this.ables.add(able)); } if (opts.datas) { opts.datas.forEach(data => this.addData(data.registry, data.data)); } this.isInitialized = false; } /** * 实体的版本 */ get version(): number { return this._version; } /** * 存储数据, 用于持久化存储 */ toJSON(): EntityJSON | undefined { const dataList: object[] = []; for (const data of this.dataManager.values()) { if (data.toJSON) { dataList.push(data.toJSON()); } } return { type: this.type, id: this.id, ableList: this.ables.toJSON(), dataList, }; } /** * 还原数据 * @param data */ fromJSON(data?: EntityJSON): void { if (!data || !data.id || !data.type) return; this.pauseChanged = true; this.reset(); if (data.dataList) { data.dataList.forEach((d: { type: string, data: object }) => { const registry = this.entityManager.getDataRegistryByType(d.type); if (registry) { const dataEnity = this.addData(registry); dataEnity.update(d.data); } }); } this.pauseChanged = false; this.fireChanged(); } /** * 实体id */ get id(): string { return this._id; } /** * 销毁实体 */ dispose(): void { this.toDispose.dispose(); } get disposed(): boolean { return this.toDispose.disposed; } /** * 重制为初始化状态 */ reset(): void { this.pauseChanged = true; for (const data of this.dataManager.values()) { if (!this.initializeDataKeys.includes(data.type)) { data.dispose(); } } this.ables.reset(); this.register(); this.pauseChanged = false; this.fireChanged(); } /** * 销毁事件 */ get onDispose(): Event { return this.toDispose.onDispose; } /** * 触发实体更新 * @protected */ protected fireChanged(): void { if (this.pauseChanged || this.isInitialized || this.disposed) return; this._version ++; if (this._version >= Number.MAX_VALUE) { this._version = 0; } this.onEntityChangedEmitter.fire(this); } /** * 添加数据 */ addData(Registry: EntityDataRegistry, defaultProps?: EntityDataProps): D { this.entityManager.registerEntityData(Registry); let entityData = this.dataManager.get(Registry.type) as D; if (entityData) { if (defaultProps) this.updateData(Registry, defaultProps); return entityData; } entityData = new Registry(this) as D; if (this.isInitialized) this.initializeDataKeys.push(entityData.type); this.dataManager.set(Registry.type, entityData); this.toDispose.push(entityData); entityData.onDataChanged(() => { const event: EntityDataChangedEvent = { type: 'update', data: entityData, entity: this }; this.onDataChangedEmitter.fire(event); this.fireChanged(); }); entityData.toDispose.push(Disposable.create(() => { this.dataManager.delete(Registry.type); const event: EntityDataChangedEvent = { type: 'delete', data: entityData, entity: this }; this.onDataChangedEmitter.fire(event); this.fireChanged(); })); this.updateData(Registry, defaultProps || entityData.getDefaultData()); return entityData; } /** * 是否存到全局manager,默认true */ get savedInManager(): boolean { return this._savedInManager; } /** * 更新实体的数据 */ updateData(Registry: EntityDataRegistry, props: EntityDataProps): void { const entityData = this.dataManager.get(Registry.type); if (entityData) { entityData.update(props); } } /** * 获取data数据 * @param Registry */ getData(Registry: EntityDataRegistry): D | undefined { return this.dataManager.get(Registry.type) as D; } /** * 是否有指定数据 * @param Registry */ hasData(Registry: EntityDataRegistry): boolean { return this.dataManager.has(Registry.type); } /** * 删除数据, 初始化状态注入的数据无法被删除 */ removeData(Registry: EntityDataRegistry): void { // 初始化的数据无法被删除 if (this.initializeDataKeys.includes(Registry.type)) return; const entityData = this.dataManager.get(Registry.type); if (entityData) { entityData.dispose(); } } /** * 添加able * @param ables */ addAbles(...ables: AbleRegistry[]): void { ables.forEach(able => this.ables.add(able)); } /** * 删除able * @param ables */ removeAbles(...ables: AbleRegistry[]): void { ables.forEach(able => this.ables.remove(able)); } /** * 是否有able * @param able */ hasAble(able: AbleRegistry): boolean { return this.ables.has(able); } hasAbles(...ables: AbleRegistry[]): boolean { for (const able of ables) { if (!this.ables.has(able)) return false; } return true; } /** * 添加子节点 * @param Registry * @param opts * @param savedInManager - 是否存储到manager,默认false */ createChild(Registry: EntityRegistry, opts: Omit): E { const child = this.entityManager.createEntity(Registry, { savedInManager: false, ...opts }); child._parent = this; if (!this._children) this._children = []; this._children.push(child); // 父节点销毁自动删除子节点 this.toDispose.push(child); child.onEntityChanged(() => { const event: EntityChildChangedEvent = { type: 'update', entity: child }; this.onChildrenChangedEmitter.fire(event); this.fireChanged(); }); child.toDispose.push(Disposable.create(() => { const children = this._children || []; const index = children.indexOf(child); if (index !== -1) { children.splice(index, 1); const event: EntityChildChangedEvent = { type: 'delete', entity: child }; this.onChildrenChangedEmitter.fire(event); this.fireChanged(); } })); const addEvent: EntityChildChangedEvent = { type: 'add', entity: child }; this.onChildrenChangedEmitter.fire(addEvent); this.fireChanged(); return child; } /** * 获取父亲节点 */ getParent(): E | undefined { return this._parent as E; } get hasChild(): boolean { return !!this._children && this._children.length > 0; } /** * 获取子节点 * @param Registry */ getChildren(Registry?: EntityRegistry): E[] { const children = this._children || []; if (!Registry) return children as E[]; return children.filter(c => c.type === Registry.type) as E[]; } /** * 清空所有子节点 */ clearChildren(): void { if (this._children) { this.pauseChanged = true; for (const c of this._children.values()) { c.dispose(); } this.pauseChanged = false; this.fireChanged(); } this._children = undefined; } /** * 根据id获取子节点 * @param id */ getChildById(id: string): E | undefined { const children = this._children || []; return children.find(c => c.id === id) as E; } protected register(): void { // 注册默认able this.getDefaultAbleRegistries().forEach(Registry => this.ables.add(Registry)); // 注册默认数据 this.getDefaultDataRegistries().forEach(Registry => this.addData(Registry)); } __opts_type__: OPTS; } export namespace Entity { export function getType(registry: EntityRegistry): string { return registry.type; } /** * 默认数据比较,采用浅比较 */ // eslint-disable-next-line @typescript-eslint/no-explicit-any export function checkDataChanged(oldProps: any, newProps: any): boolean { return Compare.isChanged(oldProps, newProps); } // eslint-disable-next-line @typescript-eslint/no-explicit-any export function isRegistryOf(target: any, Registry: any): boolean { if (target === Registry) return true; let proto = target.__proto__; while (proto && proto !== ObjectProto) { if (proto.prototype === Registry.prototype) return true; proto = proto.__proto__; } return false; } }