import { _decorator, Component, find, game } from "cc"; import { Constructor } from "../core"; import { Data } from "./Data"; const { ccclass, property, executionOrder } = _decorator; /** * 数据系统组件,常驻节点,可创建数据、获取数据、观察数据变化 * @description 创建数据:g.userData = DataSystem.createData(UserData);update方法里:DataSystem.watch(g.userData,"money") && this.moneyLabel.string = g.userData.money; * @description Data的数组属性也可以watch到变化:g.userData.bagList.push("数据");DataSystem.watch(g.userData,"bagList") * @author 袁浩 */ @ccclass('DataSystem') @executionOrder(-1) export class DataSystem extends Component { private dataMap: Map> = new Map>(); private watchData: Map> = new Map>(); private watchedList: Array<{ data: Data, key: PropertyKey }> = []; private static thisObject: DataSystem; start() { game.addPersistRootNode(this.node);//常驻节点 DataSystem.thisObject = this; } /** * 创建数据 * @param classConstructor 数据对象类型 * @returns */ static createData(classConstructor: Constructor): T { this.deleteData(classConstructor); let data = new classConstructor(); DataSystem.thisObject.dataMap.set(classConstructor, data); DataSystem.thisObject.watchData.set(data, new Map()); return data; } /** * 注册已经实例好的数据对象 * @param data 数据对象 * @param mainKey 主键 */ static regeditData(data: Data, mainKey?: PropertyKey): void { var constructor = data.constructor as Constructor; if (!mainKey) { DataSystem.thisObject.dataMap.set(constructor, data); } else { let oneDataMap: Map = DataSystem.thisObject.dataMap.get(constructor) as Map; if (!DataSystem.thisObject.dataMap.has(constructor)) { oneDataMap = new Map(); } oneDataMap.set(data[mainKey], data); DataSystem.thisObject.dataMap.set(constructor, oneDataMap); } DataSystem.thisObject.watchData.set(data, new Map()); } /** * 获取数据 * @param classConstructor 数据对象类型 * @param mainValue 主键的值 * @returns */ static getData(classConstructor: Constructor, mainValue?: PropertyKey): T { if (mainValue === undefined) { return DataSystem.thisObject.dataMap.get(classConstructor) as T; } else { let oneDataMap: Map = DataSystem.thisObject.dataMap.get(classConstructor) as Map; if (oneDataMap) { return oneDataMap.get(mainValue) as T; } } } /** * 删除数据 * @param classConstructor 数据对象类型 * @param mainValue 主键的值 */ static deleteData(classConstructor: Constructor, mainValue?: PropertyKey): void { if (mainValue === undefined) { DataSystem.thisObject.watchData.delete(DataSystem.thisObject.dataMap.get(classConstructor) as Data); DataSystem.thisObject.dataMap.delete(classConstructor); } else { let oneDataMap: Map = DataSystem.thisObject.dataMap.get(classConstructor) as Map; if (oneDataMap) { oneDataMap.delete(mainValue); } if (!oneDataMap || !oneDataMap.size) { DataSystem.thisObject.watchData.delete(DataSystem.thisObject.dataMap.get(classConstructor) as Data); } DataSystem.thisObject.watchData.delete(oneDataMap.get(mainValue)); } } /** * 观察数据,当数据产生变化时会被观察到,被观察后会在帧尾清空标记 * 注意:在watch帧的时候,改变正在watch的属性值是不会被观察到变化的 * @param data 数据对象 * @param key 数据的属性名 * @returns */ static watch(data: Data | Constructor, key: PropertyKey) { let d: Data; if (data instanceof Data) { d = data; } else { d = this.getData(data as any); } if (!d || !DataSystem.thisObject.watchData.has(d)) { return false; } let propertyKeyMap = DataSystem.thisObject.watchData.get(d); let result = propertyKeyMap.has(key); if (result && DataSystem.frameID <= propertyKeyMap.get(key)) { return false; } !result && typeof key != 'symbol' && (result = propertyKeyMap.has(key + "")); result && DataSystem.thisObject.watchedList.push({ data: d, key }); return result; } lateUpdate() { for (let i = 0; i < this.watchedList.length; i++) { const watchedData = this.watchedList[i]; let propertyKeyMap = DataSystem.thisObject.watchData.get(watchedData.data); if (propertyKeyMap.has(watchedData.key)) { this.watchData.get(watchedData.data).delete(watchedData.key); } else if (typeof watchedData.key != 'symbol' && propertyKeyMap.has(watchedData.key + "")) { this.watchData.get(watchedData.data).delete(watchedData.key + ""); this.watchData.get(watchedData.data).delete(watchedData.key); } } this.watchedList = []; } private static frameID: number = 1; update() { DataSystem.frameID++; } public static onPropertyChange(data: Data, key: PropertyKey) { if (!this.thisObject) { return; } if (!this.thisObject.watchData.has(data)) { this.thisObject.watchData.set(data, new Map()); } let propertyKeyMap = this.thisObject.watchData.get(data); propertyKeyMap.set(key, this.frameID); } }