云环境和本地调试 添加

This commit is contained in:
2025-08-18 17:00:40 +08:00
parent addc61e2a9
commit a824d9a124
155 changed files with 6531 additions and 997 deletions

View File

@@ -0,0 +1,913 @@
# 游戏云函数 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年
**维护者**: 游戏开发团队

View File

@@ -0,0 +1,270 @@
# 微信云函数游戏数据管理系统
## 📁 文件结构
```
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年
**维护者**: 游戏开发团队

View File

@@ -1,80 +1,272 @@
// 云函数入口文件
// 云函数路由入口文件
const cloud = require('wx-server-sdk');
const user_db_name = "cocos_users";
// 导入各个模块
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 responseModule = require('./modules/response');
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }); // 使用当前云环境
// 云函数入口函数
exports.main = async (event, context) => {
let cmd = event.cmd;
if (cmd == null) {
return {
code: -1,
msg: "no cmd!"
};
}
const startTime = Date.now();
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;
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)
}
});
console.log("Save data:", saveDataRes, data);
if (saveDataRes?.stats?.updated >= 1) {
return {
code: 200,
data: saveDataRes
};
console.log(`[${cmd}] Request from ${wxContext.OPENID}:`, params);
// 路由分发
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_set':
const setValidation = responseModule.validateRequiredParams(params, ['field', 'value']);
if (setValidation) return setValidation;
result = await gameDataModule.setDataField(db, wxContext.OPENID, params.field, params.value);
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;
// ==================== 库存管理 (items, tals, equips) ====================
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;
// ==================== 兼容旧接口 ====================
case 'load':
result = await authModule.login(db, wxContext);
break;
case 'save':
// 兼容旧的保存接口
if (params.data) {
const tasks = [];
if (params.data.data) tasks.push(gameDataModule.updateData(db, wxContext.OPENID, params.data.data));
if (params.data.fight_heros) tasks.push(fightHerosModule.updateFightHeros(db, wxContext.OPENID, params.data.fight_heros));
if (params.data.heros) {
// 批量更新英雄
for (const heroId in params.data.heros) {
tasks.push(herosModule.updateHero(db, wxContext.OPENID, parseInt(heroId), params.data.heros[heroId]));
}
}
if (params.data.items) tasks.push(inventoryModule.updateInventory(db, wxContext.OPENID, 'items', params.data.items));
if (params.data.tals) tasks.push(inventoryModule.updateInventory(db, wxContext.OPENID, 'tals', params.data.tals));
if (params.data.equips) tasks.push(inventoryModule.updateInventory(db, wxContext.OPENID, 'equips', params.data.equips));
const results = await Promise.all(tasks);
const hasError = results.some(r => r.code !== 200);
if (hasError) {
result = responseModule.error(-1, "Partial save failed", { results });
} else {
result = responseModule.success({ results }, "All data saved successfully");
}
} else {
return {
code: -1,
msg: `Save fail, ${JSON.stringify(saveDataRes)}`
};
result = responseModule.badRequest("No data to save");
}
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',
'load', 'save'
];
result = responseModule.unknownCommand(cmd, availableCommands);
break;
}
}
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];
// 添加执行时间
const executionTime = Date.now() - startTime;
if (result && typeof result === 'object') {
result.execution_time = executionTime;
}
return userData;
} catch (err) {
console.error(`Get or create user err`, err);
return null;
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);
}
}
};

View File

@@ -0,0 +1,280 @@
// 登录认证模块
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: "Failed to get or create user"
};
}
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: "Login successful"
};
} catch (error) {
console.error("Login error:", error);
return {
code: -5,
msg: `Login error: ${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(`New user created: ${openid}, version: ${initData.data_version}`);
} else {
userData = res.data[0];
// 检查数据版本兼容性
const versionCheck = checkDataVersionCompatibility(userData.data_version);
console.log(`User ${openid} data version check:`, 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(`User ${openid} data upgraded to version: ${upgradedData.data_version}`);
}
}
return userData;
} catch (err) {
console.error(`Get or create user err`, 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: "User not found"
};
}
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: "User info retrieved successfully"
};
} catch (error) {
console.error("Get user info error:", error);
return {
code: -5,
msg: `Get user info error: ${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: "User not found"
};
}
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: "Version information retrieved successfully"
};
} catch (error) {
console.error("Check version error:", error);
return {
code: -5,
msg: `Check version error: ${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: "Data upgrade completed successfully"
};
} else {
return {
code: -1,
msg: `Upgrade fail, ${JSON.stringify(upgradeDataRes)}`
};
}
} catch (error) {
console.error("Upgrade user data error:", error);
return {
code: -5,
msg: `Upgrade error: ${error.message}`
};
}
}
module.exports = {
login,
getOrCreaterUser,
getUserInfo,
checkVersion,
upgradeUserData
};

