Files
pixelheros/assets/script/game/common/GameDataSync.ts
panw 424c9490e7 refactor(game): 重构云端数据同步逻辑并提取公共方法
- 将 `getCloudData` 中的冲突解决逻辑提取为独立的 `syncWithCloudData` 方法
- 修改 `getCloudData` 返回 Promise 以支持调用方等待
- 在 `Initialize` 中统一使用 `gameDataSync.syncWithCloudData` 处理数据合并
- 移除 `Initialize` 中重复的 `isWxClient` 方法,复用 `GameDataSync` 中的实现
- 简化 `loadFromCloud` 方法,将登录后数据处理委托给 `syncWithCloudData`
2026-04-28 16:25:18 +08:00

154 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { sys } from "cc";
import { WxCloudApi } from "../wx_clound_client_api/WxCloudApi";
import { mLogger } from "./Logger";
import { smc, GameDate, CloudData } from "./SingletonModuleComp";
export class GameDataSync {
private debugMode: boolean = false;
private _localDataDirty: boolean = false;
private _lastSyncTime: number = 0;
private _syncTimerId: any = null;
private readonly LOCAL_STORAGE_KEY = "Heros_GameData_Local";
/** 标记数据为脏,并更新时间戳,然后保存到本地 */
public markDataDirty() {
this._localDataDirty = true;
this.saveToLocal();
// 尝试触发异步同步
this.tryAsyncCloudSync();
}
/** 同步数据到本地 localStorage */
private saveToLocal() {
try {
const data = smc.getGameDate();
data.timestamp = Date.now(); // 更新时间戳
sys.localStorage.setItem(this.LOCAL_STORAGE_KEY, JSON.stringify(data));
} catch (error) {
mLogger.error(this.debugMode, 'GameDataSync', '保存本地数据失败:', error);
}
}
/** 从本地 localStorage 读取数据 */
private loadFromLocal(): GameDate | null {
try {
const str = sys.localStorage.getItem(this.LOCAL_STORAGE_KEY);
if (str) {
return JSON.parse(str) as GameDate;
}
} catch (error) {
mLogger.error(this.debugMode, 'GameDataSync', '读取本地数据失败:', error);
}
return null;
}
/**
* 判断是否为微信客户端
*/
public isWxClient(): boolean {
return sys.platform === sys.Platform.WECHAT_GAME;
}
public updateCloudData() {
this.markDataDirty();
return true;
}
/** 尝试异步同步云端数据带有防抖Debounce保护 */
private tryAsyncCloudSync() {
if (!this.isWxClient()) return;
// 如果当前有同步在等待,清除之前的定时器
if (this._syncTimerId !== null) {
clearTimeout(this._syncTimerId);
}
// 防抖:延迟 3 秒同步,期间多次操作合并为一次同步请求
this._syncTimerId = setTimeout(() => {
this._syncTimerId = null;
this.executeCloudSync();
}, 3000);
}
/** 实际执行云端同步 */
private executeCloudSync() {
if (!this._localDataDirty) return;
let gameData = smc.getGameDate();
// 保证云端存一份时间戳,供下次登录对比
gameData.timestamp = Date.now();
WxCloudApi.save(gameData).then((result) => {
if (result.result.code === 200) {
mLogger.log(this.debugMode, 'GameDataSync', "静默云端保存成功", result.result);
// 同步成功,清除脏标记
this._localDataDirty = false;
this._lastSyncTime = Date.now();
} else {
mLogger.warn(this.debugMode, 'GameDataSync', `[GameDataSync]: 静默同步失败(等待下次重试): ${result.result.msg}`);
// 失败了不清除脏标记,下次有变化或定时器检查时会再次重试
}
}).catch((error) => {
mLogger.error(this.debugMode, 'GameDataSync', `[GameDataSync]: 静默同步异常(等待下次重试):`, error);
});
}
/**
* 将获取到的云端数据与本地对比并合并
*/
public syncWithCloudData(cloudData: CloudData | null) {
const localData = this.loadFromLocal();
let cloudTs = cloudData?.data?.timestamp || 0;
let localTs = localData?.timestamp || 0;
if (!localData || cloudTs > localTs) {
mLogger.log(this.debugMode, 'GameDataSync', `[GameDataSync]: 云端数据较新 (Cloud: ${cloudTs} > Local: ${localTs}), 执行覆盖。`);
if (cloudData) {
smc.overrideLocalDataWithRemote(cloudData);
this.saveToLocal(); // 同步到本地
}
} else {
mLogger.log(this.debugMode, 'GameDataSync', `[GameDataSync]: 本地数据较新 (Local: ${localTs} >= Cloud: ${cloudTs}), 使用本地数据,触发强制云同步。`);
smc.overrideLocalDataWithRemote({ data: localData });
// 本地数据较新,需要强制推送到云端以保证多端一致
this._localDataDirty = true;
this.executeCloudSync();
}
}
public getCloudData() {
const localData = this.loadFromLocal();
// 未登录微信云端前,先用本地数据顶上(让玩家秒进游戏)
if (localData && !this.isWxClient()) {
smc.overrideLocalDataWithRemote({ data: localData });
return Promise.resolve(false);
}
return WxCloudApi.get().then(async (result) => {
if(result.result.code === 200) {
let cloudData = result.result.data as CloudData;
mLogger.log(this.debugMode, 'GameDataSync', `[GameDataSync]: 获取游戏云端数据成功:`, cloudData);
this.syncWithCloudData(cloudData);
return true;
} else {
mLogger.warn(this.debugMode, 'GameDataSync', `[GameDataSync]: 获取游戏云端数据失败,使用本地缓存兜底。`);
if (localData) {
smc.overrideLocalDataWithRemote({ data: localData });
}
return false;
}
}).catch((error) => {
mLogger.error(this.debugMode, 'GameDataSync', `[GameDataSync]: 获取游戏云端数据异常:`, error);
if (localData) {
smc.overrideLocalDataWithRemote({ data: localData });
}
return false;
});
}
}
export const gameDataSync = new GameDataSync();