refactor(common): 重构游戏数据同步与单例模块代码
- 移除 GameDataSyncManager 类及相关依赖,简化数据同步管理逻辑 - 在 SingletonModuleComp 中集成数据管理功能,使用本地数组替代字典结构存储英雄数据 - 优化本地与云端数据同步方法,适配云函数接口改动 - 修改英雄判断逻辑,支持基于数组的查询方式 - 修正金币数据的增减接口,增加异步云调用与本地更新的统一处理 - 删除冗余注释及无用代码,提升代码可读性和维护性 - 调整数据结构定义和类型声明,保障类型安全与代码健壮性
This commit is contained in:
9
assets/Scripts.meta
Normal file
9
assets/Scripts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "f784d67d-edb7-4b84-9ea8-de8d2eb4c174",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -1,527 +0,0 @@
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { WxCloudApi ,UserGameData} from "../wx_clound_client_api/WxCloudApi";
|
||||
import { smc } from "./SingletonModuleComp";
|
||||
import { GameData } from "../wx_clound_client_api/WxCloudApi";
|
||||
|
||||
/**
|
||||
* 游戏数据同步管理器
|
||||
* 负责管理fight_heros、heros、items、tals、equips的远程操作和本地同步
|
||||
* 只有在远程修改成功后才同步修改本地数据
|
||||
*/
|
||||
export class GameDataSyncManager {
|
||||
private static instance: GameDataSyncManager;
|
||||
|
||||
private constructor() {}
|
||||
|
||||
public static getInstance(): GameDataSyncManager {
|
||||
if (!GameDataSyncManager.instance) {
|
||||
GameDataSyncManager.instance = new GameDataSyncManager();
|
||||
}
|
||||
return GameDataSyncManager.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用远程数据覆盖本地数据(统一方法)
|
||||
* @param remoteData 远程数据(云端或本地调试)
|
||||
* @param dataSource 数据源描述
|
||||
*/
|
||||
async overrideLocalDataWithRemote(remoteData: UserGameData, dataSource: string) {
|
||||
try {
|
||||
// console.log(`[Initialize]: 开始用${dataSource}数据覆盖客户端数据...`);
|
||||
|
||||
// 直接覆盖基础游戏数据
|
||||
if (remoteData.data) {
|
||||
Object.assign(smc.data, remoteData.data);
|
||||
// console.log(`[Initialize]: 基础游戏数据已从${dataSource}覆盖`);
|
||||
}
|
||||
|
||||
// 直接覆盖出战英雄配置
|
||||
if (remoteData.fight_heros) {
|
||||
Object.assign(smc.fight_heros, remoteData.fight_heros);
|
||||
// console.log(`[Initialize]: 出战英雄配置已从${dataSource}覆盖`);
|
||||
}
|
||||
|
||||
// 直接覆盖英雄数据
|
||||
if (remoteData.heros) {
|
||||
smc.heros = { ...remoteData.heros };
|
||||
// console.log(`[Initialize]: 英雄数据已从${dataSource}覆盖`);
|
||||
}
|
||||
|
||||
// 直接覆盖道具数据
|
||||
if (remoteData.items) {
|
||||
Object.assign(smc.items, remoteData.items);
|
||||
// console.log(`[Initialize]: 道具数据已从${dataSource}覆盖`);
|
||||
}
|
||||
|
||||
// 直接覆盖天赋数据
|
||||
if (remoteData.tals) {
|
||||
Object.assign(smc.tals, remoteData.tals);
|
||||
// console.log(`[Initialize]: 天赋数据已从${dataSource}覆盖`);
|
||||
}
|
||||
|
||||
// 直接覆盖装备数据
|
||||
if (remoteData.equips) {
|
||||
Object.assign(smc.equips, remoteData.equips);
|
||||
// console.log(`[Initialize]: 装备数据已从${dataSource}覆盖`);
|
||||
}
|
||||
|
||||
// 保存到本地存储(确保数据持久化)
|
||||
// smc.saveGameData();
|
||||
|
||||
// console.log(`[Initialize]: ${dataSource}数据覆盖完成,已保存到本地`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`[Initialize]: ${dataSource}数据覆盖失败:`, error);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 批量更新出战英雄配置
|
||||
* @param fightHeros 出战英雄配置对象
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async updateFightHeros(fightHero: any): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 批量更新出战英雄配置:`, fightHeros);
|
||||
|
||||
const result = await WxCloudApi.updateFightHeros(fightHero);
|
||||
|
||||
if (result.result.code === 200) {
|
||||
// 远程修改成功,同步本地数据
|
||||
Object.assign(smc.fight_heros, fightHeros);
|
||||
// console.log(`[GameDataSyncManager]: 出战英雄配置更新成功,本地数据已同步`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 出战英雄配置更新失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 更新出战英雄配置异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 重置出战英雄配置为默认值
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async resetFightHeros(): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 重置出战英雄配置`);
|
||||
|
||||
const result = await WxCloudApi.resetFightHeros();
|
||||
|
||||
if (result.result.code === 200) {
|
||||
// 远程修改成功,同步本地数据
|
||||
smc.fight_heros = result.result.data;
|
||||
// console.log(`[GameDataSyncManager]: 出战英雄配置重置成功,本地数据已同步`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 出战英雄配置重置失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 重置出战英雄配置异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 英雄管理 ====================
|
||||
|
||||
/**
|
||||
* 添加新英雄到用户库存
|
||||
* @param heroId 英雄ID
|
||||
* @param heroData 英雄数据(可选)
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async addHero(heroId: number, heroData?: any): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 添加英雄 ID:${heroId}, 数据:`, heroData);
|
||||
|
||||
const result = await WxCloudApi.addHero(heroId, heroData);
|
||||
|
||||
if (result.result.code === 200) {
|
||||
// 远程修改成功,同步本地数据
|
||||
smc.heros[heroId] = result.result.data;
|
||||
// console.log(`[GameDataSyncManager]: 英雄添加成功,本地数据已同步`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 英雄添加失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 添加英雄异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新英雄的多个属性
|
||||
* @param heroId 英雄ID
|
||||
* @param updateData 要更新的属性
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async updateHero(heroId: number, updateData: any): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 更新英雄 ID:${heroId}, 更新数据:`, updateData);
|
||||
|
||||
const result = await WxCloudApi.updateHero(heroId, updateData);
|
||||
|
||||
if (result.result.code === 200) {
|
||||
// 远程修改成功,同步本地数据
|
||||
Object.assign(smc.heros[heroId], result.result.data.new_data);
|
||||
// console.log(`[GameDataSyncManager]: 英雄更新成功,本地数据已同步`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 英雄更新失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 更新英雄异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置英雄的单个属性值
|
||||
* @param heroId 英雄ID
|
||||
* @param property 属性名
|
||||
* @param value 属性值
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async setHeroProperty(heroId: number, property: any, value: any): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 设置英雄属性 ID:${heroId}, 属性:${property}, 值:${value}`);
|
||||
|
||||
const result = await WxCloudApi.setHeroProperty(heroId, property, value);
|
||||
|
||||
if (result.result.code === 200) {
|
||||
// 远程修改成功,同步本地数据
|
||||
smc.heros[heroId][property] = value;
|
||||
// console.log(`[GameDataSyncManager]: 英雄属性设置成功,本地数据已同步`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 英雄属性设置失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 设置英雄属性异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 英雄升级指定级数
|
||||
* @param heroId 英雄ID
|
||||
* @param levels 升级级数(默认1级)
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async levelUpHero(heroId: number,levels: number = 1,): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 英雄升级 ID:${heroId}, 级数:${levels}`);
|
||||
|
||||
const result = await WxCloudApi.levelUpHero(heroId,levels);
|
||||
|
||||
if (result.result.code === 200) {
|
||||
// 远程修改成功,同步本地数据
|
||||
smc.heros[heroId].lv = result.result.data.new_value;
|
||||
// console.log(`[GameDataSyncManager]: 英雄升级成功,本地数据已同步`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 英雄升级失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 英雄升级异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 便捷方法 ====================
|
||||
|
||||
/**
|
||||
* 增加道具
|
||||
* @param itemId 道具ID
|
||||
* @param count 数量
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async addItem(itemId: number, count: number): Promise<boolean> {
|
||||
smc.items[itemId] = (smc.items[itemId] || 0) + count;
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 增加道具 ID:${itemId}, 数量:${count}`);
|
||||
const result = await WxCloudApi.addInventoryItem('items', itemId, count);
|
||||
if (result.result.code === 200) {
|
||||
// 远程修改成功,同步本地数据
|
||||
// console.log(`[GameDataSyncManager]: 道具增加成功`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 道具增加失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 增加道具异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 消耗道具
|
||||
* @param itemId 道具ID
|
||||
* @param count 数量
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async consumeItem(itemId: number, count: number): Promise<boolean> {
|
||||
if(!smc.items[itemId]||smc.items[itemId]<count){
|
||||
oops.gui.toast("道具数量不足")
|
||||
return false
|
||||
}
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 消耗道具 ID:${itemId}, 数量:${count}`);
|
||||
const result = await WxCloudApi.consumeInventoryItem('items', itemId, count);
|
||||
if (result.result.code === 200) {
|
||||
// 远程修改成功,同步本地数据
|
||||
smc.items[itemId] = Math.max(0, (smc.items[itemId] || 0) - count);
|
||||
// console.log(`[GameDataSyncManager]: 道具消耗成功,本地数据已同步`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 道具消耗失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 消耗道具异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 增加天赋点
|
||||
* @param talId 天赋ID
|
||||
* @param count 数量
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async addTalent(talId: number, count: number): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 增加天赋点 ID:${talId}, 数量:${count}`);
|
||||
|
||||
const result = await WxCloudApi.addInventoryItem('tals', talId, count);
|
||||
|
||||
if (result.result.code === 200) {
|
||||
// 远程修改成功,同步本地数据
|
||||
smc.tals[talId] = (smc.tals[talId] || 0) + count;
|
||||
// console.log(`[GameDataSyncManager]: 天赋点增加成功,本地数据已同步`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 天赋点增加失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 增加天赋点异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 消耗天赋点
|
||||
* @param talId 天赋ID
|
||||
* @param count 数量
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async consumeTalent(talId: number, count: number): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 消耗天赋点 ID:${talId}, 数量:${count}`);
|
||||
|
||||
const result = await WxCloudApi.consumeInventoryItem('tals', talId, count);
|
||||
|
||||
if (result.result.code === 200) {
|
||||
// 远程修改成功,同步本地数据
|
||||
smc.tals[talId] = Math.max(0, (smc.tals[talId] || 0) - count);
|
||||
// console.log(`[GameDataSyncManager]: 天赋点消耗成功,本地数据已同步`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 天赋点消耗失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 消耗天赋点异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加装备
|
||||
* @param equipId 装备ID
|
||||
* @param count 数量
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async addEquipment(equipId: number, count: number): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 增加装备 ID:${equipId}, 数量:${count}`);
|
||||
|
||||
const result = await WxCloudApi.addInventoryItem('equips', equipId, count);
|
||||
|
||||
if (result.result.code === 200) {
|
||||
// 远程修改成功,同步本地数据
|
||||
smc.equips[equipId] = (smc.equips[equipId] || 0) + count;
|
||||
// console.log(`[GameDataSyncManager]: 装备增加成功,本地数据已同步`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 装备增加失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 增加装备异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 消耗装备
|
||||
* @param equipId 装备ID
|
||||
* @param count 数量
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async consumeEquipment(equipId: number, count: number): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 消耗装备 ID:${equipId}, 数量:${count}`);
|
||||
|
||||
const result = await WxCloudApi.consumeInventoryItem('equips', equipId, count);
|
||||
|
||||
if (result.result.code === 200) {
|
||||
// 远程修改成功,同步本地数据
|
||||
smc.equips[equipId] = Math.max(0, (smc.equips[equipId] || 0) - count);
|
||||
// console.log(`[GameDataSyncManager]: 装备消耗成功,本地数据已同步`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 装备消耗失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 消耗装备异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
async addGameProperty(property: string, value: any): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 增加游戏数据 ${property} = ${value}`);
|
||||
const result = await WxCloudApi.addGameDataField(property, value);
|
||||
if (result.result.code === 200) {
|
||||
// console.log(`[GameDataSyncManager]: 游戏数据增加成功`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 游戏数据增加失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 增加游戏数据异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async spendGameProperty(property: string|Record<string, number>, value: any = undefined ): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 消耗游戏数据 ${property} = ${value}`);
|
||||
const result = await WxCloudApi.spendGameDataField(property, value);
|
||||
if (result.result.code === 200) {
|
||||
// console.log(`[GameDataSyncManager]: 游戏数据消耗成功`);
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 消耗游戏数据异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从云端加载所有游戏数据并同步到本地
|
||||
* @returns 是否成功
|
||||
*/
|
||||
async loadAllGameData(): Promise<boolean> {
|
||||
try {
|
||||
// console.log(`[GameDataSyncManager]: 从云端加载所有游戏数据`);
|
||||
|
||||
const result = await WxCloudApi.getAllGameData();
|
||||
|
||||
if (result.result.code === 200) {
|
||||
// 远程数据获取成功,同步本地数据
|
||||
const cloudData = result.result.data;
|
||||
smc.data = cloudData.data;
|
||||
smc.fight_heros = cloudData.fight_heros;
|
||||
smc.heros = cloudData.heros;
|
||||
smc.items = cloudData.items;
|
||||
smc.tals = cloudData.tals;
|
||||
smc.equips = cloudData.equips;
|
||||
|
||||
// console.log(`[GameDataSyncManager]: 云端数据加载成功,本地数据已同步`);
|
||||
return true;
|
||||
} else {
|
||||
console.warn(`[GameDataSyncManager]: 云端数据加载失败: ${result.result.msg}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[GameDataSyncManager]: 加载云端数据异常:`, error);
|
||||
smc.error()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 导出单例实例
|
||||
export const gameDataSyncManager = GameDataSyncManager.getInstance();
|
||||
|
||||
/*
|
||||
使用示例:
|
||||
|
||||
// 1. 出战英雄管理
|
||||
await gameDataSyncManager.updateFightHeros({0: 5001, 1: 5005}); // 批量更新
|
||||
await gameDataSyncManager.resetFightHeros(); // 重置为默认配置
|
||||
|
||||
// 2. 英雄管理
|
||||
await gameDataSyncManager.addHero(5008, {uuid: 5008, lv: 1}); // 添加新英雄
|
||||
await gameDataSyncManager.levelUpHero(5001, 100, 50, 5); // 英雄升级5级
|
||||
await gameDataSyncManager.setHeroProperty(5001, "exp", 1000); // 设置英雄经验
|
||||
|
||||
// 3. 道具管理 (items)
|
||||
await gameDataSyncManager.addItem(1001, 10); // 增加道具
|
||||
await gameDataSyncManager.consumeItem(1001, 2); // 消耗道具
|
||||
await gameDataSyncManager.setItem(1001, 5); // 设置道具数量
|
||||
|
||||
// 4. 天赋点管理 (tals)
|
||||
await gameDataSyncManager.addTalent(2001, 5); // 增加天赋点
|
||||
await gameDataSyncManager.consumeTalent(2001, 2); // 消耗天赋点
|
||||
await gameDataSyncManager.setTalent(2001, 10); // 设置天赋点数量
|
||||
|
||||
// 5. 装备管理 (equips)
|
||||
await gameDataSyncManager.addEquipment(3001, 2); // 增加装备
|
||||
await gameDataSyncManager.consumeEquipment(3001, 1); // 消耗装备
|
||||
await gameDataSyncManager.setEquipment(3001, 3); // 设置装备数量
|
||||
|
||||
// 6. 数据加载
|
||||
await gameDataSyncManager.loadAllGameData(); // 从云端加载所有数据
|
||||
|
||||
注意:所有方法都返回 Promise<boolean>,true表示成功,false表示失败
|
||||
只有在远程修改成功后,本地数据才会被同步修改
|
||||
*/
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "89c45a3b-d0bf-4e45-9e27-b7d714ba7e29",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -3,14 +3,10 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec
|
||||
import { Initialize } from "../initialize/Initialize";
|
||||
import { GameMap } from "../map/GameMap";
|
||||
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
||||
import { GameData, WxCloudApi } from "../wx_clound_client_api/WxCloudApi";
|
||||
import { gameDataSyncManager } from "./GameDataSyncManager";
|
||||
import { WxCloudApi, UserGameData } from "../wx_clound_client_api/WxCloudApi";
|
||||
import { Test } from "./Test";
|
||||
import { GameEvent } from "./config/GameEvent";
|
||||
|
||||
|
||||
// import { Role } from "../role/Role";
|
||||
// import { data } from "../data/data";
|
||||
/** 游戏模块 */
|
||||
@ecs.register('SingletonModule')
|
||||
export class SingletonModuleComp extends ecs.Comp {
|
||||
@@ -18,8 +14,6 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
initialize: Initialize = null!;
|
||||
/** 游戏地图 */
|
||||
map: GameMap = null!;
|
||||
/** 游戏数据同步管理器 */
|
||||
private gameDataSyncManager = gameDataSyncManager;
|
||||
mission:any={
|
||||
status:0, //0:未开始 1:进行中 2:胜利 3:失败
|
||||
play:false,
|
||||
@@ -32,24 +26,17 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
data:any={
|
||||
score:0,
|
||||
mission:1,
|
||||
gold:100, //升级主要资源
|
||||
diamond:100, //商店购买 及 双倍奖励资源
|
||||
meat:0,
|
||||
exp:0,
|
||||
task:0,
|
||||
}
|
||||
|
||||
fight_hero: number = 5001; // 单个出战英雄
|
||||
heros:any = {
|
||||
5001:{uuid:5001,lv:1},
|
||||
5005:{uuid:5005,lv:1},
|
||||
};
|
||||
monsters:any = [];
|
||||
sk_info:any = []
|
||||
monsters_dead:any = []
|
||||
heros_dead:any = []
|
||||
enhancements:any=[]
|
||||
items: any = {}; // 物品数据
|
||||
vmdata: any = {
|
||||
game_over:false,
|
||||
game_pause:false,
|
||||
@@ -61,7 +48,9 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
fight_time:0,//战斗时间
|
||||
level:1,//关卡等级
|
||||
max_mission:4,//最大关卡
|
||||
coin:0,
|
||||
},
|
||||
gold: 100, // 金币数据(MVVM绑定字段)
|
||||
};
|
||||
vmAdd() {
|
||||
VM.add(this.vmdata, "data");
|
||||
@@ -74,9 +63,9 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
|
||||
// ==================== 数据管理方法 ====================
|
||||
|
||||
/**
|
||||
* 判断是否为微信客户端
|
||||
*/
|
||||
/**
|
||||
* 判断是否为微信客户端
|
||||
*/
|
||||
private isWxClient(): boolean {
|
||||
// 检查是否存在微信API
|
||||
return typeof wx !== 'undefined' && typeof (wx as any).getSystemInfoSync === 'function';
|
||||
@@ -84,26 +73,63 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
|
||||
finishGuide(index:number){
|
||||
smc.guides[index]=1
|
||||
this.syncGuide()
|
||||
}
|
||||
|
||||
syncGuide(){
|
||||
//存储到远程服务器 后续再添加
|
||||
}
|
||||
|
||||
//调试用
|
||||
syncDataFromLocal(){
|
||||
if(this.isWxClient()) return
|
||||
const loginResult = new Test().load_data_from_local()
|
||||
this.gameDataSyncManager.overrideLocalDataWithRemote(loginResult, "本地调试");
|
||||
this.overrideLocalDataWithRemote(loginResult, "本地调试");
|
||||
}
|
||||
|
||||
/**
|
||||
* 用远程数据覆盖本地数据(统一方法)
|
||||
* @param remoteData 远程数据(云端或本地调试)
|
||||
* @param dataSource 数据源描述
|
||||
*/
|
||||
async overrideLocalDataWithRemote(remoteData: UserGameData, dataSource: string) {
|
||||
try {
|
||||
// 直接覆盖基础游戏数据
|
||||
if (remoteData.data) {
|
||||
// 保留原有的data字段数据
|
||||
Object.assign(this.data, remoteData.data);
|
||||
// 同步gold到vmdata
|
||||
if (remoteData.data.gold !== undefined) {
|
||||
this.vmdata.gold = remoteData.data.gold;
|
||||
}
|
||||
}
|
||||
|
||||
// 直接覆盖出战英雄配置
|
||||
if (remoteData.fight_heros) {
|
||||
this.fight_hero = remoteData.fight_heros[0] || this.fight_hero;
|
||||
}
|
||||
|
||||
// 直接覆盖英雄数据
|
||||
if (remoteData.heros) {
|
||||
this.heros = { ...remoteData.heros };
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(`[SMC]: ${dataSource}数据覆盖失败:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
addHero(hero_uuid:number,autoSave:boolean=true){
|
||||
if(this.isWxClient()){
|
||||
if(this.gameDataSyncManager.addHero(hero_uuid)){
|
||||
this.heros[hero_uuid]={ uuid:hero_uuid, lv:1, }
|
||||
return true
|
||||
}
|
||||
return false
|
||||
// 适配原有接口,保持与云函数的兼容性
|
||||
const result = WxCloudApi.addHero(hero_uuid);
|
||||
result.then((res) => {
|
||||
if(res.result.code === 200) {
|
||||
this.heros[hero_uuid]={ uuid:hero_uuid, lv:1, }
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}).catch((error) => {
|
||||
console.error(`[SMC]: 添加英雄异常:`, error);
|
||||
this.error()
|
||||
return false
|
||||
});
|
||||
}
|
||||
this.heros[hero_uuid]={ uuid:hero_uuid, lv:1, }
|
||||
return true
|
||||
@@ -113,7 +139,15 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
setFightHero(heroId: number, autoSave: boolean = true) {
|
||||
this.fight_hero = heroId;
|
||||
if (this.isWxClient()) {
|
||||
this.gameDataSyncManager.updateFightHeros({ 0: heroId }); // 适配原有接口
|
||||
// 适配原有接口,保持与云函数的兼容性
|
||||
WxCloudApi.updateFightHeros({ 0: heroId }).then((result) => {
|
||||
if (result.result.code !== 200) {
|
||||
console.warn(`[SMC]: 出战英雄配置更新失败: ${result.result.msg}`);
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(`[SMC]: 更新出战英雄配置异常:`, error);
|
||||
this.error()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,35 +156,64 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
return this.fight_hero;
|
||||
}
|
||||
|
||||
getHasHeroUUID(){
|
||||
let heros=this.heros
|
||||
let heros_uuid=[]
|
||||
for(let key in heros){
|
||||
heros_uuid.push(heros[key].uuid)
|
||||
}
|
||||
return heros_uuid
|
||||
}
|
||||
|
||||
error(){
|
||||
oops.gui.toast("数据处理异常,请重试或重新登录")
|
||||
}
|
||||
|
||||
addGold(gold:number,autoSave:boolean=true){
|
||||
if(this.isWxClient()){
|
||||
if(this.gameDataSyncManager.addGameProperty("gold",gold)){
|
||||
this.data.gold+=gold
|
||||
oops.message.dispatchEvent(GameEvent.GOLD_UPDATE)
|
||||
return true
|
||||
}
|
||||
this.error()
|
||||
return false
|
||||
WxCloudApi.addGameDataField("gold",gold).then((result) => {
|
||||
if(result.result.code === 200) {
|
||||
this.vmdata.gold += gold;
|
||||
this.data.gold = this.vmdata.gold; // 同步到data字段
|
||||
oops.message.dispatchEvent(GameEvent.GOLD_UPDATE)
|
||||
return true
|
||||
} else {
|
||||
console.warn(`[SMC]: 游戏数据增加失败: ${result.result.msg}`);
|
||||
this.error()
|
||||
return false
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(`[SMC]: 增加游戏数据异常:`, error);
|
||||
this.error()
|
||||
return false
|
||||
});
|
||||
}
|
||||
this.data.gold+=gold
|
||||
this.vmdata.gold += gold;
|
||||
this.data.gold = this.vmdata.gold; // 同步到data字段
|
||||
oops.message.dispatchEvent(GameEvent.GOLD_UPDATE)
|
||||
return true
|
||||
}
|
||||
|
||||
spendGold(gold:number,autoSave:boolean=true){
|
||||
if(this.isWxClient()){
|
||||
if(this.gameDataSyncManager.spendGameProperty("gold",gold)){
|
||||
this.data.gold-=gold
|
||||
oops.message.dispatchEvent(GameEvent.GOLD_UPDATE)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
WxCloudApi.spendGameDataField("gold",gold).then((result) => {
|
||||
if(result.result.code === 200) {
|
||||
this.vmdata.gold -= gold;
|
||||
this.data.gold = this.vmdata.gold; // 同步到data字段
|
||||
oops.message.dispatchEvent(GameEvent.GOLD_UPDATE)
|
||||
return true
|
||||
} else {
|
||||
console.warn(`[SMC]: 游戏数据消耗失败: ${result.result.msg}`);
|
||||
return false
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(`[SMC]: 消耗游戏数据异常:`, error);
|
||||
this.error()
|
||||
return false
|
||||
});
|
||||
}
|
||||
this.data.gold-=gold
|
||||
this.vmdata.gold -= gold;
|
||||
this.data.gold = this.vmdata.gold; // 同步到data字段
|
||||
oops.message.dispatchEvent(GameEvent.GOLD_UPDATE)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ export const getHeroList = (quality:number=0)=>{
|
||||
});
|
||||
|
||||
// 分离拥有和未拥有的英雄
|
||||
const ownedHeros = filteredHeros.filter(item => smc.heros[item.uuid]);
|
||||
const unownedHeros = filteredHeros.filter(item => !smc.heros[item.uuid]);
|
||||
const ownedHeros = filteredHeros.filter(item => smc.heros.some(hero => hero.uuid === item.uuid));
|
||||
const unownedHeros = filteredHeros.filter(item => !smc.heros.some(hero => hero.uuid === item.uuid));
|
||||
|
||||
// 合并列表:拥有的在前,未拥有的在后
|
||||
return [...ownedHeros, ...unownedHeros].map(item => item.uuid);
|
||||
|
||||
@@ -12,8 +12,8 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec
|
||||
import { UIID } from "../common/config/GameUIConfig";
|
||||
import { LoadingViewComp } from "./view/LoadingViewComp";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { WxCloudApi, UserGameData } from "../wx_clound_client_api/WxCloudApi";
|
||||
import { GameDataSyncManager } from "../common/GameDataSyncManager";
|
||||
import { WxCloudApi } from "../wx_clound_client_api/WxCloudApi";
|
||||
|
||||
import { Test } from "../common/Test";
|
||||
|
||||
// import {data} from "../data/data";
|
||||
@@ -141,7 +141,7 @@ export class Initialize extends ecs.Entity {
|
||||
const cloudData = response.data;
|
||||
|
||||
// 3. 用云端数据覆盖本地数据
|
||||
GameDataSyncManager.getInstance().overrideLocalDataWithRemote(cloudData, "云端");
|
||||
|
||||
} else {
|
||||
console.warn("[Initialize]: 云端登录失败:", response.msg);
|
||||
// 登录失败时使用本地数据 游戏需要退出
|
||||
@@ -163,7 +163,7 @@ export class Initialize extends ecs.Entity {
|
||||
const loginResult = new Test().load_data_from_local()
|
||||
|
||||
// 用本地调试数据覆盖客户端数据
|
||||
GameDataSyncManager.getInstance().overrideLocalDataWithRemote(loginResult, "本地调试");
|
||||
|
||||
} catch (error) {
|
||||
console.error("[Initialize]: 本地调试数据加载异常:", error);
|
||||
}
|
||||
|
||||
@@ -1,84 +1,9 @@
|
||||
// 云函数返回类型定义
|
||||
export type CloudReturnType<T = any> = {
|
||||
code: number, // 200成功,其他都是失败
|
||||
msg?: string, // 消息信息
|
||||
data?: T, // 返回数据
|
||||
timestamp?: number, // 时间戳
|
||||
version?: string, // 数据版本
|
||||
execution_time?: number // 执行时间(ms)
|
||||
code: number,// 200成功
|
||||
msg?:string,
|
||||
data?:T
|
||||
}
|
||||
|
||||
// 用户信息类型
|
||||
export type UserInfo = {
|
||||
user_id: string,
|
||||
openid: string,
|
||||
regist_time: number,
|
||||
init_time?: number,
|
||||
data_version?: string,
|
||||
last_save_time?: number
|
||||
}
|
||||
|
||||
// 完整用户数据类型
|
||||
export type UserGameData = UserInfo & {
|
||||
data: GameData,
|
||||
fight_heros: FightHeros,
|
||||
heros: Heros,
|
||||
items: Items,
|
||||
tals: Tals,
|
||||
equips: Equips
|
||||
}
|
||||
|
||||
// 基础游戏数据类型
|
||||
export type GameData = {
|
||||
score: number,
|
||||
mission: number,
|
||||
gold: number,
|
||||
diamond: number,
|
||||
meat: number,
|
||||
exp: number,
|
||||
}
|
||||
|
||||
// 出战英雄类型
|
||||
export type FightHeros = {
|
||||
[position: number]: number // 位置 -> 英雄ID
|
||||
}
|
||||
|
||||
// 英雄数据类型
|
||||
export type HeroData = {
|
||||
uuid: number,
|
||||
lv: number,
|
||||
exp?: number,
|
||||
star?: number,
|
||||
power?: number
|
||||
}
|
||||
|
||||
export type Heros = {
|
||||
[heroId: number]: HeroData
|
||||
}
|
||||
|
||||
// 库存类型
|
||||
export type Items = {
|
||||
[itemId: number]: number
|
||||
}
|
||||
|
||||
export type Tals = {
|
||||
[talId: number]: number
|
||||
}
|
||||
|
||||
export type Equips = {
|
||||
[equipId: number]: number
|
||||
}
|
||||
|
||||
// 版本兼容性检查结果
|
||||
export type VersionCompatibility = {
|
||||
compatible: boolean,
|
||||
needsUpgrade: boolean,
|
||||
message: string
|
||||
}
|
||||
|
||||
// 库存类型枚举
|
||||
export type InventoryType = 'items' | 'tals' | 'equips'
|
||||
|
||||
export class WxCloudApi{
|
||||
/**
|
||||
* @en init the cloud
|
||||
@@ -91,14 +16,30 @@ export class WxCloudApi{
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 认证相关接口 ====================
|
||||
|
||||
/**
|
||||
* @en Login to the cloud
|
||||
* @zh 用户登录,获取完整的用户和游戏数据
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<UserGameData>>>
|
||||
* @zh 登录云
|
||||
* @return 返回结果
|
||||
* 参考:
|
||||
* result.result = {
|
||||
* code: number, // 200成功,其他都是失败
|
||||
* msg: string, // 如果失败,这里是失败原因等信息
|
||||
* data: { // 成功才有
|
||||
* openid: string, // 用户微信平台openid
|
||||
* regist_time: number, // 时间戳,用户注册时间
|
||||
* game_data: object, // 开发者自己保存的数据
|
||||
* }
|
||||
* }
|
||||
* 如果这个泛型令你报错(一般是因为你删了wx.api.d.ts导致),请使用以下签名:
|
||||
* login():Promise<{result: CloudReturnType<{openid: string, regist_time: number, game_data: object}>}>
|
||||
* 或者你是个“不拘小节”的老哥,可以用以下简洁版签名(参考上方的数据结构例子使用即可)
|
||||
* login():Promise<any>
|
||||
*/
|
||||
public static async login(): Promise<CloudCallFunctionResult<CloudReturnType<UserGameData>>> {
|
||||
public static async login(): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
openid:string,
|
||||
regist_time:number,
|
||||
game_data:any
|
||||
}>>>{
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
@@ -108,486 +49,29 @@ export class WxCloudApi{
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Get user basic info
|
||||
* @zh 获取用户基本信息(不包含游戏数据)
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<UserInfo>>>
|
||||
*/
|
||||
public static async getUserInfo(): Promise<CloudCallFunctionResult<CloudReturnType<UserInfo>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "user_info"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Check data version compatibility
|
||||
* @zh 检查数据版本兼容性
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{user_version: string, current_version: string, compatibility: VersionCompatibility}>>>
|
||||
*/
|
||||
public static async checkVersion(): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
user_version: string,
|
||||
current_version: string,
|
||||
compatibility: VersionCompatibility,
|
||||
init_time: number,
|
||||
regist_time: number,
|
||||
last_save_time: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "version"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Force upgrade user data
|
||||
* @zh 强制升级用户数据结构
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{old_version: string, new_version: string, upgrade_time: number} & UserGameData>>>
|
||||
*/
|
||||
public static async upgradeUserData(): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
old_version: string,
|
||||
new_version: string,
|
||||
upgrade_time: number
|
||||
} & UserGameData>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "upgrade"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 基础游戏数据接口 ====================
|
||||
|
||||
/**
|
||||
* @en Get game data
|
||||
* @zh 获取基础游戏数据(金币、钻石、经验等)
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<GameData>>>
|
||||
*/
|
||||
public static async getGameData(): Promise<CloudCallFunctionResult<CloudReturnType<GameData>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "data_get"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Update game data
|
||||
* @zh 批量更新基础游戏数据
|
||||
* @param data 要更新的数据
|
||||
* @param merge 是否合并更新(默认true)
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<GameData>>>
|
||||
*/
|
||||
public static async updateGameData(data: Partial<GameData>, merge: boolean = true): Promise<CloudCallFunctionResult<CloudReturnType<GameData>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "data_update",
|
||||
data: data,
|
||||
merge: merge
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Add to game data field
|
||||
* @zh 增加指定字段的数值
|
||||
* @param field 字段名
|
||||
* @param amount 增加的数量
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{field: string, old_value: number, new_value: number, change: number}>>>
|
||||
*/
|
||||
public static async addGameDataField(field:string, amount: number): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
field: string,
|
||||
old_value: number,
|
||||
new_value: number,
|
||||
change: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "data_add",
|
||||
field: field,
|
||||
amount: amount
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Spend game data field
|
||||
* @zh 消耗指定字段的数值(会检查是否足够)
|
||||
* @param field 字段名
|
||||
* @param amount 消耗的数量
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{field: string, old_value: number, new_value: number, change: number}>>>
|
||||
*/
|
||||
public static async spendGameDataField(field:string|Record<string, number>, amount: number): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
field: string|Record<string, number>,
|
||||
old_value: number,
|
||||
new_value: number,
|
||||
change: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "data_spend",
|
||||
field: field,
|
||||
amount: amount
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Set game data field
|
||||
* @zh 直接设置某个字段的值
|
||||
* @param field 字段名
|
||||
* @param value 新的值
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{field: string, old_value: any, new_value: any}>>>
|
||||
*/
|
||||
public static async setGameDataField(field: keyof GameData, value: any): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
field: string,
|
||||
old_value: any,
|
||||
new_value: any
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "data_set",
|
||||
field: field,
|
||||
value: value
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Reset game data
|
||||
* @zh 重置基础游戏数据为默认值
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<GameData>>>
|
||||
*/
|
||||
public static async resetGameData(): Promise<CloudCallFunctionResult<CloudReturnType<GameData>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "data_reset"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 便捷方法:金币操作
|
||||
/**
|
||||
* @en Add gold
|
||||
* @zh 增加金币
|
||||
* @param amount 金币数量
|
||||
*/
|
||||
public static async addGold(amount: number) {
|
||||
return await this.addGameDataField('gold', amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Spend gold
|
||||
* @zh 消耗金币
|
||||
* @param amount 金币数量
|
||||
*/
|
||||
public static async spendGold(amount: number) {
|
||||
return await this.spendGameDataField('gold', amount);
|
||||
}
|
||||
|
||||
// 便捷方法:钻石操作
|
||||
/**
|
||||
* @en Add diamond
|
||||
* @zh 增加钻石
|
||||
* @param amount 钻石数量
|
||||
*/
|
||||
public static async addDiamond(amount: number) {
|
||||
return await this.addGameDataField('diamond', amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Spend diamond
|
||||
* @zh 消耗钻石
|
||||
* @param amount 钻石数量
|
||||
*/
|
||||
public static async spendDiamond(amount: number) {
|
||||
return await this.spendGameDataField('diamond', amount);
|
||||
}
|
||||
|
||||
// ==================== 出战英雄接口 ====================
|
||||
|
||||
/**
|
||||
* @en Get fight heros
|
||||
* @zh 获取出战英雄配置
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<FightHeros>>>
|
||||
*/
|
||||
public static async getFightHeros(): Promise<CloudCallFunctionResult<CloudReturnType<FightHeros>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "fight_heros_get"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Set fight hero
|
||||
* @zh 设置指定位置的出战英雄
|
||||
* @param position 出战位置 (0-4)
|
||||
* @param heroId 英雄ID,0表示移除
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{position: number, old_hero_id: number, new_hero_id: number}>>>
|
||||
*/
|
||||
public static async setFightHero(position: number, heroId: number): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
position: number,
|
||||
old_hero_id: number,
|
||||
new_hero_id: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "fight_hero_set",
|
||||
position: position,
|
||||
hero_id: heroId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Update fight heros
|
||||
* @zh 批量更新出战英雄配置
|
||||
* @param fightHeros 出战英雄配置对象
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<FightHeros>>>
|
||||
*/
|
||||
public static async updateFightHeros(fightHeros: Partial<FightHeros>): Promise<CloudCallFunctionResult<CloudReturnType<FightHeros>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "fight_heros_update",
|
||||
fight_heros: fightHeros
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Get active fight heros
|
||||
* @zh 获取当前出战的英雄列表(不包含空位)
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{active_heros: Array<{position: number, hero_id: number, hero_data: HeroData}>, total_count: number}>>>
|
||||
*/
|
||||
public static async getActiveFightHeros(): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
active_heros: Array<{
|
||||
position: number,
|
||||
hero_id: number,
|
||||
hero_data: HeroData
|
||||
}>,
|
||||
total_count: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "fight_heros_active"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Swap fight heros
|
||||
* @zh 交换两个出战位置的英雄
|
||||
* @param position1 位置1 (0-4)
|
||||
* @param position2 位置2 (0-4)
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{position1: number, position2: number, hero1_moved_to: number, hero2_moved_to: number}>>>
|
||||
*/
|
||||
public static async swapFightHeros(position1: number, position2: number): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
position1: number,
|
||||
position2: number,
|
||||
hero1_moved_to: number,
|
||||
hero2_moved_to: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "fight_heros_swap",
|
||||
position1: position1,
|
||||
position2: position2
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Reset fight heros
|
||||
* @zh 重置出战英雄配置为默认值
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<FightHeros>>>
|
||||
*/
|
||||
public static async resetFightHeros(): Promise<CloudCallFunctionResult<CloudReturnType<FightHeros>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "fight_heros_reset"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 英雄管理接口 ====================
|
||||
|
||||
/**
|
||||
* @en Get all heros
|
||||
* @zh 获取用户拥有的所有英雄数据
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<Heros>>>
|
||||
*/
|
||||
public static async getHeros(): Promise<CloudCallFunctionResult<CloudReturnType<Heros>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "heros_get"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Get single hero
|
||||
* @zh 获取指定英雄的详细数据
|
||||
* @param heroId 英雄ID
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<HeroData>>>
|
||||
*/
|
||||
public static async getHero(heroId: number): Promise<CloudCallFunctionResult<CloudReturnType<HeroData>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "hero_get",
|
||||
hero_id: heroId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Add new hero
|
||||
* @zh 添加新英雄到用户库存
|
||||
* @param heroId 英雄ID
|
||||
* @param heroData 英雄数据(可选)
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<HeroData>>>
|
||||
*/
|
||||
public static async addHero(heroId: number, heroData?: Partial<HeroData>): Promise<CloudCallFunctionResult<CloudReturnType<HeroData>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "hero_add",
|
||||
hero_id: heroId,
|
||||
hero_data: heroData
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Update hero
|
||||
* @zh 批量更新英雄的多个属性
|
||||
* @param heroId 英雄ID
|
||||
* @param updateData 要更新的属性
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{old_data: HeroData, new_data: HeroData}>>>
|
||||
*/
|
||||
public static async updateHero(heroId: number, updateData: Partial<HeroData>): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
old_data: HeroData,
|
||||
new_data: HeroData
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "hero_update",
|
||||
hero_id: heroId,
|
||||
update_data: updateData
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Set hero property
|
||||
* @zh 设置英雄的单个属性值
|
||||
* @param heroId 英雄ID
|
||||
* @param property 属性名
|
||||
* @param value 属性值
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{hero_id: number, property: string, old_value: any, new_value: any}>>>
|
||||
*/
|
||||
public static async setHeroProperty(heroId: number, property: keyof HeroData, value: any): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
hero_id: number,
|
||||
property: string,
|
||||
old_value: any,
|
||||
new_value: any
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "hero_property_set",
|
||||
hero_id: heroId,
|
||||
property: property,
|
||||
value: value
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Level up hero
|
||||
* @zh 英雄升级指定级数
|
||||
* @param heroId 英雄ID
|
||||
* @param levels 升级级数(默认1级)
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{hero_id: number, property: string, old_value: number, new_value: number}>>>
|
||||
*/
|
||||
public static async levelUpHero(heroId: number,levels: number = 1): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
hero_id: number,
|
||||
property: string,
|
||||
old_value: number,
|
||||
new_value: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "hero_levelup",
|
||||
hero_id: heroId,
|
||||
levels: levels
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Delete hero
|
||||
* @zh 删除指定英雄(会检查是否在出战阵容中)
|
||||
* @param heroId 英雄ID
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<HeroData>>>
|
||||
*/
|
||||
public static async deleteHero(heroId: number): Promise<CloudCallFunctionResult<CloudReturnType<HeroData>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "hero_delete",
|
||||
hero_id: heroId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Get owned hero IDs
|
||||
* @zh 获取用户拥有的所有英雄ID
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{hero_ids: number[], total_count: number}>>>
|
||||
*/
|
||||
public static async getOwnedHeroIds(): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
hero_ids: number[],
|
||||
total_count: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "heros_owned"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 兼容旧接口 ====================
|
||||
|
||||
/**
|
||||
* @en Save game data to the cloud (Legacy)
|
||||
* @zh 把客户端数据写入云,此为全覆盖写入,请自行管理完整数据(兼容旧接口)
|
||||
* @param gameData 游戏数据
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{results: any[]}>>>
|
||||
* @en Save game data to the cloud
|
||||
* @zh 把客户端数据写入云,此为全覆盖写入,请自行管理完整数据
|
||||
* @return 返回结果
|
||||
* 参考:
|
||||
* result.result = {
|
||||
* code: number, // 200成功,其他都是失败
|
||||
* msg: string, // 如果失败,这里是失败原因等信息
|
||||
* data: {
|
||||
* errMsg: "document.update:ok", // 数据库返回结果
|
||||
* stats: {
|
||||
* updated: number, // 更新了几条数据(正常是1)
|
||||
* }
|
||||
* }
|
||||
* 如果这个泛型令你报错(一般是因为你删了wx.api.d.ts导致),请使用以下签名:
|
||||
* save(gameData: any): Promise<{resoult:CloudReturnType}>
|
||||
* 或者你是个“不拘小节”的老哥,可以用以下简洁版签名(参考上方的数据结构例子使用即可)
|
||||
* login():Promise<any>
|
||||
*/
|
||||
public static async save(gameData: any): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
results: any[]
|
||||
errMsg: string,
|
||||
status:{
|
||||
updated: number
|
||||
}
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
@@ -597,284 +81,4 @@ export class WxCloudApi{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 库存管理接口 (items, tals, equips) ====================
|
||||
|
||||
/**
|
||||
* @en Get inventory
|
||||
* @zh 获取指定类型的所有库存数据
|
||||
* @param type 库存类型 ('items', 'tals', 'equips')
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<Items | Tals | Equips>>>
|
||||
*/
|
||||
public static async getInventory(type: InventoryType): Promise<CloudCallFunctionResult<CloudReturnType<Items | Tals | Equips>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "inventory_get",
|
||||
type: type
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Get inventory item
|
||||
* @zh 获取指定物品的数量
|
||||
* @param type 库存类型
|
||||
* @param itemId 物品ID
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{item_id: number, count: number}>>>
|
||||
*/
|
||||
public static async getInventoryItem(type: InventoryType, itemId: number): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
item_id: number,
|
||||
count: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "inventory_item_get",
|
||||
type: type,
|
||||
item_id: itemId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Add inventory item
|
||||
* @zh 增加指定物品的数量
|
||||
* @param type 库存类型
|
||||
* @param itemId 物品ID
|
||||
* @param count 添加数量
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{item_id: number, old_count: number, new_count: number, added: number}>>>
|
||||
*/
|
||||
public static async addInventoryItem(type: InventoryType, itemId: number, count: number): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
item_id: number,
|
||||
old_count: number,
|
||||
new_count: number,
|
||||
added: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "inventory_item_add",
|
||||
type: type,
|
||||
item_id: itemId,
|
||||
count: count
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Consume inventory item
|
||||
* @zh 消耗指定数量的物品(会检查是否足够)
|
||||
* @param type 库存类型
|
||||
* @param itemId 物品ID
|
||||
* @param count 消耗数量
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{item_id: number, old_count: number, new_count: number, added: number}>>>
|
||||
*/
|
||||
public static async consumeInventoryItem(type: InventoryType, itemId: number, count: number): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
item_id: number,
|
||||
old_count: number,
|
||||
new_count: number,
|
||||
added: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "inventory_item_consume",
|
||||
type: type,
|
||||
item_id: itemId,
|
||||
count: count
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Set inventory item
|
||||
* @zh 直接设置物品的数量
|
||||
* @param type 库存类型
|
||||
* @param itemId 物品ID
|
||||
* @param count 新的数量
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{item_id: number, old_count: number, new_count: number}>>>
|
||||
*/
|
||||
public static async setInventoryItem(type: InventoryType, itemId: number, count: number): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
item_id: number,
|
||||
old_count: number,
|
||||
new_count: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "inventory_item_set",
|
||||
type: type,
|
||||
item_id: itemId,
|
||||
count: count
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Update inventory
|
||||
* @zh 批量更新多个物品的数量
|
||||
* @param type 库存类型
|
||||
* @param data 更新数据对象
|
||||
* @param merge 是否合并更新(默认true)
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<Items | Tals | Equips>>>
|
||||
*/
|
||||
public static async updateInventory(type: InventoryType, data: Partial<Items | Tals | Equips>, merge: boolean = true): Promise<CloudCallFunctionResult<CloudReturnType<Items | Tals | Equips>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "inventory_update",
|
||||
type: type,
|
||||
data: data,
|
||||
merge: merge
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Reset inventory
|
||||
* @zh 重置指定类型的库存为默认值
|
||||
* @param type 库存类型
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<Items | Tals | Equips>>>
|
||||
*/
|
||||
public static async resetInventory(type: InventoryType): Promise<CloudCallFunctionResult<CloudReturnType<Items | Tals | Equips>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "inventory_reset",
|
||||
type: type
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Get owned items
|
||||
* @zh 获取数量大于0的物品列表
|
||||
* @param type 库存类型
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<{owned_items: Array<{item_id: number, count: number}>, total_types: number}>>>
|
||||
*/
|
||||
public static async getOwnedItems(type: InventoryType): Promise<CloudCallFunctionResult<CloudReturnType<{
|
||||
owned_items: Array<{
|
||||
item_id: number,
|
||||
count: number
|
||||
}>,
|
||||
total_types: number
|
||||
}>>> {
|
||||
return await wx?.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: "inventory_owned",
|
||||
type: type
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 便捷方法:道具操作 ====================
|
||||
|
||||
/**
|
||||
* @en Get items
|
||||
* @zh 获取所有道具数据
|
||||
*/
|
||||
public static async getItems() {
|
||||
return await this.getInventory('items');
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Add item
|
||||
* @zh 添加道具
|
||||
* @param itemId 道具ID
|
||||
* @param count 数量
|
||||
*/
|
||||
public static async addItem(itemId: number, count: number) {
|
||||
return await this.addInventoryItem('items', itemId, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Consume item
|
||||
* @zh 消耗道具
|
||||
* @param itemId 道具ID
|
||||
* @param count 数量
|
||||
*/
|
||||
public static async consumeItem(itemId: number, count: number) {
|
||||
return await this.consumeInventoryItem('items', itemId, count);
|
||||
}
|
||||
|
||||
// ==================== 便捷方法:天赋操作 ====================
|
||||
|
||||
/**
|
||||
* @en Get talents
|
||||
* @zh 获取所有天赋数据
|
||||
*/
|
||||
public static async getTalents() {
|
||||
return await this.getInventory('tals');
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Add talent
|
||||
* @zh 添加天赋点
|
||||
* @param talId 天赋ID
|
||||
* @param count 数量
|
||||
*/
|
||||
public static async addTalent(talId: number, count: number) {
|
||||
return await this.addInventoryItem('tals', talId, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Consume talent
|
||||
* @zh 消耗天赋点
|
||||
* @param talId 天赋ID
|
||||
* @param count 数量
|
||||
*/
|
||||
public static async consumeTalent(talId: number, count: number) {
|
||||
return await this.consumeInventoryItem('tals', talId, count);
|
||||
}
|
||||
|
||||
// ==================== 便捷方法:装备操作 ====================
|
||||
|
||||
/**
|
||||
* @en Get equipments
|
||||
* @zh 获取所有装备数据
|
||||
*/
|
||||
public static async getEquipments() {
|
||||
return await this.getInventory('equips');
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Add equipment
|
||||
* @zh 添加装备
|
||||
* @param equipId 装备ID
|
||||
* @param count 数量
|
||||
*/
|
||||
public static async addEquipment(equipId: number, count: number) {
|
||||
return await this.addInventoryItem('equips', equipId, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Consume equipment
|
||||
* @zh 消耗装备
|
||||
* @param equipId 装备ID
|
||||
* @param count 数量
|
||||
*/
|
||||
public static async consumeEquipment(equipId: number, count: number) {
|
||||
return await this.consumeInventoryItem('equips', equipId, count);
|
||||
}
|
||||
|
||||
// ==================== 其他便捷方法 ====================
|
||||
|
||||
/**
|
||||
* @en Load game data (Legacy compatible)
|
||||
* @zh 加载游戏数据(兼容旧接口)
|
||||
*/
|
||||
public static async load() {
|
||||
return await this.login();
|
||||
}
|
||||
|
||||
/**
|
||||
* @en Get all game data at once
|
||||
* @zh 一次性获取所有游戏数据
|
||||
* @return Promise<CloudCallFunctionResult<CloudReturnType<UserGameData>>>
|
||||
*/
|
||||
public static async getAllGameData(): Promise<CloudCallFunctionResult<CloudReturnType<UserGameData>>> {
|
||||
return await this.login();
|
||||
}
|
||||
}
|
||||
@@ -1,920 +0,0 @@
|
||||
# 游戏云函数 API 文档
|
||||
|
||||
## 📋 概述
|
||||
|
||||
本文档详细说明了游戏云函数的所有可用接口,包括认证、数据管理、英雄系统、库存管理等功能。
|
||||
|
||||
## 🏗️ 项目结构
|
||||
|
||||
```
|
||||
cocos_cloud/
|
||||
├── index.js # 路由入口文件
|
||||
├── user_init_data.js # 用户初始化数据配置
|
||||
├── modules/ # 功能模块目录
|
||||
│ ├── auth.js # 认证模块
|
||||
│ ├── gameData.js # 基础游戏数据模块
|
||||
│ ├── fightHeros.js # 出战英雄模块
|
||||
│ ├── heros.js # 英雄管理模块
|
||||
│ ├── inventory.js # 库存管理模块
|
||||
│ └── response.js # 响应处理模块
|
||||
├── README.md # 项目说明文档
|
||||
└── API.md # API接口文档
|
||||
```
|
||||
|
||||
## 🚀 通用调用格式
|
||||
|
||||
```javascript
|
||||
wx.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: '命令名',
|
||||
// 其他参数...
|
||||
}
|
||||
}).then(res => {
|
||||
console.log('调用结果:', res.result);
|
||||
}).catch(err => {
|
||||
console.error('调用失败:', err);
|
||||
});
|
||||
```
|
||||
|
||||
## 📊 通用响应格式
|
||||
|
||||
```javascript
|
||||
{
|
||||
code: 200, // 状态码 (200=成功, 负数=错误)
|
||||
msg: "Success", // 响应消息
|
||||
data: { /* 返回数据 */ }, // 具体数据
|
||||
timestamp: 1234567890, // 时间戳
|
||||
version: "1.0.0", // 数据版本
|
||||
execution_time: 50 // 执行时间(ms)
|
||||
}
|
||||
```
|
||||
|
||||
## 🔐 认证相关接口
|
||||
|
||||
### 1. 用户登录
|
||||
获取用户完整信息和游戏数据。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{ cmd: 'login' }
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
user_id: "用户ID",
|
||||
openid: "微信OpenID",
|
||||
regist_time: 1234567890,
|
||||
data: { /* 基础游戏数据 */ },
|
||||
fight_heros: { /* 出战英雄配置 */ },
|
||||
heros: { /* 英雄属性数据 */ },
|
||||
items: { /* 道具数据 */ },
|
||||
tals: { /* 天赋数据 */ },
|
||||
equips: { /* 装备数据 */ },
|
||||
data_version: "1.0.0",
|
||||
last_save_time: 1234567890
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 获取用户信息
|
||||
获取用户基本信息(不包含游戏数据)。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{ cmd: 'user_info' }
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
user_id: "用户ID",
|
||||
openid: "微信OpenID",
|
||||
regist_time: 1234567890,
|
||||
init_time: 1234567890,
|
||||
data_version: "1.0.0",
|
||||
last_save_time: 1234567890
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 检查版本信息
|
||||
检查用户数据版本兼容性。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{ cmd: 'version' }
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
user_version: "1.0.0",
|
||||
current_version: "1.1.0",
|
||||
compatibility: {
|
||||
compatible: true,
|
||||
needsUpgrade: true,
|
||||
message: "Minor version update available"
|
||||
},
|
||||
init_time: 1234567890,
|
||||
regist_time: 1234567890,
|
||||
last_save_time: 1234567890
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 强制升级数据
|
||||
手动触发用户数据结构升级。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{ cmd: 'upgrade' }
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
old_version: "1.0.0",
|
||||
new_version: "1.1.0",
|
||||
upgrade_time: 1234567890,
|
||||
// ... 升级后的完整数据
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎮 基础游戏数据接口
|
||||
|
||||
### 1. 获取游戏数据
|
||||
获取用户的基础游戏数据(金币、钻石、经验等)。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{ cmd: 'data_get' }
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
score: 0,
|
||||
mission: 1,
|
||||
gold: 100,
|
||||
diamond: 100,
|
||||
meat: 0,
|
||||
exp: 0,
|
||||
// ... 更多字段
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 更新游戏数据
|
||||
批量更新基础游戏数据。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'data_update',
|
||||
data: {
|
||||
gold: 1000,
|
||||
diamond: 200,
|
||||
exp: 500
|
||||
},
|
||||
merge: true // 可选,默认true(合并更新)
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
// 更新后的完整数据
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 增加指定字段
|
||||
增加某个字段的数值。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'data_add',
|
||||
field: 'gold',
|
||||
amount: 100
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
field: 'gold',
|
||||
old_value: 1000,
|
||||
new_value: 1100,
|
||||
change: 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 消耗指定字段
|
||||
消耗某个字段的数值(会检查是否足够)。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'data_spend',
|
||||
field: 'gold',
|
||||
amount: 50
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
field: 'gold',
|
||||
old_value: 1100,
|
||||
new_value: 1050,
|
||||
change: -50
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 设置指定字段
|
||||
直接设置某个字段的值。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'data_set',
|
||||
field: 'mission',
|
||||
value: 5
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
field: 'mission',
|
||||
old_value: 1,
|
||||
new_value: 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 重置游戏数据
|
||||
重置基础游戏数据为默认值。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{ cmd: 'data_reset' }
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
// 重置后的默认数据
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ⚔️ 出战英雄接口
|
||||
|
||||
### 1. 获取出战英雄配置
|
||||
获取当前的出战英雄配置。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{ cmd: 'fight_heros_get' }
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
0: 5001, // 位置0: 英雄5001
|
||||
1: 5005, // 位置1: 英雄5005
|
||||
2: 0, // 位置2: 空
|
||||
3: 0, // 位置3: 空
|
||||
4: 0 // 位置4: 空
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 设置单个出战英雄
|
||||
设置指定位置的出战英雄。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'fight_hero_set',
|
||||
position: 2,
|
||||
hero_id: 5007
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
position: 2,
|
||||
old_hero_id: 0,
|
||||
new_hero_id: 5007
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 批量更新出战英雄
|
||||
批量更新多个位置的出战英雄。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'fight_heros_update',
|
||||
fight_heros: {
|
||||
0: 5001,
|
||||
1: 5005,
|
||||
2: 5007
|
||||
}
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
// 更新后的完整出战配置
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 获取激活的出战英雄
|
||||
获取当前出战的英雄列表(不包含空位)。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{ cmd: 'fight_heros_active' }
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
active_heros: [
|
||||
{
|
||||
position: 0,
|
||||
hero_id: 5001,
|
||||
hero_data: { /* 英雄详细数据 */ }
|
||||
},
|
||||
{
|
||||
position: 1,
|
||||
hero_id: 5005,
|
||||
hero_data: { /* 英雄详细数据 */ }
|
||||
}
|
||||
],
|
||||
total_count: 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 交换出战英雄位置
|
||||
交换两个位置的英雄。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'fight_heros_swap',
|
||||
position1: 0,
|
||||
position2: 2
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
position1: 0,
|
||||
position2: 2,
|
||||
hero1_moved_to: 5007,
|
||||
hero2_moved_to: 5001
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 重置出战英雄
|
||||
重置出战英雄配置为默认值。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{ cmd: 'fight_heros_reset' }
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
// 重置后的默认配置
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🦸 英雄管理接口
|
||||
|
||||
### 1. 获取所有英雄
|
||||
获取用户拥有的所有英雄数据。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{ cmd: 'heros_get' }
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
5001: { uuid: 5001, lv: 10, exp: 500, star: 2, power: 150 },
|
||||
5005: { uuid: 5005, lv: 8, exp: 300, star: 1, power: 120 },
|
||||
5007: { uuid: 5007, lv: 1, exp: 0, star: 1, power: 90 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 获取单个英雄
|
||||
获取指定英雄的详细数据。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'hero_get',
|
||||
hero_id: 5001
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
uuid: 5001,
|
||||
lv: 10,
|
||||
exp: 500,
|
||||
star: 2,
|
||||
power: 150
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 添加新英雄
|
||||
添加新英雄到用户库存。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'hero_add',
|
||||
hero_id: 5008,
|
||||
hero_data: { // 可选,不提供则使用默认数据
|
||||
lv: 1,
|
||||
exp: 0,
|
||||
star: 1,
|
||||
power: 110
|
||||
}
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
uuid: 5008,
|
||||
lv: 1,
|
||||
exp: 0,
|
||||
star: 1,
|
||||
power: 110
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 更新英雄属性
|
||||
批量更新英雄的多个属性。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'hero_update',
|
||||
hero_id: 5001,
|
||||
update_data: {
|
||||
lv: 15,
|
||||
exp: 800,
|
||||
star: 3
|
||||
}
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
old_data: { /* 更新前的数据 */ },
|
||||
new_data: { /* 更新后的数据 */ }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 设置英雄单个属性
|
||||
设置英雄的单个属性值。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'hero_property_set',
|
||||
hero_id: 5001,
|
||||
property: 'lv',
|
||||
value: 20
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
hero_id: 5001,
|
||||
property: 'lv',
|
||||
old_value: 15,
|
||||
new_value: 20
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 英雄升级
|
||||
英雄升级指定级数。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'hero_levelup',
|
||||
hero_id: 5001,
|
||||
levels: 3 // 可选,默认1级
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
hero_id: 5001,
|
||||
property: 'lv',
|
||||
old_value: 20,
|
||||
new_value: 23
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 删除英雄
|
||||
删除指定英雄(会检查是否在出战阵容中)。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'hero_delete',
|
||||
hero_id: 5008
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
// 被删除的英雄数据
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8. 获取拥有的英雄ID列表
|
||||
获取用户拥有的所有英雄ID。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{ cmd: 'heros_owned' }
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
hero_ids: [5001, 5005, 5007],
|
||||
total_count: 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎒 库存管理接口
|
||||
|
||||
库存管理接口支持三种类型的数据:
|
||||
- `items`: 道具
|
||||
- `tals`: 天赋
|
||||
- `equips`: 装备
|
||||
|
||||
### 1. 获取库存数据
|
||||
获取指定类型的所有库存数据。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'inventory_get',
|
||||
type: 'items' // 'items', 'tals', 'equips'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
1001: 5, // 道具1001: 5个
|
||||
1002: 3, // 道具1002: 3个
|
||||
1003: 0, // 道具1003: 0个
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 获取单个物品
|
||||
获取指定物品的数量。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'inventory_item_get',
|
||||
type: 'items',
|
||||
item_id: 1001
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
item_id: 1001,
|
||||
count: 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 添加物品
|
||||
增加指定物品的数量。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'inventory_item_add',
|
||||
type: 'items',
|
||||
item_id: 1001,
|
||||
count: 10
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
item_id: 1001,
|
||||
old_count: 5,
|
||||
new_count: 15,
|
||||
added: 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 消耗物品
|
||||
消耗指定数量的物品(会检查是否足够)。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'inventory_item_consume',
|
||||
type: 'items',
|
||||
item_id: 1001,
|
||||
count: 3
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
item_id: 1001,
|
||||
old_count: 15,
|
||||
new_count: 12,
|
||||
added: -3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 设置物品数量
|
||||
直接设置物品的数量。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'inventory_item_set',
|
||||
type: 'items',
|
||||
item_id: 1001,
|
||||
count: 20
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
item_id: 1001,
|
||||
old_count: 12,
|
||||
new_count: 20
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 批量更新库存
|
||||
批量更新多个物品的数量。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'inventory_update',
|
||||
type: 'items',
|
||||
data: {
|
||||
1001: 25,
|
||||
1002: 10,
|
||||
1003: 5
|
||||
},
|
||||
merge: true // 可选,默认true(合并更新)
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
// 更新后的完整库存数据
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 重置库存
|
||||
重置指定类型的库存为默认值。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'inventory_reset',
|
||||
type: 'items'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
// 重置后的默认库存数据
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8. 获取拥有的物品
|
||||
获取数量大于0的物品列表。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'inventory_owned',
|
||||
type: 'items'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
owned_items: [
|
||||
{ item_id: 1001, count: 25 },
|
||||
{ item_id: 1002, count: 10 },
|
||||
{ item_id: 1003, count: 5 }
|
||||
],
|
||||
total_types: 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔄 兼容旧接口
|
||||
|
||||
为了保持向后兼容,保留了一些旧接口:
|
||||
|
||||
### 1. 加载数据 (兼容)
|
||||
等同于 `login` 命令。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{ cmd: 'load' }
|
||||
|
||||
// 响应:与login相同
|
||||
```
|
||||
|
||||
### 2. 保存数据 (兼容)
|
||||
批量保存多种类型的数据。
|
||||
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
cmd: 'save',
|
||||
data: {
|
||||
data: { gold: 1000, diamond: 200 },
|
||||
fight_heros: { 0: 5001, 1: 5005 },
|
||||
heros: { 5001: { lv: 10, exp: 500 } },
|
||||
items: { 1001: 10, 1002: 5 },
|
||||
tals: { 1001: 1 },
|
||||
equips: { 1001: 2 }
|
||||
}
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
code: 200,
|
||||
data: {
|
||||
results: [
|
||||
// 各个模块的保存结果
|
||||
]
|
||||
},
|
||||
msg: "All data saved successfully"
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 错误码说明
|
||||
|
||||
| 错误码 | 说明 | 示例 |
|
||||
|-------|------|------|
|
||||
| 200 | 成功 | 操作成功完成 |
|
||||
| -1 | 操作失败 | 数据库更新失败 |
|
||||
| -2 | 未知命令 | 命令不存在 |
|
||||
| -3 | 参数错误 | 缺少必需参数或参数格式错误 |
|
||||
| -4 | 用户未找到 | 用户不存在或创建失败 |
|
||||
| -5 | 系统错误 | 服务器内部错误 |
|
||||
| -6 | 资源不足 | 金币、道具等资源不够 |
|
||||
| -7 | 资源已存在 | 英雄已存在等 |
|
||||
| -8 | 操作被拒绝 | 英雄正在出战中无法删除等 |
|
||||
|
||||
## 📝 使用示例
|
||||
|
||||
### 完整的游戏流程示例
|
||||
|
||||
```javascript
|
||||
// 1. 用户登录
|
||||
wx.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: { cmd: 'login' }
|
||||
}).then(res => {
|
||||
console.log('用户登录成功:', res.result.data);
|
||||
|
||||
// 2. 增加金币
|
||||
return wx.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: 'data_add',
|
||||
field: 'gold',
|
||||
amount: 100
|
||||
}
|
||||
});
|
||||
}).then(res => {
|
||||
console.log('金币增加成功:', res.result.data);
|
||||
|
||||
// 3. 添加新英雄
|
||||
return wx.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: 'hero_add',
|
||||
hero_id: 5008
|
||||
}
|
||||
});
|
||||
}).then(res => {
|
||||
console.log('英雄添加成功:', res.result.data);
|
||||
|
||||
// 4. 设置出战英雄
|
||||
return wx.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: 'fight_hero_set',
|
||||
position: 2,
|
||||
hero_id: 5008
|
||||
}
|
||||
});
|
||||
}).then(res => {
|
||||
console.log('出战英雄设置成功:', res.result.data);
|
||||
}).catch(err => {
|
||||
console.error('操作失败:', err);
|
||||
});
|
||||
```
|
||||
|
||||
## 🔧 开发调试
|
||||
|
||||
### 1. 启用调试日志
|
||||
在开发环境中,云函数会输出详细的调试日志:
|
||||
|
||||
```javascript
|
||||
// 请求日志
|
||||
[data_add] Request from oxxx: { field: 'gold', amount: 100 }
|
||||
|
||||
// 响应日志
|
||||
[data_add] Response (45ms): 200 gold updated successfully
|
||||
```
|
||||
|
||||
### 2. 性能监控
|
||||
每个响应都包含 `execution_time` 字段,显示接口执行时间。
|
||||
|
||||
### 3. 版本管理
|
||||
使用 `version` 命令检查数据版本兼容性,确保客户端和服务端数据结构一致。
|
||||
|
||||
---
|
||||
|
||||
**版本**: 1.0.0
|
||||
**更新时间**: 2024年
|
||||
**维护者**: 游戏开发团队
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,270 +0,0 @@
|
||||
# 微信云函数游戏数据管理系统
|
||||
|
||||
## 📁 文件结构
|
||||
|
||||
```
|
||||
cocos_cloud/
|
||||
├── index.js # 主云函数文件
|
||||
├── user_init_data.js # 新用户初始化数据配置
|
||||
└── README.md # 说明文档
|
||||
```
|
||||
|
||||
## 🎮 功能特性
|
||||
|
||||
### 1. 数据结构管理
|
||||
- **平级数据存储**: 所有游戏数据字段与用户基本信息平级存储
|
||||
- **版本控制**: 支持数据结构版本管理和自动升级
|
||||
- **数据验证**: 完整的数据结构和类型验证
|
||||
- **默认值管理**: 集中管理新用户初始化数据
|
||||
|
||||
### 2. 支持的命令
|
||||
|
||||
| 命令 | 功能 | 说明 |
|
||||
|------|------|------|
|
||||
| `login` | 用户登录 | 返回完整的用户和游戏数据 |
|
||||
| `load` | 加载游戏数据 | 获取用户的所有游戏数据 |
|
||||
| `save` | 保存游戏数据 | 支持增量更新,自动合并数据 |
|
||||
| `reset` | 重置游戏数据 | 恢复为默认初始值 |
|
||||
| `backup` | 创建数据备份 | 在独立集合中创建备份记录 |
|
||||
| `version` | 查看版本信息 | 检查数据版本兼容性 |
|
||||
| `upgrade` | 强制升级数据 | 手动触发数据结构升级 |
|
||||
|
||||
## 📊 数据结构
|
||||
|
||||
### 用户数据库结构 (cocos_users 集合)
|
||||
```javascript
|
||||
{
|
||||
_id: "用户ID",
|
||||
_openid: "微信OpenID",
|
||||
regist_time: "注册时间戳",
|
||||
init_time: "初始化时间戳",
|
||||
last_save_time: "最后保存时间",
|
||||
data_version: "数据版本号",
|
||||
|
||||
// 游戏数据字段(与基本信息平级)
|
||||
data: {
|
||||
score: 0, // 游戏分数
|
||||
mission: 1, // 当前关卡
|
||||
gold: 100, // 金币
|
||||
diamond: 100, // 钻石
|
||||
meat: 0, // 肉类资源
|
||||
exp: 0, // 升级经验
|
||||
ghstone: 0, // 绿色英雄石
|
||||
bhstone: 0, // 蓝色英雄石
|
||||
phlestone: 0, // 紫色英雄石
|
||||
rhstone: 0, // 红色英雄石
|
||||
herocard: 0, // 英雄卡
|
||||
ckey: 0, // 铜钥匙
|
||||
skey: 0, // 银钥匙
|
||||
gkey: 0 // 金钥匙
|
||||
},
|
||||
fight_heros: {
|
||||
0: 5001, // 出战位置1
|
||||
1: 5005, // 出战位置2
|
||||
2: 0, // 出战位置3(空)
|
||||
3: 0, // 出战位置4(空)
|
||||
4: 0 // 出战位置5(空)
|
||||
},
|
||||
heros: {
|
||||
5001: { uuid: 5001, lv: 1, exp: 0, star: 1, power: 100 },
|
||||
5005: { uuid: 5005, lv: 1, exp: 0, star: 1, power: 120 },
|
||||
5007: { uuid: 5007, lv: 1, exp: 0, star: 1, power: 90 }
|
||||
},
|
||||
items: {
|
||||
1001: 0, // 生命药水
|
||||
1002: 0, // 魔法药水
|
||||
1003: 0, // 力量药水
|
||||
// ... 更多道具
|
||||
},
|
||||
tals: {
|
||||
1001: 0, // 攻击强化
|
||||
1002: 0, // 防御强化
|
||||
1003: 0, // 生命强化
|
||||
// ... 更多天赋
|
||||
},
|
||||
equips: {
|
||||
1001: 0, // 武器
|
||||
1002: 0, // 头盔
|
||||
1003: 0, // 胸甲
|
||||
// ... 更多装备
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 备份数据库结构 (game_backups 集合)
|
||||
```javascript
|
||||
{
|
||||
user_id: "用户ID",
|
||||
openid: "微信OpenID",
|
||||
data: { /* 基础游戏数据 */ },
|
||||
fight_heros: { /* 出战英雄配置 */ },
|
||||
heros: { /* 英雄属性数据 */ },
|
||||
items: { /* 道具数据 */ },
|
||||
tals: { /* 天赋数据 */ },
|
||||
equips: { /* 装备数据 */ },
|
||||
backup_time: "备份时间戳",
|
||||
original_save_time: "原始保存时间"
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 使用示例
|
||||
|
||||
### 客户端调用示例
|
||||
|
||||
#### 1. 用户登录
|
||||
```javascript
|
||||
wx.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: { cmd: 'login' }
|
||||
}).then(res => {
|
||||
console.log('登录成功:', res.result);
|
||||
// res.result.data 包含完整的用户和游戏数据
|
||||
});
|
||||
```
|
||||
|
||||
#### 2. 保存游戏数据
|
||||
```javascript
|
||||
wx.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: {
|
||||
cmd: 'save',
|
||||
data: {
|
||||
data: { gold: 1000, diamond: 50 },
|
||||
fight_heros: { 0: 5001, 1: 5005 },
|
||||
heros: { 5001: { lv: 10, exp: 100 } },
|
||||
items: { 1001: 5 }
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### 3. 加载游戏数据
|
||||
```javascript
|
||||
wx.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: { cmd: 'load' }
|
||||
}).then(res => {
|
||||
const gameData = res.result.data;
|
||||
console.log('游戏数据:', gameData);
|
||||
});
|
||||
```
|
||||
|
||||
#### 4. 检查版本信息
|
||||
```javascript
|
||||
wx.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: { cmd: 'version' }
|
||||
}).then(res => {
|
||||
console.log('版本信息:', res.result.data);
|
||||
if (res.result.data.compatibility.needsUpgrade) {
|
||||
console.log('需要升级数据');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### 5. 创建数据备份
|
||||
```javascript
|
||||
wx.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: { cmd: 'backup' }
|
||||
}).then(res => {
|
||||
console.log('备份成功:', res.result.data.backup_id);
|
||||
});
|
||||
```
|
||||
|
||||
## 🔧 配置管理
|
||||
|
||||
### 修改默认数据
|
||||
编辑 `user_init_data.js` 文件中的常量:
|
||||
|
||||
```javascript
|
||||
// 修改默认金币数量
|
||||
const DEFAULT_GAME_DATA = {
|
||||
// ...
|
||||
gold: 200, // 从100改为200
|
||||
// ...
|
||||
};
|
||||
|
||||
// 添加新英雄
|
||||
const DEFAULT_HEROS = {
|
||||
// 现有英雄...
|
||||
5008: { uuid: 5008, lv: 1, exp: 0, star: 1, power: 110 }
|
||||
};
|
||||
```
|
||||
|
||||
### 版本升级
|
||||
当数据结构发生变化时,更新版本号:
|
||||
|
||||
```javascript
|
||||
// 在 user_init_data.js 中
|
||||
const DATA_VERSION = "1.1.0"; // 从1.0.0升级到1.1.0
|
||||
```
|
||||
|
||||
## 📈 版本控制
|
||||
|
||||
### 版本号格式
|
||||
- **MAJOR.MINOR.PATCH** (如: 1.2.3)
|
||||
- **MAJOR**: 重大结构变更,不向后兼容
|
||||
- **MINOR**: 新增字段,向后兼容
|
||||
- **PATCH**: 数值调整,完全兼容
|
||||
|
||||
### 自动升级机制
|
||||
- 用户登录时自动检查版本兼容性
|
||||
- 如需升级,自动合并新的默认数据
|
||||
- 保留用户的现有数据,只补充缺失字段
|
||||
|
||||
## 🛡️ 错误处理
|
||||
|
||||
### 错误码说明
|
||||
- `200`: 成功
|
||||
- `-1`: 操作失败
|
||||
- `-2`: 未知命令
|
||||
- `-3`: 数据结构无效
|
||||
- `-4`: 用户创建/获取失败
|
||||
- `-5`: 系统错误
|
||||
|
||||
### 日志记录
|
||||
- 新用户创建日志
|
||||
- 数据版本升级日志
|
||||
- 错误操作日志
|
||||
- 性能监控日志
|
||||
|
||||
## 🔍 调试和监控
|
||||
|
||||
### 查看用户数据版本
|
||||
```javascript
|
||||
wx.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: { cmd: 'version' }
|
||||
});
|
||||
```
|
||||
|
||||
### 强制升级用户数据
|
||||
```javascript
|
||||
wx.cloud.callFunction({
|
||||
name: 'cocos_cloud',
|
||||
data: { cmd: 'upgrade' }
|
||||
});
|
||||
```
|
||||
|
||||
## 📝 注意事项
|
||||
|
||||
1. **数据备份**: 重要操作前建议创建备份
|
||||
2. **版本兼容**: 升级数据结构时注意向后兼容性
|
||||
3. **性能优化**: 大量数据操作时注意性能影响
|
||||
4. **安全验证**: 所有输入数据都经过严格验证
|
||||
5. **错误处理**: 完善的错误处理和日志记录
|
||||
|
||||
## 🚀 部署说明
|
||||
|
||||
1. 将整个 `cocos_cloud` 文件夹上传到微信云开发
|
||||
2. 在微信开发者工具中部署云函数
|
||||
3. 确保数据库权限配置正确
|
||||
4. 测试各项功能是否正常工作
|
||||
|
||||
---
|
||||
|
||||
**版本**: 1.0.0
|
||||
**更新时间**: 2024年
|
||||
**维护者**: 游戏开发团队
|
||||
|
||||
@@ -1,371 +1,80 @@
|
||||
// 云函数路由入口文件
|
||||
// 云函数入口文件
|
||||
const cloud = require('wx-server-sdk');
|
||||
|
||||
// 导入各个模块
|
||||
const authModule = require('./modules/auth');
|
||||
const gameDataModule = require('./modules/gameData');
|
||||
const fightHerosModule = require('./modules/fightHeros');
|
||||
const herosModule = require('./modules/heros');
|
||||
const inventoryModule = require('./modules/inventory');
|
||||
const itemsModule = require('./modules/items');
|
||||
const talsModule = require('./modules/tals');
|
||||
const equipsModule = require('./modules/equips');
|
||||
const responseModule = require('./modules/response');
|
||||
|
||||
const user_db_name = "cocos_users";
|
||||
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }); // 使用当前云环境
|
||||
|
||||
// 云函数入口函数
|
||||
exports.main = async (event, context) => {
|
||||
const startTime = Date.now();
|
||||
let cmd = event.cmd;
|
||||
if (cmd == null) {
|
||||
return {
|
||||
code: -1,
|
||||
msg: "no cmd!"
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
// 验证命令参数
|
||||
const validation = responseModule.validateRequiredParams(event, ['cmd']);
|
||||
if (validation) {
|
||||
return validation;
|
||||
}
|
||||
|
||||
const { cmd, ...params } = event;
|
||||
const wxContext = cloud.getWXContext();
|
||||
const db = cloud.database({
|
||||
env: cloud.DYNAMIC_CURRENT_ENV,
|
||||
throwOnNotFound: false
|
||||
});
|
||||
const _ = db.command;
|
||||
|
||||
console.log(`[${cmd}] Request from ${wxContext.OPENID}:`, params);
|
||||
if (cmd === "login") {
|
||||
let user = await getOrCreaterUser(db, wxContext.OPENID);
|
||||
return {
|
||||
code: 200,
|
||||
data: user,
|
||||
};
|
||||
} else if (cmd === "save") {
|
||||
let data = event.data;
|
||||
let user = await getOrCreaterUser(db, wxContext.OPENID);
|
||||
let saveDataRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
game_data: _.set(data)
|
||||
}
|
||||
});
|
||||
|
||||
// 路由分发
|
||||
let result;
|
||||
switch (cmd) {
|
||||
// ==================== 认证相关 ====================
|
||||
case 'login':
|
||||
result = await authModule.login(db, wxContext);
|
||||
break;
|
||||
|
||||
case 'user_info':
|
||||
result = await authModule.getUserInfo(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
case 'version':
|
||||
result = await authModule.checkVersion(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
case 'upgrade':
|
||||
result = await authModule.upgradeUserData(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
// ==================== 基础游戏数据 ====================
|
||||
case 'data_get':
|
||||
result = await gameDataModule.getData(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
case 'data_update':
|
||||
const merge = params.merge !== false; // 默认合并
|
||||
result = await gameDataModule.updateData(db, wxContext.OPENID, params.data, merge);
|
||||
break;
|
||||
|
||||
case 'data_add':
|
||||
const fieldValidation = responseModule.validateRequiredParams(params, ['field', 'amount']);
|
||||
if (fieldValidation) return fieldValidation;
|
||||
result = await gameDataModule.addDataField(db, wxContext.OPENID, params.field, params.amount);
|
||||
break;
|
||||
|
||||
case 'data_spend':
|
||||
const spendValidation = responseModule.validateRequiredParams(params, ['field', 'amount']);
|
||||
if (spendValidation) return spendValidation;
|
||||
result = await gameDataModule.spendDataField(db, wxContext.OPENID, params.field, params.amount);
|
||||
break;
|
||||
|
||||
case 'data_reset':
|
||||
result = await gameDataModule.resetData(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
// ==================== 出战英雄 ====================
|
||||
case 'fight_heros_get':
|
||||
result = await fightHerosModule.getFightHeros(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
case 'fight_hero_set':
|
||||
const heroSetValidation = responseModule.validateRequiredParams(params, ['position', 'hero_id']);
|
||||
if (heroSetValidation) return heroSetValidation;
|
||||
result = await fightHerosModule.setFightHero(db, wxContext.OPENID, params.position, params.hero_id);
|
||||
break;
|
||||
|
||||
case 'fight_heros_update':
|
||||
const herosUpdateValidation = responseModule.validateRequiredParams(params, ['fight_heros']);
|
||||
if (herosUpdateValidation) return herosUpdateValidation;
|
||||
result = await fightHerosModule.updateFightHeros(db, wxContext.OPENID, params.fight_heros);
|
||||
break;
|
||||
|
||||
case 'fight_heros_active':
|
||||
result = await fightHerosModule.getActiveFightHeros(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
case 'fight_heros_swap':
|
||||
const swapValidation = responseModule.validateRequiredParams(params, ['position1', 'position2']);
|
||||
if (swapValidation) return swapValidation;
|
||||
result = await fightHerosModule.swapFightHeros(db, wxContext.OPENID, params.position1, params.position2);
|
||||
break;
|
||||
|
||||
case 'fight_heros_reset':
|
||||
result = await fightHerosModule.resetFightHeros(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
// ==================== 英雄管理 ====================
|
||||
case 'heros_get':
|
||||
result = await herosModule.getHeros(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
case 'hero_get':
|
||||
const heroGetValidation = responseModule.validateRequiredParams(params, ['hero_id']);
|
||||
if (heroGetValidation) return heroGetValidation;
|
||||
result = await herosModule.getHero(db, wxContext.OPENID, params.hero_id);
|
||||
break;
|
||||
|
||||
case 'hero_add':
|
||||
const heroAddValidation = responseModule.validateRequiredParams(params, ['hero_id']);
|
||||
if (heroAddValidation) return heroAddValidation;
|
||||
result = await herosModule.addHero(db, wxContext.OPENID, params.hero_id, params.hero_data);
|
||||
break;
|
||||
|
||||
case 'hero_update':
|
||||
const heroUpdateValidation = responseModule.validateRequiredParams(params, ['hero_id', 'update_data']);
|
||||
if (heroUpdateValidation) return heroUpdateValidation;
|
||||
result = await herosModule.updateHero(db, wxContext.OPENID, params.hero_id, params.update_data);
|
||||
break;
|
||||
|
||||
case 'hero_property_set':
|
||||
const propValidation = responseModule.validateRequiredParams(params, ['hero_id', 'property', 'value']);
|
||||
if (propValidation) return propValidation;
|
||||
result = await herosModule.setHeroProperty(db, wxContext.OPENID, params.hero_id, params.property, params.value);
|
||||
break;
|
||||
|
||||
case 'hero_levelup':
|
||||
const levelValidation = responseModule.validateRequiredParams(params, ['hero_id']);
|
||||
if (levelValidation) return levelValidation;
|
||||
result = await herosModule.levelUpHero(db, wxContext.OPENID, params.hero_id, params.levels);
|
||||
break;
|
||||
|
||||
case 'hero_delete':
|
||||
const deleteValidation = responseModule.validateRequiredParams(params, ['hero_id']);
|
||||
if (deleteValidation) return deleteValidation;
|
||||
result = await herosModule.deleteHero(db, wxContext.OPENID, params.hero_id);
|
||||
break;
|
||||
|
||||
case 'heros_owned':
|
||||
result = await herosModule.getOwnedHeroIds(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
// ==================== 库存管理 (通用接口) ====================
|
||||
case 'inventory_get':
|
||||
const invGetValidation = responseModule.validateRequiredParams(params, ['type']);
|
||||
if (invGetValidation) return invGetValidation;
|
||||
result = await inventoryModule.getInventory(db, wxContext.OPENID, params.type);
|
||||
break;
|
||||
|
||||
case 'inventory_item_get':
|
||||
const itemGetValidation = responseModule.validateRequiredParams(params, ['type', 'item_id']);
|
||||
if (itemGetValidation) return itemGetValidation;
|
||||
result = await inventoryModule.getInventoryItem(db, wxContext.OPENID, params.type, params.item_id);
|
||||
break;
|
||||
|
||||
case 'inventory_item_add':
|
||||
const itemAddValidation = responseModule.validateRequiredParams(params, ['type', 'item_id', 'count']);
|
||||
if (itemAddValidation) return itemAddValidation;
|
||||
result = await inventoryModule.addInventoryItem(db, wxContext.OPENID, params.type, params.item_id, params.count);
|
||||
break;
|
||||
|
||||
case 'inventory_item_consume':
|
||||
const itemConsumeValidation = responseModule.validateRequiredParams(params, ['type', 'item_id', 'count']);
|
||||
if (itemConsumeValidation) return itemConsumeValidation;
|
||||
result = await inventoryModule.consumeInventoryItem(db, wxContext.OPENID, params.type, params.item_id, params.count);
|
||||
break;
|
||||
|
||||
case 'inventory_item_set':
|
||||
const itemSetValidation = responseModule.validateRequiredParams(params, ['type', 'item_id', 'count']);
|
||||
if (itemSetValidation) return itemSetValidation;
|
||||
result = await inventoryModule.setInventoryItem(db, wxContext.OPENID, params.type, params.item_id, params.count);
|
||||
break;
|
||||
|
||||
case 'inventory_update':
|
||||
const invUpdateValidation = responseModule.validateRequiredParams(params, ['type', 'data']);
|
||||
if (invUpdateValidation) return invUpdateValidation;
|
||||
const invMerge = params.merge !== false;
|
||||
result = await inventoryModule.updateInventory(db, wxContext.OPENID, params.type, params.data, invMerge);
|
||||
break;
|
||||
|
||||
case 'inventory_reset':
|
||||
const invResetValidation = responseModule.validateRequiredParams(params, ['type']);
|
||||
if (invResetValidation) return invResetValidation;
|
||||
result = await inventoryModule.resetInventory(db, wxContext.OPENID, params.type);
|
||||
break;
|
||||
|
||||
case 'inventory_owned':
|
||||
const invOwnedValidation = responseModule.validateRequiredParams(params, ['type']);
|
||||
if (invOwnedValidation) return invOwnedValidation;
|
||||
result = await inventoryModule.getOwnedItems(db, wxContext.OPENID, params.type);
|
||||
break;
|
||||
|
||||
// ==================== 物品管理 (items) ====================
|
||||
case 'items_get':
|
||||
result = await itemsModule.getItems(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
case 'item_get':
|
||||
const itemIdValidation = responseModule.validateRequiredParams(params, ['item_id']);
|
||||
if (itemIdValidation) return itemIdValidation;
|
||||
result = await itemsModule.getItem(db, wxContext.OPENID, params.item_id);
|
||||
break;
|
||||
|
||||
case 'item_add':
|
||||
const addItemValidation = responseModule.validateRequiredParams(params, ['item_id', 'count']);
|
||||
if (addItemValidation) return addItemValidation;
|
||||
result = await itemsModule.addItem(db, wxContext.OPENID, params.item_id, params.count);
|
||||
break;
|
||||
|
||||
case 'item_consume':
|
||||
const consumeItemValidation = responseModule.validateRequiredParams(params, ['item_id', 'count']);
|
||||
if (consumeItemValidation) return consumeItemValidation;
|
||||
result = await itemsModule.consumeItem(db, wxContext.OPENID, params.item_id, params.count);
|
||||
break;
|
||||
|
||||
case 'item_set':
|
||||
const setItemValidation = responseModule.validateRequiredParams(params, ['item_id', 'count']);
|
||||
if (setItemValidation) return setItemValidation;
|
||||
result = await itemsModule.setItem(db, wxContext.OPENID, params.item_id, params.count);
|
||||
break;
|
||||
|
||||
case 'items_update':
|
||||
const updateItemsValidation = responseModule.validateRequiredParams(params, ['data']);
|
||||
if (updateItemsValidation) return updateItemsValidation;
|
||||
const itemsMerge = params.merge !== false;
|
||||
result = await itemsModule.updateItems(db, wxContext.OPENID, params.data, itemsMerge);
|
||||
break;
|
||||
|
||||
case 'items_reset':
|
||||
result = await itemsModule.resetItems(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
case 'items_owned':
|
||||
result = await itemsModule.getOwnedItems(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
// ==================== 天赋管理 (tals) ====================
|
||||
case 'tals_get':
|
||||
result = await talsModule.getTals(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
case 'tal_get':
|
||||
const talIdValidation = responseModule.validateRequiredParams(params, ['tal_id']);
|
||||
if (talIdValidation) return talIdValidation;
|
||||
result = await talsModule.getTal(db, wxContext.OPENID, params.tal_id);
|
||||
break;
|
||||
|
||||
case 'tal_add':
|
||||
const addTalValidation = responseModule.validateRequiredParams(params, ['tal_id', 'count']);
|
||||
if (addTalValidation) return addTalValidation;
|
||||
result = await talsModule.addTal(db, wxContext.OPENID, params.tal_id, params.count);
|
||||
break;
|
||||
|
||||
case 'tal_consume':
|
||||
const consumeTalValidation = responseModule.validateRequiredParams(params, ['tal_id', 'count']);
|
||||
if (consumeTalValidation) return consumeTalValidation;
|
||||
result = await talsModule.consumeTal(db, wxContext.OPENID, params.tal_id, params.count);
|
||||
break;
|
||||
|
||||
case 'tal_set':
|
||||
const setTalValidation = responseModule.validateRequiredParams(params, ['tal_id', 'count']);
|
||||
if (setTalValidation) return setTalValidation;
|
||||
result = await talsModule.setTal(db, wxContext.OPENID, params.tal_id, params.count);
|
||||
break;
|
||||
|
||||
case 'tals_update':
|
||||
const updateTalsValidation = responseModule.validateRequiredParams(params, ['data']);
|
||||
if (updateTalsValidation) return updateTalsValidation;
|
||||
const talsMerge = params.merge !== false;
|
||||
result = await talsModule.updateTals(db, wxContext.OPENID, params.data, talsMerge);
|
||||
break;
|
||||
|
||||
case 'tals_reset':
|
||||
result = await talsModule.resetTals(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
case 'tals_owned':
|
||||
result = await talsModule.getOwnedTals(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
// ==================== 装备管理 (equips) ====================
|
||||
case 'equips_get':
|
||||
result = await equipsModule.getEquips(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
case 'equip_get':
|
||||
const equipIdValidation = responseModule.validateRequiredParams(params, ['equip_id']);
|
||||
if (equipIdValidation) return equipIdValidation;
|
||||
result = await equipsModule.getEquip(db, wxContext.OPENID, params.equip_id);
|
||||
break;
|
||||
|
||||
case 'equip_add':
|
||||
const addEquipValidation = responseModule.validateRequiredParams(params, ['equip_id', 'count']);
|
||||
if (addEquipValidation) return addEquipValidation;
|
||||
result = await equipsModule.addEquip(db, wxContext.OPENID, params.equip_id, params.count);
|
||||
break;
|
||||
|
||||
case 'equip_consume':
|
||||
const consumeEquipValidation = responseModule.validateRequiredParams(params, ['equip_id', 'count']);
|
||||
if (consumeEquipValidation) return consumeEquipValidation;
|
||||
result = await equipsModule.consumeEquip(db, wxContext.OPENID, params.equip_id, params.count);
|
||||
break;
|
||||
|
||||
case 'equip_set':
|
||||
const setEquipValidation = responseModule.validateRequiredParams(params, ['equip_id', 'count']);
|
||||
if (setEquipValidation) return setEquipValidation;
|
||||
result = await equipsModule.setEquip(db, wxContext.OPENID, params.equip_id, params.count);
|
||||
break;
|
||||
|
||||
case 'equips_update':
|
||||
const updateEquipsValidation = responseModule.validateRequiredParams(params, ['data']);
|
||||
if (updateEquipsValidation) return updateEquipsValidation;
|
||||
const equipsMerge = params.merge !== false;
|
||||
result = await equipsModule.updateEquips(db, wxContext.OPENID, params.data, equipsMerge);
|
||||
break;
|
||||
|
||||
case 'equips_reset':
|
||||
result = await equipsModule.resetEquips(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
case 'equips_owned':
|
||||
result = await equipsModule.getOwnedEquips(db, wxContext.OPENID);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
const availableCommands = [
|
||||
'login', 'user_info', 'version', 'upgrade',
|
||||
'data_get', 'data_update', 'data_add', 'data_spend', 'data_set', 'data_reset',
|
||||
'fight_heros_get', 'fight_hero_set', 'fight_heros_update', 'fight_heros_active', 'fight_heros_swap', 'fight_heros_reset',
|
||||
'heros_get', 'hero_get', 'hero_add', 'hero_update', 'hero_property_set', 'hero_levelup', 'hero_delete', 'heros_owned',
|
||||
'inventory_get', 'inventory_item_get', 'inventory_item_add', 'inventory_item_consume', 'inventory_item_set', 'inventory_update', 'inventory_reset', 'inventory_owned',
|
||||
'items_get', 'item_get', 'item_add', 'item_consume', 'item_set', 'items_update', 'items_reset', 'items_owned',
|
||||
'tals_get', 'tal_get', 'tal_add', 'tal_consume', 'tal_set', 'tals_update', 'tals_reset', 'tals_owned',
|
||||
'equips_get', 'equip_get', 'equip_add', 'equip_consume', 'equip_set', 'equips_update', 'equips_reset', 'equips_owned',
|
||||
'load', 'save'
|
||||
];
|
||||
result = responseModule.unknownCommand(cmd, availableCommands);
|
||||
break;
|
||||
console.log("Save data:", saveDataRes, data);
|
||||
if (saveDataRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: saveDataRes
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `Save fail, ${JSON.stringify(saveDataRes)}`
|
||||
};
|
||||
}
|
||||
|
||||
// 添加执行时间
|
||||
const executionTime = Date.now() - startTime;
|
||||
if (result && typeof result === 'object') {
|
||||
result.execution_time = executionTime;
|
||||
}
|
||||
|
||||
console.log(`[${cmd}] Response (${executionTime}ms):`, result.code, result.msg);
|
||||
return result;
|
||||
|
||||
} catch (error) {
|
||||
console.error("Cloud function error:", error);
|
||||
return responseModule.systemError("Cloud function execution failed", error);
|
||||
}
|
||||
|
||||
return {
|
||||
code: -2,
|
||||
msg: `Unknow cmd: ${event?.cmd}`,
|
||||
};
|
||||
};
|
||||
|
||||
async function getOrCreaterUser(db, openid) {
|
||||
try {
|
||||
let res = await db.collection(user_db_name).where({ _openid: openid }).get();
|
||||
let userData = null;
|
||||
if (res == null || res.data == null || res.data.length <= 0) {
|
||||
userData = {
|
||||
_openid: openid,
|
||||
regist_time: Date.now(),
|
||||
};
|
||||
let addResult = await db.collection(user_db_name).add({
|
||||
data: userData
|
||||
});
|
||||
userData._id = addResult._id;
|
||||
} else {
|
||||
userData = res.data[0];
|
||||
}
|
||||
return userData;
|
||||
} catch (err) {
|
||||
console.error(`Get or create user err`, err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,283 +0,0 @@
|
||||
// 登录认证模块
|
||||
const {
|
||||
getNewUserInitData,
|
||||
mergeUserDataWithDefaults,
|
||||
checkDataVersionCompatibility
|
||||
} = require('../user_init_data');
|
||||
|
||||
const user_db_name = "cocos_users";
|
||||
|
||||
/**
|
||||
* 用户登录处理
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {Object} wxContext 微信上下文
|
||||
* @returns {Object} 登录结果
|
||||
*/
|
||||
async function login(db, wxContext) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, wxContext.OPENID);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "获取或创建用户失败"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
user_id: user._id,
|
||||
openid: user._openid,
|
||||
regist_time: user.regist_time,
|
||||
data: user.data,
|
||||
fight_heros: user.fight_heros,
|
||||
heros: user.heros,
|
||||
items: user.items,
|
||||
tals: user.tals,
|
||||
equips: user.equips,
|
||||
data_version: user.data_version,
|
||||
last_save_time: user.last_save_time || null
|
||||
},
|
||||
msg: "登录成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("登录错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `登录错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取或创建用户
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 用户数据
|
||||
*/
|
||||
async function getOrCreaterUser(db, openid) {
|
||||
try {
|
||||
let res = await db.collection(user_db_name).where({ _openid: openid }).get();
|
||||
let userData = null;
|
||||
|
||||
if (res == null || res.data == null || res.data.length <= 0) {
|
||||
// 创建新用户时使用初始化数据配置
|
||||
let initData = getNewUserInitData();
|
||||
userData = {
|
||||
_openid: openid,
|
||||
regist_time: Date.now(),
|
||||
data: initData.data,
|
||||
fight_heros: initData.fight_heros,
|
||||
heros: initData.heros,
|
||||
items: initData.items,
|
||||
tals: initData.tals,
|
||||
equips: initData.equips,
|
||||
data_version: initData.data_version,
|
||||
init_time: initData.init_time
|
||||
};
|
||||
|
||||
let addResult = await db.collection(user_db_name).add({
|
||||
data: userData
|
||||
});
|
||||
userData._id = addResult._id;
|
||||
|
||||
// console.log(`新用户已创建: ${openid}, 版本: ${initData.data_version}`);
|
||||
} else {
|
||||
userData = res.data[0];
|
||||
|
||||
// 检查数据版本兼容性
|
||||
const versionCheck = checkDataVersionCompatibility(userData.data_version);
|
||||
// console.log(`用户 ${openid} 数据版本检查:`, versionCheck);
|
||||
|
||||
if (versionCheck.needsUpgrade) {
|
||||
// 使用新的数据管理系统合并和升级数据
|
||||
const upgradedData = mergeUserDataWithDefaults({
|
||||
data: userData.data,
|
||||
fight_heros: userData.fight_heros,
|
||||
heros: userData.heros,
|
||||
items: userData.items,
|
||||
tals: userData.tals,
|
||||
equips: userData.equips,
|
||||
data_version: userData.data_version
|
||||
});
|
||||
|
||||
// 更新用户数据
|
||||
userData.data = upgradedData.data;
|
||||
userData.fight_heros = upgradedData.fight_heros;
|
||||
userData.heros = upgradedData.heros;
|
||||
userData.items = upgradedData.items;
|
||||
userData.tals = upgradedData.tals;
|
||||
userData.equips = upgradedData.equips;
|
||||
userData.data_version = upgradedData.data_version;
|
||||
|
||||
// console.log(`用户 ${openid} 数据已升级到版本: ${upgradedData.data_version}`);
|
||||
}
|
||||
}
|
||||
|
||||
return userData;
|
||||
} catch (err) {
|
||||
console.error(`获取或创建用户错误`, err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户基本信息
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 用户基本信息
|
||||
*/
|
||||
async function getUserInfo(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
user_id: user._id,
|
||||
openid: user._openid,
|
||||
regist_time: user.regist_time,
|
||||
init_time: user.init_time,
|
||||
data_version: user.data_version,
|
||||
last_save_time: user.last_save_time
|
||||
},
|
||||
msg: "用户信息获取成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("获取用户信息错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取用户信息错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户数据版本
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 版本检查结果
|
||||
*/
|
||||
async function checkVersion(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
const versionCheck = checkDataVersionCompatibility(user.data_version);
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
user_version: user.data_version || "unknown",
|
||||
current_version: require('../user_init_data').DATA_VERSION,
|
||||
compatibility: versionCheck,
|
||||
init_time: user.init_time,
|
||||
regist_time: user.regist_time,
|
||||
last_save_time: user.last_save_time
|
||||
},
|
||||
msg: "版本信息获取成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("检查版本错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `检查版本错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制升级用户数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 升级结果
|
||||
*/
|
||||
async function upgradeUserData(db, openid) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
// 强制升级用户数据
|
||||
const upgradedData = mergeUserDataWithDefaults({
|
||||
data: user.data,
|
||||
fight_heros: user.fight_heros,
|
||||
heros: user.heros,
|
||||
items: user.items,
|
||||
tals: user.tals,
|
||||
equips: user.equips,
|
||||
data_version: user.data_version
|
||||
});
|
||||
|
||||
let upgradeDataRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
data: _.set(upgradedData.data),
|
||||
fight_heros: _.set(upgradedData.fight_heros),
|
||||
heros: _.set(upgradedData.heros),
|
||||
items: _.set(upgradedData.items),
|
||||
tals: _.set(upgradedData.tals),
|
||||
equips: _.set(upgradedData.equips),
|
||||
data_version: _.set(upgradedData.data_version),
|
||||
last_save_time: _.set(Date.now()),
|
||||
upgrade_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (upgradeDataRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
old_version: user.data_version || "unknown",
|
||||
new_version: upgradedData.data_version,
|
||||
upgrade_time: Date.now(),
|
||||
data: upgradedData.data,
|
||||
fight_heros: upgradedData.fight_heros,
|
||||
heros: upgradedData.heros,
|
||||
items: upgradedData.items,
|
||||
tals: upgradedData.tals,
|
||||
equips: upgradedData.equips
|
||||
},
|
||||
msg: "数据升级成功完成"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `升级失败, ${JSON.stringify(upgradeDataRes)}`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("升级用户数据错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `升级错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
login,
|
||||
getOrCreaterUser,
|
||||
getUserInfo,
|
||||
checkVersion,
|
||||
upgradeUserData
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,370 +0,0 @@
|
||||
// 出战英雄操作模块
|
||||
const { getOrCreaterUser } = require('./auth');
|
||||
|
||||
const user_db_name = "cocos_users";
|
||||
|
||||
/**
|
||||
* 获取出战英雄配置
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getFightHeros(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: user.fight_heros,
|
||||
msg: "出战英雄获取成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("获取出战英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取出战英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置出战英雄
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} position 出战位置 (0-4)
|
||||
* @param {number} heroId 英雄ID,0表示移除
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function setFightHero(db, openid, position, heroId) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证位置参数
|
||||
if (position < 0 || position > 4) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "无效的位置,必须是0-4"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证英雄ID
|
||||
if (typeof heroId !== 'number' || heroId < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "无效的英雄ID"
|
||||
};
|
||||
}
|
||||
|
||||
// 如果不是移除操作,检查英雄是否存在
|
||||
if (heroId > 0 && !user.heros[heroId]) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: "未拥有该英雄"
|
||||
};
|
||||
}
|
||||
|
||||
const oldHeroId = user.fight_heros[position];
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`fight_heros.${position}`]: _.set(heroId),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
position: position,
|
||||
old_hero_id: oldHeroId,
|
||||
new_hero_id: heroId
|
||||
},
|
||||
msg: `出战英雄位置 ${position} 更新成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `设置出战英雄失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("设置出战英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `设置出战英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置出战英雄
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {Object} fightHeros 出战英雄配置对象
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function updateFightHeros(db, openid, fightHeros) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证数据格式
|
||||
if (!fightHeros || typeof fightHeros !== 'object') {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "无效的出战英雄数据格式"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证每个位置和英雄ID
|
||||
for (const pos in fightHeros) {
|
||||
const position = parseInt(pos);
|
||||
const heroId = fightHeros[pos];
|
||||
|
||||
if (isNaN(position) || position < 0 || position > 4) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `无效的位置: ${pos}`
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof heroId !== 'number' || heroId < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `位置 ${pos} 的英雄ID无效: ${heroId}`
|
||||
};
|
||||
}
|
||||
|
||||
// 如果不是移除操作,检查英雄是否存在
|
||||
if (heroId > 0 && !user.heros[heroId]) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: `位置 ${pos} 未拥有英雄 ${heroId}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const newFightHeros = { ...user.fight_heros, ...fightHeros };
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
fight_heros: _.set(newFightHeros),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: newFightHeros,
|
||||
msg: "出战英雄更新成功"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `更新出战英雄失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("更新出战英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `更新出战英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前出战英雄列表(不包含空位)
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getActiveFightHeros(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
const activeHeros = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const heroId = user.fight_heros[i];
|
||||
if (heroId && heroId > 0) {
|
||||
activeHeros.push({
|
||||
position: i,
|
||||
hero_id: heroId,
|
||||
hero_data: user.heros[heroId] || null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
active_heros: activeHeros,
|
||||
total_count: activeHeros.length
|
||||
},
|
||||
msg: "获取活跃出战英雄成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("获取活跃出战英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取活跃出战英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 交换两个出战位置的英雄
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} position1 位置1 (0-4)
|
||||
* @param {number} position2 位置2 (0-4)
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function swapFightHeros(db, openid, position1, position2) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证位置参数
|
||||
if (position1 < 0 || position1 > 4 || position2 < 0 || position2 > 4) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "无效的位置,必须是0-4"
|
||||
};
|
||||
}
|
||||
|
||||
if (position1 === position2) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "不能交换相同位置"
|
||||
};
|
||||
}
|
||||
|
||||
const hero1 = user.fight_heros[position1];
|
||||
const hero2 = user.fight_heros[position2];
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`fight_heros.${position1}`]: _.set(hero2),
|
||||
[`fight_heros.${position2}`]: _.set(hero1),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
position1: position1,
|
||||
position2: position2,
|
||||
hero1_moved_to: hero1,
|
||||
hero2_moved_to: hero2
|
||||
},
|
||||
msg: `出战英雄交换成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `交换出战英雄失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("交换出战英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `交换出战英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置出战英雄配置
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function resetFightHeros(db, openid) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
const { getNewUserInitData } = require('../user_init_data');
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
const defaultData = getNewUserInitData();
|
||||
|
||||
let resetRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
fight_heros: _.set(defaultData.fight_heros),
|
||||
last_save_time: _.set(Date.now()),
|
||||
reset_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (resetRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: defaultData.fight_heros,
|
||||
msg: "出战英雄重置成功"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `重置失败, ${JSON.stringify(resetRes)}`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("重置出战英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `重置出战英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getFightHeros,
|
||||
setFightHero,
|
||||
updateFightHeros,
|
||||
getActiveFightHeros,
|
||||
swapFightHeros,
|
||||
resetFightHeros
|
||||
};
|
||||
|
||||
@@ -1,386 +0,0 @@
|
||||
// 基础游戏数据操作模块 (data字段)
|
||||
const { getOrCreaterUser } = require('./auth');
|
||||
const { validateDataStructure, mergeUserDataWithDefaults } = require('../user_init_data');
|
||||
|
||||
const user_db_name = "cocos_users";
|
||||
|
||||
/**
|
||||
* 获取基础游戏数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getData(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "用户未找到"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: user.data,
|
||||
msg: "游戏数据获取成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("获取游戏数据错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取游戏数据错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新基础游戏数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {Object} updateData 要更新的数据
|
||||
* @param {boolean} merge 是否合并更新(默认true)
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function updateData(db, openid, updateData, merge = true) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "用户未找到"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证数据格式
|
||||
if (!updateData || typeof updateData !== 'object') {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "无效的更新数据格式"
|
||||
};
|
||||
}
|
||||
|
||||
let newData;
|
||||
if (merge) {
|
||||
// 合并更新
|
||||
newData = { ...user.data, ...updateData };
|
||||
} else {
|
||||
// 完全替换
|
||||
newData = updateData;
|
||||
}
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
data: _.set(newData),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: newData,
|
||||
msg: "游戏数据更新成功"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `更新失败, ${JSON.stringify(updateRes)}`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("更新游戏数据错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `更新游戏数据错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加指定字段的数值
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} field 字段名
|
||||
* @param {number} amount 增加的数量
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function addDataField(db, openid, field, amount) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "用户未找到"
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof amount !== 'number') {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "数量必须是数字"
|
||||
};
|
||||
}
|
||||
|
||||
const currentValue = user.data[field] || 0;
|
||||
const newValue = Math.max(0, currentValue + amount);
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`data.${field}`]: _.set(newValue),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
field: field,
|
||||
old_value: currentValue,
|
||||
new_value: newValue,
|
||||
change: amount
|
||||
},
|
||||
msg: `${field} 更新成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `更新 ${field} 失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`增加 ${field} 错误:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `增加 ${field} 错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 消耗指定字段的数值
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string|Object[]} field 字段名或字段对象数组 [{field: 字段名, amount: 数量}]
|
||||
* @param {number} [amount] 消耗的数量 (当field为字符串时使用)
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function spendDataField(db, openid, field, amount) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "用户未找到"
|
||||
};
|
||||
}
|
||||
|
||||
// 处理单个字段的情况
|
||||
if (typeof field === 'string') {
|
||||
if (typeof amount !== 'number' || amount < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "数量必须是正数"
|
||||
};
|
||||
}
|
||||
|
||||
const currentValue = user.data[field] || 0;
|
||||
if (currentValue < amount) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: `${field} 不足, 当前: ${currentValue}, 需要: ${amount}`
|
||||
};
|
||||
}
|
||||
|
||||
return await addDataField(db, openid, field, -amount);
|
||||
}
|
||||
|
||||
// 处理多个字段的情况
|
||||
if (Array.isArray(field)) {
|
||||
const fieldsToSpend = field;
|
||||
|
||||
// 验证参数格式
|
||||
for (const item of fieldsToSpend) {
|
||||
if (!item.field || typeof item.amount !== 'number' || item.amount < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "字段参数格式错误,需要 {field, amount} 结构,且amount必须是正数"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 检查所有资源是否足够
|
||||
for (const item of fieldsToSpend) {
|
||||
const currentValue = user.data[item.field] || 0;
|
||||
if (currentValue < item.amount) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: `${item.field} 不足, 当前: ${currentValue}, 需要: ${item.amount}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 所有资源都足够,开始扣除
|
||||
const updateData = {};
|
||||
const changes = [];
|
||||
|
||||
for (const item of fieldsToSpend) {
|
||||
const currentValue = user.data[item.field] || 0;
|
||||
const newValue = Math.max(0, currentValue - item.amount);
|
||||
updateData[`data.${item.field}`] = _.set(newValue);
|
||||
|
||||
changes.push({
|
||||
field: item.field,
|
||||
old_value: currentValue,
|
||||
new_value: newValue,
|
||||
change: -item.amount
|
||||
});
|
||||
}
|
||||
|
||||
// 更新数据库
|
||||
updateData['last_save_time'] = _.set(Date.now());
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: updateData
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: changes,
|
||||
msg: "资源消耗成功"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: "资源消耗失败"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: -3,
|
||||
msg: "参数格式错误"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`消耗资源错误:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `消耗资源错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置指定字段的数值
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} field 字段名
|
||||
* @param {any} value 新的值
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function setDataField(db, openid, field, value) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "用户未找到"
|
||||
};
|
||||
}
|
||||
|
||||
const oldValue = user.data[field];
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`data.${field}`]: _.set(value),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
field: field,
|
||||
old_value: oldValue,
|
||||
new_value: value
|
||||
},
|
||||
msg: `${field} 设置成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `设置 ${field} 失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`设置 ${field} 错误:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `设置 ${field} 错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置基础游戏数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function resetData(db, openid) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
const { getNewUserInitData } = require('../user_init_data');
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "用户未找到"
|
||||
};
|
||||
}
|
||||
|
||||
const defaultData = getNewUserInitData();
|
||||
|
||||
let resetRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
data: _.set(defaultData.data),
|
||||
last_save_time: _.set(Date.now()),
|
||||
reset_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (resetRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: defaultData.data,
|
||||
msg: "游戏数据重置成功"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `重置失败, ${JSON.stringify(resetRes)}`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("重置游戏数据错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `重置游戏数据错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getData,
|
||||
updateData,
|
||||
addDataField,
|
||||
spendDataField,
|
||||
setDataField,
|
||||
resetData
|
||||
};
|
||||
@@ -1,440 +0,0 @@
|
||||
// 英雄数据操作模块
|
||||
const { getOrCreaterUser } = require('./auth');
|
||||
|
||||
const user_db_name = "cocos_users";
|
||||
|
||||
/**
|
||||
* 获取所有英雄数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getHeros(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: user.heros,
|
||||
msg: "获取英雄列表成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("获取英雄列表错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取英雄列表错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个英雄数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} heroId 英雄ID
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getHero(db, openid, heroId) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
const hero = user.heros[heroId];
|
||||
if (!hero) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: "未找到英雄"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: hero,
|
||||
msg: "获取英雄成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("获取英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加新英雄
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} heroId 英雄ID
|
||||
* @param {Object} heroData 英雄数据(可选)
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function addHero(db, openid, heroId, heroData = null) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 检查英雄是否已存在
|
||||
if (user.heros[heroId]) {
|
||||
return {
|
||||
code: -7,
|
||||
msg: "英雄已存在"
|
||||
};
|
||||
}
|
||||
|
||||
// 使用提供的数据或默认数据
|
||||
const newHero = heroData || {
|
||||
uuid: heroId,
|
||||
lv: 1,
|
||||
exp: 0,
|
||||
star: 1,
|
||||
power: 100
|
||||
};
|
||||
|
||||
// 确保uuid字段正确
|
||||
newHero.uuid = heroId;
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`heros.${heroId}`]: _.set(newHero),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: newHero,
|
||||
msg: `英雄 ${heroId} 添加成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `添加英雄失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("添加英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `添加英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新英雄属性
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} heroId 英雄ID
|
||||
* @param {Object} updateData 要更新的属性
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function updateHero(db, openid, heroId, updateData) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 检查英雄是否存在
|
||||
if (!user.heros[heroId]) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: "未找到英雄"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证更新数据
|
||||
if (!updateData || typeof updateData !== 'object') {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "无效的更新数据格式"
|
||||
};
|
||||
}
|
||||
|
||||
const currentHero = user.heros[heroId];
|
||||
const newHero = { ...currentHero, ...updateData };
|
||||
|
||||
// 确保uuid字段不被修改
|
||||
newHero.uuid = heroId;
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`heros.${heroId}`]: _.set(newHero),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
old_data: currentHero,
|
||||
new_data: newHero
|
||||
},
|
||||
msg: `英雄 ${heroId} 更新成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `更新英雄失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("更新英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `更新英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置英雄属性
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} heroId 英雄ID
|
||||
* @param {string} property 属性名
|
||||
* @param {any} value 属性值
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function setHeroProperty(db, openid, heroId, property, value) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 检查英雄是否存在
|
||||
if (!user.heros[heroId]) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: "未找到英雄"
|
||||
};
|
||||
}
|
||||
|
||||
// 防止修改uuid
|
||||
if (property === 'uuid') {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "不可修改英雄UUID"
|
||||
};
|
||||
}
|
||||
|
||||
const oldValue = user.heros[heroId][property];
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`heros.${heroId}.${property}`]: _.set(value),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
hero_id: heroId,
|
||||
property: property,
|
||||
old_value: oldValue,
|
||||
new_value: value
|
||||
},
|
||||
msg: `英雄 ${heroId} 属性 ${property} 更新成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `设置英雄属性失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("设置英雄属性错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `设置英雄属性错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 英雄升级
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} heroId 英雄ID
|
||||
* @param {number} levels 升级级数(默认1级)
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function levelUpHero(db, openid, heroId,levels = 1) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 检查英雄是否存在
|
||||
if (!user.heros[heroId]) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: "未找到英雄"
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof levels !== 'number' || levels < 1) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "等级必须为正数"
|
||||
};
|
||||
}
|
||||
const currentLevel = user.heros[heroId].lv || 1;
|
||||
const newLevel = currentLevel + levels;
|
||||
return await setHeroProperty(db, openid, heroId, 'lv', newLevel);
|
||||
} catch (error) {
|
||||
console.error("英雄升级错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `英雄升级错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除英雄
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} heroId 英雄ID
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function deleteHero(db, openid, heroId) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 检查英雄是否存在
|
||||
if (!user.heros[heroId]) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: "未找到英雄"
|
||||
};
|
||||
}
|
||||
|
||||
// 检查英雄是否在出战阵容中
|
||||
for (let pos = 0; pos < 5; pos++) {
|
||||
if (user.fight_heros[pos] === heroId) {
|
||||
return {
|
||||
code: -8,
|
||||
msg: `英雄位于出战位置 ${pos},请先从出战阵容移除`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const deletedHero = user.heros[heroId];
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`heros.${heroId}`]: _.remove(),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: deletedHero,
|
||||
msg: `英雄 ${heroId} 删除成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `删除英雄失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("删除英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `删除英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已拥有的英雄ID列表
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getOwnedHeroIds(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
const heroIds = Object.keys(user.heros).map(Number);
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
hero_ids: heroIds,
|
||||
total_count: heroIds.length
|
||||
},
|
||||
msg: "获取已拥有英雄ID成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("获取已拥有英雄ID错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取已拥有英雄ID错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getHeros,
|
||||
getHero,
|
||||
addHero,
|
||||
updateHero,
|
||||
setHeroProperty,
|
||||
levelUpHero,
|
||||
deleteHero,
|
||||
getOwnedHeroIds
|
||||
};
|
||||
|
||||
@@ -1,501 +0,0 @@
|
||||
// 通用库存操作模块 (items, tals, equips)
|
||||
const { getOrCreaterUser } = require('./auth');
|
||||
|
||||
const user_db_name = "cocos_users";
|
||||
|
||||
// 支持的数据类型
|
||||
const SUPPORTED_TYPES = ['items', 'tals', 'equips'];
|
||||
|
||||
/**
|
||||
* 验证数据类型
|
||||
* @param {string} dataType 数据类型
|
||||
* @returns {boolean} 是否有效
|
||||
*/
|
||||
function validateDataType(dataType) {
|
||||
return SUPPORTED_TYPES.includes(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取库存数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型 ('items', 'tals', 'equips')
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getInventory(db, openid, dataType) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `无效的数据类型: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: user[dataType],
|
||||
msg: `${dataType}获取成功`
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`获取${dataType}错误:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取${dataType}错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个物品数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @param {number} itemId 物品ID
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getInventoryItem(db, openid, dataType, itemId) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `无效的数据类型: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
const itemCount = user[dataType][itemId];
|
||||
if (itemCount === undefined) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: `${dataType.slice(0, -1)} ${itemId} 未找到`
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
item_id: itemId,
|
||||
count: itemCount
|
||||
},
|
||||
msg: `${dataType.slice(0, -1)} ${itemId} 获取成功`
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`获取${dataType}物品错误:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取${dataType}物品错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加物品
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @param {number} itemId 物品ID
|
||||
* @param {number} count 添加数量
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function addInventoryItem(db, openid, dataType, itemId, count) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `无效的数据类型: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof count !== 'number' || count < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "数量必须是非负数"
|
||||
};
|
||||
}
|
||||
|
||||
const currentCount = user[dataType][itemId] || 0;
|
||||
const newCount = currentCount + count;
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`${dataType}.${itemId}`]: _.set(newCount),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
item_id: itemId,
|
||||
old_count: currentCount,
|
||||
new_count: newCount,
|
||||
added: count
|
||||
},
|
||||
msg: `${dataType.slice(0, -1)} ${itemId} 添加成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `添加 ${dataType.slice(0, -1)} 失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`添加${dataType}物品错误:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `添加${dataType}物品错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 消耗物品
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @param {number} itemId 物品ID
|
||||
* @param {number} count 消耗数量
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function consumeInventoryItem(db, openid, dataType, itemId, count) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `无效的数据类型: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof count !== 'number' || count < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "数量必须是非负数"
|
||||
};
|
||||
}
|
||||
|
||||
const currentCount = user[dataType][itemId] || 0;
|
||||
if (currentCount < count) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: `${dataType.slice(0, -1)} ${itemId}不足, 当前: ${currentCount}, 需要: ${count}`
|
||||
};
|
||||
}
|
||||
|
||||
return await addInventoryItem(db, openid, dataType, itemId, -count);
|
||||
} catch (error) {
|
||||
console.error(`消耗${dataType}物品错误:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `消耗${dataType}物品错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置物品数量
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @param {number} itemId 物品ID
|
||||
* @param {number} count 新的数量
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function setInventoryItem(db, openid, dataType, itemId, count) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `无效的数据类型: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof count !== 'number' || count < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "数量必须是非负数"
|
||||
};
|
||||
}
|
||||
|
||||
const oldCount = user[dataType][itemId] || 0;
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`${dataType}.${itemId}`]: _.set(count),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
item_id: itemId,
|
||||
old_count: oldCount,
|
||||
new_count: count
|
||||
},
|
||||
msg: `${dataType.slice(0, -1)} ${itemId} 设置成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `设置 ${dataType.slice(0, -1)} 失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`设置${dataType}物品错误:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `设置${dataType}物品错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新库存
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @param {Object} updateData 更新数据对象
|
||||
* @param {boolean} merge 是否合并更新(默认true)
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function updateInventory(db, openid, dataType, updateData, merge = true) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid data type: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证更新数据
|
||||
if (!updateData || typeof updateData !== 'object') {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "Invalid update data format"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证所有值都是非负数
|
||||
for (const itemId in updateData) {
|
||||
const count = updateData[itemId];
|
||||
if (typeof count !== 'number' || count < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid count for item ${itemId}: ${count}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let newData;
|
||||
if (merge) {
|
||||
// 合并更新
|
||||
newData = { ...user[dataType], ...updateData };
|
||||
} else {
|
||||
// 完全替换
|
||||
newData = updateData;
|
||||
}
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[dataType]: _.set(newData),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: newData,
|
||||
msg: `${dataType} updated successfully`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `Update ${dataType} fail`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Update ${dataType} error:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Update ${dataType} error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置库存数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function resetInventory(db, openid, dataType) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid data type: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
const _ = db.command;
|
||||
const { getNewUserInitData } = require('../user_init_data');
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
const defaultData = getNewUserInitData();
|
||||
|
||||
let resetRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[dataType]: _.set(defaultData[dataType]),
|
||||
last_save_time: _.set(Date.now()),
|
||||
reset_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (resetRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: defaultData[dataType],
|
||||
msg: `${dataType} reset successfully`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `Reset ${dataType} fail`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Reset ${dataType} error:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Reset ${dataType} error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取拥有的物品列表(数量大于0的)
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getOwnedItems(db, openid, dataType) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid data type: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
const ownedItems = [];
|
||||
for (const itemId in user[dataType]) {
|
||||
const count = user[dataType][itemId];
|
||||
if (count > 0) {
|
||||
ownedItems.push({
|
||||
item_id: parseInt(itemId),
|
||||
count: count
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
owned_items: ownedItems,
|
||||
total_types: ownedItems.length
|
||||
},
|
||||
msg: `Owned ${dataType} retrieved successfully`
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Get owned ${dataType} error:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Get owned ${dataType} error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getInventory,
|
||||
getInventoryItem,
|
||||
addInventoryItem,
|
||||
consumeInventoryItem,
|
||||
setInventoryItem,
|
||||
updateInventory,
|
||||
resetInventory,
|
||||
getOwnedItems,
|
||||
SUPPORTED_TYPES
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,274 +0,0 @@
|
||||
// 统一响应处理模块
|
||||
const { DATA_VERSION } = require('../user_init_data');
|
||||
|
||||
/**
|
||||
* 成功响应
|
||||
* @param {any} data 返回数据
|
||||
* @param {string} message 成功消息
|
||||
* @param {Object} extra 额外信息
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function success(data = null, message = "成功", extra = {}) {
|
||||
return {
|
||||
code: 200,
|
||||
data: data,
|
||||
msg: message,
|
||||
timestamp: Date.now(),
|
||||
version: DATA_VERSION,
|
||||
...extra
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误响应
|
||||
* @param {number} code 错误码
|
||||
* @param {string} message 错误消息
|
||||
* @param {any} data 错误相关数据
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function error(code, message, data = null) {
|
||||
return {
|
||||
code: code,
|
||||
msg: message,
|
||||
data: data,
|
||||
timestamp: Date.now(),
|
||||
version: DATA_VERSION
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数错误响应
|
||||
* @param {string} message 错误消息
|
||||
* @param {any} data 错误相关数据
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function badRequest(message = "请求参数错误", data = null) {
|
||||
return error(-3, message, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户未找到响应
|
||||
* @param {string} message 错误消息
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function userNotFound(message = "未找到用户") {
|
||||
return error(-4, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统错误响应
|
||||
* @param {string} message 错误消息
|
||||
* @param {Error} err 错误对象
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function systemError(message = "系统错误", err = null) {
|
||||
const errorData = err ? {
|
||||
error_message: err.message,
|
||||
error_stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
|
||||
} : null;
|
||||
|
||||
return error(-5, message, errorData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源不足响应
|
||||
* @param {string} resource 资源名称
|
||||
* @param {number} current 当前数量
|
||||
* @param {number} required 需要数量
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function insufficientResource(resource, current = 0, required = 0) {
|
||||
return error(-6, `${resource}不足`, {
|
||||
resource: resource,
|
||||
current: current,
|
||||
required: required,
|
||||
shortage: required - current
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源已存在响应
|
||||
* @param {string} resource 资源名称
|
||||
* @param {any} identifier 资源标识
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function resourceExists(resource, identifier = null) {
|
||||
return error(-7, `${resource}已存在`, {
|
||||
resource: resource,
|
||||
identifier: identifier
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作被拒绝响应
|
||||
* @param {string} reason 拒绝原因
|
||||
* @param {any} data 相关数据
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function operationDenied(reason, data = null) {
|
||||
return error(-8, `操作被拒绝: ${reason}`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 未知命令响应
|
||||
* @param {string} command 命令名
|
||||
* @param {Array} availableCommands 可用命令列表
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function unknownCommand(command, availableCommands = []) {
|
||||
return error(-2, `未知命令: ${command}`, {
|
||||
command: command,
|
||||
available_commands: availableCommands
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 包装异步操作,统一错误处理
|
||||
* @param {Function} operation 异步操作函数
|
||||
* @param {string} operationName 操作名称
|
||||
* @returns {Function} 包装后的函数
|
||||
*/
|
||||
function wrapAsync(operation, operationName = "Operation") {
|
||||
return async (...args) => {
|
||||
try {
|
||||
const result = await operation(...args);
|
||||
|
||||
// 如果操作返回的是错误格式,直接返回
|
||||
if (result && typeof result === 'object' && result.code !== undefined) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// 如果是成功结果,包装为成功响应
|
||||
return success(result, `${operationName}成功完成`);
|
||||
} catch (error) {
|
||||
console.error(`${operationName}错误:`, error);
|
||||
return systemError(`${operationName}失败`, error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证必需参数
|
||||
* @param {Object} params 参数对象
|
||||
* @param {Array} requiredFields 必需字段列表
|
||||
* @returns {Object|null} 如果验证失败返回错误响应,否则返回null
|
||||
*/
|
||||
function validateRequiredParams(params, requiredFields) {
|
||||
if (!params || typeof params !== 'object') {
|
||||
return badRequest("Invalid parameters");
|
||||
}
|
||||
|
||||
const missingFields = [];
|
||||
for (const field of requiredFields) {
|
||||
if (params[field] === undefined || params[field] === null) {
|
||||
missingFields.push(field);
|
||||
}
|
||||
}
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
return badRequest(`Missing required parameters: ${missingFields.join(', ')}`, {
|
||||
missing_fields: missingFields,
|
||||
required_fields: requiredFields
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数值参数
|
||||
* @param {any} value 要验证的值
|
||||
* @param {string} fieldName 字段名
|
||||
* @param {Object} options 验证选项
|
||||
* @returns {Object|null} 如果验证失败返回错误响应,否则返回null
|
||||
*/
|
||||
function validateNumber(value, fieldName, options = {}) {
|
||||
const {
|
||||
min = Number.NEGATIVE_INFINITY,
|
||||
max = Number.POSITIVE_INFINITY,
|
||||
integer = false
|
||||
} = options;
|
||||
|
||||
if (typeof value !== 'number' || isNaN(value)) {
|
||||
return badRequest(`${fieldName} must be a number`);
|
||||
}
|
||||
|
||||
if (integer && !Number.isInteger(value)) {
|
||||
return badRequest(`${fieldName} must be an integer`);
|
||||
}
|
||||
|
||||
if (value < min) {
|
||||
return badRequest(`${fieldName} must be at least ${min}`);
|
||||
}
|
||||
|
||||
if (value > max) {
|
||||
return badRequest(`${fieldName} must be at most ${max}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建分页响应
|
||||
* @param {Array} items 数据项
|
||||
* @param {number} total 总数
|
||||
* @param {number} page 当前页
|
||||
* @param {number} pageSize 页大小
|
||||
* @param {string} message 成功消息
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function paginated(items, total, page, pageSize, message = "Data retrieved successfully") {
|
||||
const totalPages = Math.ceil(total / pageSize);
|
||||
|
||||
return success({
|
||||
items: items,
|
||||
pagination: {
|
||||
current_page: page,
|
||||
page_size: pageSize,
|
||||
total_items: total,
|
||||
total_pages: totalPages,
|
||||
has_next: page < totalPages,
|
||||
has_prev: page > 1
|
||||
}
|
||||
}, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误码常量
|
||||
*/
|
||||
const ERROR_CODES = {
|
||||
SUCCESS: 200,
|
||||
OPERATION_FAILED: -1,
|
||||
UNKNOWN_COMMAND: -2,
|
||||
BAD_REQUEST: -3,
|
||||
USER_NOT_FOUND: -4,
|
||||
SYSTEM_ERROR: -5,
|
||||
INSUFFICIENT_RESOURCE: -6,
|
||||
RESOURCE_EXISTS: -7,
|
||||
OPERATION_DENIED: -8
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
success,
|
||||
error,
|
||||
badRequest,
|
||||
userNotFound,
|
||||
systemError,
|
||||
insufficientResource,
|
||||
resourceExists,
|
||||
operationDenied,
|
||||
unknownCommand,
|
||||
wrapAsync,
|
||||
validateRequiredParams,
|
||||
validateNumber,
|
||||
paginated,
|
||||
ERROR_CODES
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,247 +0,0 @@
|
||||
// 新用户初始化数据配置文件
|
||||
// 用于管理新用户注册时的默认游戏数据
|
||||
|
||||
/**
|
||||
* 数据版本号 - 用于数据结构升级和兼容性管理
|
||||
* 格式: MAJOR.MINOR.PATCH
|
||||
* MAJOR: 重大结构变更,不向后兼容
|
||||
* MINOR: 新增字段,向后兼容
|
||||
* PATCH: 数值调整,完全兼容
|
||||
*/
|
||||
const DATA_VERSION = "1.0.0";
|
||||
|
||||
/**
|
||||
* 基础游戏数据默认值
|
||||
*/
|
||||
const DEFAULT_GAME_DATA = {
|
||||
score: 0, // 游戏分数
|
||||
mission: 1, // 当前关卡
|
||||
gold: 100, // 金币 - 升级主要资源
|
||||
diamond: 100, // 钻石 - 商店购买及双倍奖励资源
|
||||
meat: 0, // 肉类资源
|
||||
exp: 0, // 升级经验
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* 默认出战英雄配置
|
||||
* 位置 0-4 对应 5个出战位置
|
||||
* 0 表示该位置为空
|
||||
*/
|
||||
const DEFAULT_FIGHT_HEROS = {
|
||||
0: 5001, // 第1个位置:默认英雄5001
|
||||
1: 5005, // 第2个位置:默认英雄5005
|
||||
2: 0, // 第3个位置:空
|
||||
3: 0, // 第4个位置:空
|
||||
4: 0 // 第5个位置:空
|
||||
};
|
||||
|
||||
/**
|
||||
* 默认英雄属性数据
|
||||
* 每个英雄包含: uuid(唯一标识), lv(等级), 其他属性可扩展
|
||||
*/
|
||||
const DEFAULT_HEROS = {
|
||||
5001: {
|
||||
uuid: 5001,
|
||||
lv: 1, // 初始等级
|
||||
exp: 0, // 英雄经验
|
||||
star: 1, // 星级
|
||||
power: 100 // 战力
|
||||
},
|
||||
5005: {
|
||||
uuid: 5005,
|
||||
lv: 1,
|
||||
exp: 0,
|
||||
star: 1,
|
||||
power: 120
|
||||
},
|
||||
5007: {
|
||||
uuid: 5007,
|
||||
lv: 1,
|
||||
exp: 0,
|
||||
star: 1,
|
||||
power: 90
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 默认道具数据
|
||||
* ID 1001-1007 对应不同类型的道具
|
||||
*/
|
||||
const DEFAULT_ITEMS = {
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* 默认天赋数据
|
||||
* ID 1001-1007 对应不同的天赋技能
|
||||
*/
|
||||
const DEFAULT_TALS = {
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* 默认装备数据
|
||||
* ID 1001-1005 对应不同部位的装备
|
||||
*/
|
||||
const DEFAULT_EQUIPS = {
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取完整的新用户初始化数据
|
||||
* @returns {Object} 包含所有默认数据的对象
|
||||
*/
|
||||
function getNewUserInitData() {
|
||||
return {
|
||||
data_version: DATA_VERSION,
|
||||
init_time: Date.now(),
|
||||
data: { ...DEFAULT_GAME_DATA },
|
||||
fight_heros: { ...DEFAULT_FIGHT_HEROS },
|
||||
heros: JSON.parse(JSON.stringify(DEFAULT_HEROS)), // 深拷贝避免引用问题
|
||||
items: { ...DEFAULT_ITEMS },
|
||||
tals: { ...DEFAULT_TALS },
|
||||
equips: { ...DEFAULT_EQUIPS }
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取特定类型的默认数据
|
||||
* @param {string} dataType 数据类型: 'data', 'fight_heros', 'heros', 'items', 'tals', 'equips'
|
||||
* @returns {Object} 指定类型的默认数据
|
||||
*/
|
||||
function getDefaultDataByType(dataType) {
|
||||
const dataMap = {
|
||||
data: DEFAULT_GAME_DATA,
|
||||
fight_heros: DEFAULT_FIGHT_HEROS,
|
||||
heros: DEFAULT_HEROS,
|
||||
items: DEFAULT_ITEMS,
|
||||
tals: DEFAULT_TALS,
|
||||
equips: DEFAULT_EQUIPS
|
||||
};
|
||||
|
||||
const defaultData = dataMap[dataType];
|
||||
if (!defaultData) {
|
||||
throw new Error(`Unknown data type: ${dataType}`);
|
||||
}
|
||||
|
||||
// 返回深拷贝以避免修改原始数据
|
||||
return JSON.parse(JSON.stringify(defaultData));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数据版本兼容性
|
||||
* @param {string} userDataVersion 用户数据版本
|
||||
* @returns {Object} 兼容性检查结果
|
||||
*/
|
||||
function checkDataVersionCompatibility(userDataVersion) {
|
||||
if (!userDataVersion) {
|
||||
return {
|
||||
compatible: false,
|
||||
needsUpgrade: true,
|
||||
message: "No version found, needs full upgrade"
|
||||
};
|
||||
}
|
||||
|
||||
const [userMajor, userMinor, userPatch] = userDataVersion.split('.').map(Number);
|
||||
const [currentMajor, currentMinor, currentPatch] = DATA_VERSION.split('.').map(Number);
|
||||
|
||||
if (userMajor < currentMajor) {
|
||||
return {
|
||||
compatible: false,
|
||||
needsUpgrade: true,
|
||||
message: "Major version mismatch, needs full upgrade"
|
||||
};
|
||||
}
|
||||
|
||||
if (userMajor === currentMajor && userMinor < currentMinor) {
|
||||
return {
|
||||
compatible: true,
|
||||
needsUpgrade: true,
|
||||
message: "Minor version update available"
|
||||
};
|
||||
}
|
||||
|
||||
if (userMajor === currentMajor && userMinor === currentMinor && userPatch < currentPatch) {
|
||||
return {
|
||||
compatible: true,
|
||||
needsUpgrade: true,
|
||||
message: "Patch update available"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
compatible: true,
|
||||
needsUpgrade: false,
|
||||
message: "Data version is up to date"
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并用户数据和默认数据
|
||||
* 确保用户数据包含所有必需的字段
|
||||
* @param {Object} userData 用户现有数据
|
||||
* @returns {Object} 合并后的完整数据
|
||||
*/
|
||||
function mergeUserDataWithDefaults(userData) {
|
||||
const defaultData = getNewUserInitData();
|
||||
const mergedData = {
|
||||
data_version: DATA_VERSION,
|
||||
init_time: userData.init_time || Date.now(),
|
||||
data: { ...defaultData.data, ...userData.data },
|
||||
fight_heros: { ...defaultData.fight_heros, ...userData.fight_heros },
|
||||
heros: { ...defaultData.heros, ...userData.heros },
|
||||
items: { ...defaultData.items, ...userData.items },
|
||||
tals: { ...defaultData.tals, ...userData.tals },
|
||||
equips: { ...defaultData.equips, ...userData.equips }
|
||||
};
|
||||
|
||||
return mergedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数据结构完整性
|
||||
* @param {Object} gameData 要验证的游戏数据
|
||||
* @returns {Object} 验证结果
|
||||
*/
|
||||
function validateDataStructure(gameData) {
|
||||
const requiredFields = ['data', 'fight_heros', 'heros', 'items', 'tals', 'equips'];
|
||||
const missingFields = [];
|
||||
|
||||
for (const field of requiredFields) {
|
||||
if (!gameData[field] || typeof gameData[field] !== 'object') {
|
||||
missingFields.push(field);
|
||||
}
|
||||
}
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
return {
|
||||
valid: false,
|
||||
missingFields,
|
||||
message: `Missing or invalid fields: ${missingFields.join(', ')}`
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
message: "Data structure is valid"
|
||||
};
|
||||
}
|
||||
|
||||
// 导出所有功能函数
|
||||
module.exports = {
|
||||
DATA_VERSION,
|
||||
getNewUserInitData,
|
||||
getDefaultDataByType,
|
||||
checkDataVersionCompatibility,
|
||||
mergeUserDataWithDefaults,
|
||||
validateDataStructure,
|
||||
|
||||
// 导出原始数据常量(只读)
|
||||
DEFAULT_GAME_DATA: Object.freeze({ ...DEFAULT_GAME_DATA }),
|
||||
DEFAULT_FIGHT_HEROS: Object.freeze({ ...DEFAULT_FIGHT_HEROS }),
|
||||
DEFAULT_HEROS: Object.freeze(JSON.parse(JSON.stringify(DEFAULT_HEROS))),
|
||||
DEFAULT_ITEMS: Object.freeze({ ...DEFAULT_ITEMS }),
|
||||
DEFAULT_TALS: Object.freeze({ ...DEFAULT_TALS }),
|
||||
DEFAULT_EQUIPS: Object.freeze({ ...DEFAULT_EQUIPS })
|
||||
};
|
||||
Reference in New Issue
Block a user