View File

@@ -0,0 +1,370 @@
// 出战英雄操作模块
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: "User not found"
};
}
return {
code: 200,
data: user.fight_heros,
msg: "Fight heros retrieved successfully"
};
} catch (error) {
console.error("Get fight heros error:", error);
return {
code: -5,
msg: `Get fight heros error: ${error.message}`
};
}
}
/**
* 设置出战英雄
* @param {Object} db 数据库实例
* @param {string} openid 用户openid
* @param {number} position 出战位置 (0-4)
* @param {number} heroId 英雄ID0表示移除
* @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: "User not found"
};
}
// 验证位置参数
if (position < 0 || position > 4) {
return {
code: -3,
msg: "Invalid position, must be 0-4"
};
}
// 验证英雄ID
if (typeof heroId !== 'number' || heroId < 0) {
return {
code: -3,
msg: "Invalid hero ID"
};
}
// 如果不是移除操作,检查英雄是否存在
if (heroId > 0 && !user.heros[heroId]) {
return {
code: -6,
msg: "Hero not owned"
};
}
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: `Fight hero position ${position} updated successfully`
};
} else {
return {
code: -1,
msg: `Set fight hero fail`
};
}
} catch (error) {
console.error("Set fight hero error:", error);
return {
code: -5,
msg: `Set fight hero error: ${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: "User not found"
};
}
// 验证数据格式
if (!fightHeros || typeof fightHeros !== 'object') {
return {
code: -3,
msg: "Invalid fight heros data format"
};
}
// 验证每个位置和英雄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: `Invalid position: ${pos}`
};
}
if (typeof heroId !== 'number' || heroId < 0) {
return {
code: -3,
msg: `Invalid hero ID for position ${pos}: ${heroId}`
};
}
// 如果不是移除操作,检查英雄是否存在
if (heroId > 0 && !user.heros[heroId]) {
return {
code: -6,
msg: `Hero ${heroId} not owned for position ${pos}`
};
}
}
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: "Fight heros updated successfully"
};
} else {
return {
code: -1,
msg: `Update fight heros fail`
};
}
} catch (error) {
console.error("Update fight heros error:", error);
return {
code: -5,
msg: `Update fight heros error: ${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: "User not found"
};
}
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: "Active fight heros retrieved successfully"
};
} catch (error) {
console.error("Get active fight heros error:", error);
return {
code: -5,
msg: `Get active fight heros error: ${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: "User not found"
};
}
// 验证位置参数
if (position1 < 0 || position1 > 4 || position2 < 0 || position2 > 4) {
return {
code: -3,
msg: "Invalid positions, must be 0-4"
};
}
if (position1 === position2) {
return {
code: -3,
msg: "Cannot swap same position"
};
}
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: `Fight heros swapped successfully`
};
} else {
return {
code: -1,
msg: `Swap fight heros fail`
};
}
} catch (error) {
console.error("Swap fight heros error:", error);
return {
code: -5,
msg: `Swap fight heros error: ${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: "User not found"
};
}
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: "Fight heros reset successfully"
};
} else {
return {
code: -1,
msg: `Reset fail, ${JSON.stringify(resetRes)}`
};
}
} catch (error) {
console.error("Reset fight heros error:", error);
return {
code: -5,
msg: `Reset fight heros error: ${error.message}`
};
}
}
module.exports = {
getFightHeros,
setFightHero,
updateFightHeros,
getActiveFightHeros,
swapFightHeros,
resetFightHeros
};

View File

@@ -0,0 +1,315 @@
// 基础游戏数据操作模块 (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} field 字段名
* @param {number} amount 消耗的数量
* @returns {Object} 操作结果
*/
async function spendDataField(db, openid, field, amount) {
try {
let user = await getOrCreaterUser(db, openid);
if (!user) {
return {
code: -4,
msg: "用户未找到"
};
}
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);
} catch (error) {
console.error(`消耗 ${field} 错误:`, error);
return {
code: -5,
msg: `消耗 ${field} 错误: ${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
};

View File

@@ -0,0 +1,456 @@
// 英雄数据操作模块
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, exp,gold,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: "等级必须为正数"
};
}
let exp_result=await spendDataField(db, openid, 'exp', exp);
if(exp_result.code!==200){
return {
code: -1,
msg: `升级失败,经验不足`
};
}
let gold_result=await spendDataField(db, openid, 'gold', gold);
if(gold_result.code!==200){
await addDataField(db, openid, 'exp', exp);
return {
code: -1,
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
};

View File

@@ -0,0 +1,498 @@
// 通用库存操作模块 (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: `Invalid data type: ${dataType}`
};
}
let user = await getOrCreaterUser(db, openid);
if (!user) {
return {
code: -4,
msg: "User not found"
};
}
return {
code: 200,
data: user[dataType],
msg: `${dataType} retrieved successfully`
};
} catch (error) {
console.error(`Get ${dataType} error:`, error);
return {
code: -5,
msg: `Get ${dataType} error: ${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: `Invalid data type: ${dataType}`
};
}
let user = await getOrCreaterUser(db, openid);
if (!user) {
return {
code: -4,
msg: "User not found"
};
}
const itemCount = user[dataType][itemId];
if (itemCount === undefined) {
return {
code: -6,
msg: `${dataType.slice(0, -1)} ${itemId} not found`
};
}
return {
code: 200,
data: {
item_id: itemId,
count: itemCount
},
msg: `${dataType.slice(0, -1)} ${itemId} retrieved successfully`
};
} catch (error) {
console.error(`Get ${dataType} item error:`, error);
return {
code: -5,
msg: `Get ${dataType} item error: ${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: `Invalid data type: ${dataType}`
};
}
const _ = db.command;
let user = await getOrCreaterUser(db, openid);
if (!user) {
return {
code: -4,
msg: "User not found"
};
}
if (typeof count !== 'number' || count < 0) {
return {
code: -3,
msg: "Count must be a non-negative number"
};
}
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} added successfully`
};
} else {
return {
code: -1,
msg: `Add ${dataType.slice(0, -1)} fail`
};
}
} catch (error) {
console.error(`Add ${dataType} item error:`, error);
return {
code: -5,
msg: `Add ${dataType} item error: ${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: `Invalid data type: ${dataType}`
};
}
let user = await getOrCreaterUser(db, openid);
if (!user) {
return {
code: -4,
msg: "User not found"
};
}
if (typeof count !== 'number' || count < 0) {
return {
code: -3,
msg: "Count must be a non-negative number"
};
}
const currentCount = user[dataType][itemId] || 0;
if (currentCount < count) {
return {
code: -6,
msg: `Insufficient ${dataType.slice(0, -1)} ${itemId}, current: ${currentCount}, required: ${count}`
};
}
return await addInventoryItem(db, openid, dataType, itemId, -count);
} catch (error) {
console.error(`Consume ${dataType} item error:`, error);
return {
code: -5,
msg: `Consume ${dataType} item error: ${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: `Invalid data type: ${dataType}`
};
}
const _ = db.command;
let user = await getOrCreaterUser(db, openid);
if (!user) {
return {
code: -4,
msg: "User not found"
};
}
if (typeof count !== 'number' || count < 0) {
return {
code: -3,
msg: "Count must be a non-negative number"
};
}
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} set successfully`
};
} else {
return {
code: -1,
msg: `Set ${dataType.slice(0, -1)} fail`
};
}
} catch (error) {
console.error(`Set ${dataType} item error:`, error);
return {
code: -5,
msg: `Set ${dataType} item error: ${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
};

