refactor(game): 重构游戏云端数据同步逻辑

1. 新增微信云函数双向同步接口,将时间戳对比逻辑移至云端完成
2. 简化初始化流程,合并云端登录与数据同步步骤
3. 重构GameDataSync类,统一同步流程并改为异步调用
4. 替换旧的getCloudData接口为新的syncFromCloud方法
This commit is contained in:
pan
2026-08-07 10:04:55 +08:00
parent 076e03742d
commit ac2de96bd0
5 changed files with 135 additions and 78 deletions

View File

@@ -94,60 +94,65 @@ export class GameDataSync {
}
/**
* 将获取到的云端数据与本地对比并合并
* 登录阶段与云端双向同步数据sync 模式)。
* 时间戳对比在云端完成:
* - 本地较新:云端已被本地数据覆盖,无需额外处理
* - 云端较新:用云端数据覆盖本地,并写入 localStorage
* @returns true=本次以云端数据为准覆盖了本地false=以本地数据为准或同步失败
*/
public syncWithCloudData(cloudData: CloudData | null) {
public async syncFromCloud(): Promise<boolean> {
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 (!this.isWxClient()) {
if (localData) {
smc.overrideLocalDataWithRemote({ data: localData });
}
return false;
});
}
try {
// 本地无缓存时用空对象参与对比,云端会直接下发
const gameData = localData || ({} as GameDate);
gameData.timestamp = gameData.timestamp || 0;
const result = await WxCloudApi.sync(gameData);
const response = result.result;
if (response && response.code === 200 && response.data) {
const cloudData: CloudData = {
openid: response.data.openid || '',
data: (response.data.game_data || {}) as GameDate,
};
if (response.updated) {
// 本地数据较新,云端已被覆盖
mLogger.log(this.debugMode, 'GameDataSync', `[GameDataSync]: 本地数据较新,已覆盖云端。`);
if (localData) {
smc.overrideLocalDataWithRemote({ data: localData });
}
return false;
} else {
// 云端数据较新,覆盖本地
mLogger.log(this.debugMode, 'GameDataSync', `[GameDataSync]: 云端数据较新,覆盖本地。`);
smc.overrideLocalDataWithRemote(cloudData);
this.saveToLocal();
return true;
}
}
mLogger.warn(this.debugMode, 'GameDataSync', `[GameDataSync]: 云端同步失败,使用本地缓存兜底。`, response?.msg);
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;
}
}
}

View File

@@ -228,7 +228,7 @@ export class SingletonModuleComp extends ecs.Comp {
}
getCloudData() {
gameDataSync.getCloudData();
gameDataSync.syncFromCloud();
}
public async overrideLocalDataWithRemote(cloudData: any) {
try {