import { ch } from "../../ch/ch"; import PeriodData, { PeriodDataUpdate } from "./PeriodData"; export interface data_interface { serialize(): any; unserialize(data: any): void; } /**游戏数据 * 有额外自定义数据可以继承此类 */ export default class GameData { private _key: string; private _uid: string; private _gid: string; private _save_time: number; private _ver: string; private _data: PeriodData; private _day_data: PeriodData
; private _week_data: PeriodData; private _month_data: PeriodData; constructor(gid: string, uid: string, name: string, limt?: Map, day_limt?: Map, week_limt?: Map, month_limt?: Map, ) { this._key = name; this._gid = gid; this._uid = uid; this._data = new PeriodData(PeriodDataUpdate.none, limt); this._day_data = new PeriodData
(PeriodDataUpdate.day, day_limt); this._week_data = new PeriodData(PeriodDataUpdate.week, week_limt); this._month_data = new PeriodData(PeriodDataUpdate.month, month_limt); } // public get data(): PeriodData { return this._data }; public get day_data(): PeriodData
{ return this._day_data }; public get week_data(): PeriodData { return this._week_data }; public get month_data(): PeriodData { return this._month_data }; public get uid(): string { return this._uid }; // private _dirty: boolean = false; public checkNewDay(): void { let now = ch.date.now(); this._day_data?.check(now); this._week_data?.check(now); this._month_data?.check(now); } // private compareVersion(version1: string, version2: string): number { // 移除前面的 'v' 字符 const v1 = version1.replace(/^V/, ''); const v2 = version2.replace(/^V/, ''); // 分割版本号 const parts1 = v1.split('.').map(Number); // 将版本号分割并转为数字 const parts2 = v2.split('.').map(Number); // 比较每一部分 for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) { const num1 = parts1[i] || 0; // 如果没有该部分,默认为 0 const num2 = parts2[i] || 0; if (num1 < num2) { return -1; // version1 < version2 } if (num1 > num2) { return 1; // version1 > version2 } } return 0; // 两个版本号相等 } // private async loadGameDataWithRetry(maxRetries: number = 3, delayMs: number = 1000): Promise { let attempt = 0; while (attempt < maxRetries) { const data = await this.load_data(); if (data != null) { return data ?? null; } else { attempt++; await new Promise(resolve => setTimeout(resolve, delayMs)); } } return null; } // private async saveGameDataWithRetry(save_data: { [key: string]: any }, maxRetries: number = 3, delayMs: number = 1000): Promise { let attempt = 0; while (attempt < maxRetries) { const ret = await this.save_data(save_data); if (ret) { return true; } else { attempt++; await new Promise(resolve => setTimeout(resolve, delayMs)); } } return false; } /**加载数据*/ public async load(ver?: string | null): Promise { this.on_load(0); let load_data = ch.storage.getObject(this._key, this._gid); if (load_data) { if (ch.sdk.get_inited() && load_data.uid != this._uid) load_data = null; } // if (!load_data) { const remote_data = await this.loadGameDataWithRetry(); load_data = remote_data; } // } else if (remote_data && this.on_check(load_data, remote_data)) { // load_data = remote_data; // } // if (!load_data) { this.on_init(); } else { this.unserialize(load_data); } this.checkVer(ver); this.checkNewDay(); this.on_load(1); } /**远程调用保存,如果不是强制远程保存,必并先设置脏数据*/ public async save(force: boolean = false): Promise { this.on_save(0); if (force) { this.setDirty(); } else if (!this._dirty) { this.on_save(1); return false; } let ret = await this.saveGameDataWithRetry(this.serialize()); this.on_save(1); if (ret) this._dirty = false; return ret; } /**设置脏数据后保存到本地*/ public setDirty() { this._dirty = true; ch.storage.set(this._key, this.serialize(), this._gid); } private checkVer(new_v: string | null): void { if (!new_v) return; if (!this._ver) { this.on_ver(true, this._ver, new_v); } let k = this.compareVersion(this._ver, new_v); this.on_ver(k < 0, this._ver, new_v); this._ver = new_v; } /** * 序列化(数据库存储) */ private serialize(): { [key: string]: number | string | any } { const save_data: { [key: string]: number | string } = {}; if (this._data) save_data.data = this._data.serialize(); if (this._day_data) save_data.day_data = this._day_data.serialize(); if (this._week_data) save_data.week_data = this._week_data.serialize(); if (this._month_data) save_data.month_data = this._month_data.serialize(); save_data.uid = this._uid; save_data.gid = this._gid; this._save_time = ch.date.now(); save_data.save_time = this._save_time; if (this._ver) save_data.ver = this._ver; this.on_serialize(save_data); return save_data; } /** * 反序列化 */ private unserialize(load_data: { [key: string]: number | string | any }): void { if (!load_data) return; this._data?.unserialize(load_data.data); this._day_data?.unserialize(load_data.day_data); this._week_data?.unserialize(load_data.week_data); this._month_data?.unserialize(load_data.month_data); this._uid = load_data.uid ?? this._uid; this._gid = load_data.gid ?? this._gid; this._save_time = load_data.save_time as number ?? ch.date.now(); if (load_data.ver) this._ver = load_data.ver as string; this.on_unserialize(load_data); } /**重写此方法初始自定义数据*/ protected on_init(): void { } /**重写此方法检测是否使用远程数据*/ protected on_check(local: any, remote: any): boolean { return true; } /**重写 版本检测数据处理*/ protected on_ver(is_new: boolean, old_v: string, new_v: string): void { } /**重写序列化加入自定义的数据*/ protected on_serialize(data: { [key: string]: number | string | any }): void { } /**重写反序列化*/ protected on_unserialize(data: { [key: string]: number | string | any }): void { } /**保存数据(0开始 1结束)*/ protected on_save(step: 0 | 1): void { } /**加载数据(0开始 1结束)*/ protected on_load(step: 0 | 1): void { } /**重写成其它加载方式*/ protected async load_data(): Promise<{ [key: string]: any; }> { const ret = await ch.sdk.loadGameData(this._key); if (ret.code === 0) { return ret.data; } else { ch.log.warn(`尝试加载数据失败,错误代码: ${ret.code} ${ret.err}`); } return null; } /**重写成其它保存方式*/ protected async save_data(save_data: { [key: string]: any; }): Promise { const ret = await ch.sdk.saveGameData(this._key, save_data); if (ret.code == 0) { return true; } else { ch.log.warn(`尝试保存数据失败,错误代码: ${ret.code} ${ret.err}`); return false; } } }