View File

@@ -0,0 +1,267 @@
// 统一响应处理模块
const { DATA_VERSION } = require('../user_init_data');
/**
* 成功响应
* @param {any} data 返回数据
* @param {string} message 成功消息
* @param {Object} extra 额外信息
* @returns {Object} 响应对象
*/
function success(data = null, message = "Success", 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 = "Bad request", data = null) {
return error(-3, message, data);
}
/**
* 用户未找到响应
* @param {string} message 错误消息
* @returns {Object} 响应对象
*/
function userNotFound(message = "User not found") {
return error(-4, message);
}
/**
* 系统错误响应
* @param {string} message 错误消息
* @param {Error} err 错误对象
* @returns {Object} 响应对象
*/
function systemError(message = "System error", 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, `Insufficient ${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} already exists`, {
resource: resource,
identifier: identifier
});
}
/**
* 操作被拒绝响应
* @param {string} reason 拒绝原因
* @param {any} data 相关数据
* @returns {Object} 响应对象
*/
function operationDenied(reason, data = null) {
return error(-8, `Operation denied: ${reason}`, data);
}
/**
* 未知命令响应
* @param {string} command 命令名
* @param {Array} availableCommands 可用命令列表
* @returns {Object} 响应对象
*/
function unknownCommand(command, availableCommands = []) {
return error(-2, `Unknown command: ${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} completed successfully`);
} catch (error) {
console.error(`${operationName} error:`, error);
return systemError(`${operationName} failed`, 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
};

View File

@@ -0,0 +1,274 @@
// 新用户初始化数据配置文件
// 用于管理新用户注册时的默认游戏数据
/**
* 数据版本号 - 用于数据结构升级和兼容性管理
* 格式: 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, // 升级经验
// 英雄升星石头资源
ghstone: 0, // 绿色英雄石 - 普通英雄升星
bhstone: 0, // 蓝色英雄石 - 稀有英雄升星
phlestone: 0, // 紫色英雄石 - 史诗英雄升星
rhstone: 0, // 红色英雄石 - 传说英雄升星
// 抽卡和解锁资源
herocard: 0, // 英雄卡 - 抽卡凭证
ckey: 0, // 铜钥匙 - 解锁稀有英雄/兑换金币
skey: 0, // 银钥匙 - 解锁史诗英雄/兑换金币
gkey: 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 = {
1001: 0, // 生命药水
1002: 0, // 魔法药水
1003: 0, // 力量药水
1004: 0, // 敏捷药水
1005: 0, // 智力药水
1006: 0, // 复活卷轴
1007: 0 // 传送卷轴
};
/**
* 默认天赋数据
* ID 1001-1007 对应不同的天赋技能
*/
const DEFAULT_TALS = {
1001: 0, // 攻击强化
1002: 0, // 防御强化
1003: 0, // 生命强化
1004: 0, // 速度强化
1005: 0, // 暴击强化
1006: 0, // 经验强化
1007: 0 // 金币强化
};
/**
* 默认装备数据
* ID 1001-1005 对应不同部位的装备
*/
const DEFAULT_EQUIPS = {
1001: 0, // 武器
1002: 0, // 头盔
1003: 0, // 胸甲
1004: 0, // 护腿
1005: 0 // 靴子
};
/**
* 获取完整的新用户初始化数据
* @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 })
};