From 011349132f63e547cfa1e7022daf1d6bb2ca0d57 Mon Sep 17 00:00:00 2001 From: yaoyanwei Date: Tue, 2 Sep 2025 16:58:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BB=BB=E5=8A=A1=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Plugins/steam_api.dll.meta | 27 + Assets/Plugins/steam_api64.dll.meta | 27 + Assets/TcgEngine/Docs.meta | 8 + Assets/TcgEngine/Docs/TaskConfigurations.md | 115 ++++ .../TcgEngine/Docs/TaskConfigurations.md.meta | 7 + Assets/TcgEngine/Docs/TaskSystemAPI.md | 119 ++++ Assets/TcgEngine/Docs/TaskSystemAPI.md.meta | 7 + Assets/TcgEngine/Docs/TaskSystemUserGuide.md | 101 ++++ .../Docs/TaskSystemUserGuide.md.meta | 7 + Assets/TcgEngine/Resources/Tasks.meta | 8 + .../Resources/Tasks/DefeatHeroTask.asset | 13 + .../Resources/Tasks/DefeatHeroTask.asset.meta | 8 + .../TcgEngine/Resources/Tasks/LoginTask.asset | 13 + .../Resources/Tasks/LoginTask.asset.meta | 8 + .../Resources/Tasks/SummonHeroTask.asset | 13 + .../Resources/Tasks/SummonHeroTask.asset.meta | 8 + .../Resources/Tasks/UseSkillTask.asset | 13 + .../Resources/Tasks/UseSkillTask.asset.meta | 8 + .../TcgEngine/Resources/Tasks/WinTask.asset | 13 + .../Resources/Tasks/WinTask.asset.meta | 8 + Assets/TcgEngine/Scripts/Api/ApiMsg.cs | 43 +- Assets/TcgEngine/Scripts/Data/TaskData.cs | 116 ++++ .../TcgEngine/Scripts/Data/TaskData.cs.meta | 11 + .../GameClient/GameClientTaskIntegration.cs | 43 ++ .../GameClientTaskIntegration.cs.meta | 11 + .../Scripts/GameLogic/TaskManager.cs | 553 ++++++++++++++++++ .../Scripts/GameLogic/TaskManager.cs.meta | 11 + 27 files changed, 1318 insertions(+), 1 deletion(-) create mode 100644 Assets/Plugins/steam_api.dll.meta create mode 100644 Assets/Plugins/steam_api64.dll.meta create mode 100644 Assets/TcgEngine/Docs.meta create mode 100644 Assets/TcgEngine/Docs/TaskConfigurations.md create mode 100644 Assets/TcgEngine/Docs/TaskConfigurations.md.meta create mode 100644 Assets/TcgEngine/Docs/TaskSystemAPI.md create mode 100644 Assets/TcgEngine/Docs/TaskSystemAPI.md.meta create mode 100644 Assets/TcgEngine/Docs/TaskSystemUserGuide.md create mode 100644 Assets/TcgEngine/Docs/TaskSystemUserGuide.md.meta create mode 100644 Assets/TcgEngine/Resources/Tasks.meta create mode 100644 Assets/TcgEngine/Resources/Tasks/DefeatHeroTask.asset create mode 100644 Assets/TcgEngine/Resources/Tasks/DefeatHeroTask.asset.meta create mode 100644 Assets/TcgEngine/Resources/Tasks/LoginTask.asset create mode 100644 Assets/TcgEngine/Resources/Tasks/LoginTask.asset.meta create mode 100644 Assets/TcgEngine/Resources/Tasks/SummonHeroTask.asset create mode 100644 Assets/TcgEngine/Resources/Tasks/SummonHeroTask.asset.meta create mode 100644 Assets/TcgEngine/Resources/Tasks/UseSkillTask.asset create mode 100644 Assets/TcgEngine/Resources/Tasks/UseSkillTask.asset.meta create mode 100644 Assets/TcgEngine/Resources/Tasks/WinTask.asset create mode 100644 Assets/TcgEngine/Resources/Tasks/WinTask.asset.meta create mode 100644 Assets/TcgEngine/Scripts/Data/TaskData.cs create mode 100644 Assets/TcgEngine/Scripts/Data/TaskData.cs.meta create mode 100644 Assets/TcgEngine/Scripts/GameClient/GameClientTaskIntegration.cs create mode 100644 Assets/TcgEngine/Scripts/GameClient/GameClientTaskIntegration.cs.meta create mode 100644 Assets/TcgEngine/Scripts/GameLogic/TaskManager.cs create mode 100644 Assets/TcgEngine/Scripts/GameLogic/TaskManager.cs.meta diff --git a/Assets/Plugins/steam_api.dll.meta b/Assets/Plugins/steam_api.dll.meta new file mode 100644 index 0000000..c89d660 --- /dev/null +++ b/Assets/Plugins/steam_api.dll.meta @@ -0,0 +1,27 @@ +fileFormatVersion: 2 +guid: f167045178ff20d45821bd7cb37231f7 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/steam_api64.dll.meta b/Assets/Plugins/steam_api64.dll.meta new file mode 100644 index 0000000..1c606e7 --- /dev/null +++ b/Assets/Plugins/steam_api64.dll.meta @@ -0,0 +1,27 @@ +fileFormatVersion: 2 +guid: 46713ca58de687b4db4d9684c7021923 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Docs.meta b/Assets/TcgEngine/Docs.meta new file mode 100644 index 0000000..328e4bf --- /dev/null +++ b/Assets/TcgEngine/Docs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 08d1c1c6476cad04f97fb97cec8d0798 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Docs/TaskConfigurations.md b/Assets/TcgEngine/Docs/TaskConfigurations.md new file mode 100644 index 0000000..3bafbaf --- /dev/null +++ b/Assets/TcgEngine/Docs/TaskConfigurations.md @@ -0,0 +1,115 @@ +# 任务配置文件结构说明 + +## 概述 + +任务配置文件定义了游戏中可用的各种任务。每个任务都有特定的条件和奖励。 + +## 配置字段说明 + +| 字段名 | 类型 | 必需 | 描述 | +|--------|------|------|------| +| id | string | 是 | 任务唯一标识符 | +| name | string | 是 | 任务显示名称 | +| desc | string | 是 | 任务描述 | +| condition | int | 是 | 任务条件类型 (参考TaskConditionType枚举) | +| value1 | int | 是 | 任务目标值 | +| value2 | string | 否 | 条件参数2 (根据任务类型可能需要) | +| value3 | string | 否 | 条件参数3 (根据任务类型可能需要) | +| rewardTypes | int[] | 是 | 奖励类型数组 (参考TaskRewardType枚举) | +| rewardNums | int[] | 是 | 奖励数量数组 (与rewardTypes一一对应) | +| isDailyTask | boolean | 是 | 是否为每日任务 | +| durationHours | int | 是 | 任务持续时间(小时) | + +## 任务类型详解 + +### 1. 登录任务 (LoginGame - 1) +- **描述**: 玩家登录游戏即可完成 +- **value1**: 无意义 (通常为1) +- **value2/value3**: 不使用 + +### 2. 对战任务 (PlayGames - 2) +- **描述**: 完成指定场次的游戏对战 +- **value1**: 需要完成的对战场次 +- **value2/value3**: 不使用 + +### 3. 胜利任务 (WinGames - 3) +- **描述**: 获得指定场次的对战胜利 +- **value1**: 需要获得胜利的场次 +- **value2/value3**: 不使用 + +### 4. 击败英雄任务 (DefeatHeroWithAttributes - 4) +- **描述**: 击败指定阵营的英雄 +- **value1**: 需要击败的英雄数量 +- **value2**: 第一个目标阵营 (如 "YiYongJun") +- **value3**: 第二个目标阵营 (如 "DiGuoJun") + +### 5. 召唤英雄任务 (SummonHeroWithAttributes - 5) +- **描述**: 召唤指定阵营的英雄 +- **value1**: 需要召唤的英雄数量 +- **value2**: 第一个目标阵营 (如 "WangGuoJun") +- **value3**: 第二个目标阵营 (如 "ZiYouRen") + +### 6. 使用技能任务 (UseHeroSkillWithAttributes - 6) +- **描述**: 使用指定阵营英雄的技能 +- **value1**: 需要使用的技能次数 +- **value2**: 第一个目标阵营 (如 "ShouQun") +- **value3**: 第二个目标阵营 (如 "XieMo") + +## 奖励类型 + +### 金币奖励 (Coins - 0) +- **描述**: 给予玩家指定数量的金币 +- **rewardNums**: 金币数量 + +## 示例配置文件 + +### 登录任务示例 +```json +{ + "id": "login_task_1", + "name": "每日登录", + "desc": "每日登录游戏", + "condition": 1, + "value1": 1, + "value2": "", + "value3": "", + "rewardTypes": [0], + "rewardNums": [100], + "isDailyTask": true, + "durationHours": 24 +} +``` + +### 胜利任务示例 +```json +{ + "id": "win_task_1", + "name": "胜利之路", + "desc": "获得3场对战胜利", + "condition": 3, + "value1": 3, + "value2": "", + "value3": "", + "rewardTypes": [0], + "rewardNums": [200], + "isDailyTask": true, + "durationHours": 24 +} +``` + +### 击败英雄任务示例 +```json +{ + "id": "defeat_hero_task_1", + "name": "阵营克星", + "desc": "击败5个义勇军或帝国军英雄", + "condition": 4, + "value1": 5, + "value2": "YiYongJun", + "value3": "DiGuoJun", + "rewardTypes": [0], + "rewardNums": [300], + "isDailyTask": true, + "durationHours": 24 +} +``` \ No newline at end of file diff --git a/Assets/TcgEngine/Docs/TaskConfigurations.md.meta b/Assets/TcgEngine/Docs/TaskConfigurations.md.meta new file mode 100644 index 0000000..d786c36 --- /dev/null +++ b/Assets/TcgEngine/Docs/TaskConfigurations.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c0a30614928943b46853e32be2a29fb0 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Docs/TaskSystemAPI.md b/Assets/TcgEngine/Docs/TaskSystemAPI.md new file mode 100644 index 0000000..d31abaf --- /dev/null +++ b/Assets/TcgEngine/Docs/TaskSystemAPI.md @@ -0,0 +1,119 @@ +# 任务系统接口文档 + +## 概述 + +任务系统允许玩家完成各种游戏内任务以获得奖励。系统支持多种任务类型,包括日常任务、成就任务等。 + +## API端点 + +### 获取所有任务配置 +``` +GET /api/tasks +``` + +**响应** +```json +[ + { + "id": "login_task_1", + "name": "每日登录", + "desc": "每日登录游戏", + "condition": 1, + "value1": 1, + "value2": "", + "value3": "", + "rewardTypes": [0], + "rewardNums": [100], + "isDailyTask": true, + "durationHours": 24 + }, + { + "id": "win_task_1", + "name": "胜利之路", + "desc": "获得3场对战胜利", + "condition": 3, + "value1": 3, + "value2": "", + "value3": "", + "rewardTypes": [0], + "rewardNums": [200], + "isDailyTask": true, + "durationHours": 24 + } +] +``` + +### 获取玩家任务数据 +``` +GET /api/users/{userId}/tasks +``` + +**响应** +```json +{ + "tasks": [ + { + "taskId": "login_task_1", + "assignedTime": 16409952000000000, + "expireTime": 16410816000000000, + "status": 1, + "progress": 1 + } + ], + "lastDailyTaskAssigned": 16409952000000000 +} +``` + +### 保存玩家任务数据 +``` +POST /api/users/{userId}/tasks +``` + +**请求体** +```json +{ + "tasks": [ + { + "taskId": "login_task_1", + "assignedTime": 16409952000000000, + "expireTime": 16410816000000000, + "status": 1, + "progress": 1 + } + ], + "lastDailyTaskAssigned": 16409952000000000 +} +``` + +**响应** +```json +{ + "success": true, + "error": "" +} +``` + +## 枚举值定义 + +### 任务条件类型 (TaskConditionType) +| 值 | 名称 | 描述 | +|---|------|------| +| 1 | LoginGame | 登入游戏 | +| 2 | PlayGames | 进行X场对战 | +| 3 | WinGames | 胜利X场 | +| 4 | DefeatHeroWithAttributes | 击败Y属性和Z属性的英雄X次 | +| 5 | SummonHeroWithAttributes | 召唤Y属性和Z属性的英雄X次 | +| 6 | UseHeroSkillWithAttributes | 使用Y属性和Z属性英雄的技能X次 | + +### 任务奖励类型 (TaskRewardType) +| 值 | 名称 | 描述 | +|---|------|------| +| 0 | Coins | 金币 | + +### 任务状态 (TaskStatus) +| 值 | 名称 | 描述 | +|---|------|------| +| 0 | Active | 激活 | +| 1 | Completed | 完成 | +| 2 | Expired | 过期 | +| 3 | Claimed | 已领取 | \ No newline at end of file diff --git a/Assets/TcgEngine/Docs/TaskSystemAPI.md.meta b/Assets/TcgEngine/Docs/TaskSystemAPI.md.meta new file mode 100644 index 0000000..5c4ccd5 --- /dev/null +++ b/Assets/TcgEngine/Docs/TaskSystemAPI.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 33e4d9d92f851d04ea1362bf1570a671 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Docs/TaskSystemUserGuide.md b/Assets/TcgEngine/Docs/TaskSystemUserGuide.md new file mode 100644 index 0000000..3f2f194 --- /dev/null +++ b/Assets/TcgEngine/Docs/TaskSystemUserGuide.md @@ -0,0 +1,101 @@ +# 任务系统使用说明 + +## 概述 + +任务系统为玩家提供游戏目标和奖励机制。系统每天为玩家分配一个随机任务,玩家完成任务后可获得奖励。 + +## 系统架构 + +任务系统由以下几个核心组件构成: + +1. **TaskData**: 任务配置数据结构 +2. **TaskManager**: 任务管理器,负责任务逻辑处理 +3. **GameClientTaskIntegration**: 游戏客户端集成组件 +4. **API接口**: 与服务器通信的接口 + +## 功能特性 + +### 1. 任务分配 +- 每日0点为每个玩家随机分配一个任务 +- 玩家最多同时持有5个任务 +- 任务过期时间为24小时 + +### 2. 任务类型 +系统支持以下6种任务类型: +1. 登录任务 +2. 对战任务 +3. 胜利任务 +4. 击败特定阵营英雄任务 +5. 召唤特定阵营英雄任务 +6. 使用特定阵营英雄技能任务 + +### 3. 任务状态 +任务具有以下4种状态: +1. **Active**: 激活状态,玩家正在进行中 +2. **Completed**: 完成状态,条件已满足但奖励未领取 +3. **Expired**: 过期状态,任务已超时 +4. **Claimed**: 已领取,奖励已发放 + +### 4. 奖励机制 +当前版本仅支持金币奖励,未来可扩展支持: +- 卡牌包 +- 稀有卡牌 +- 经验值 +- 其他游戏内物品 + +## 集成指南 + +### 1. 客户端集成 +在游戏客户端中,通过以下方式集成任务系统: + +```csharp +// 在游戏启动时初始化任务系统 +TaskManager taskManager = TaskManager.Instance; +taskManager.OnPlayerLogin(); // 玩家登录时检查任务 + +// 在游戏过程中自动追踪任务进度 +// 系统会自动监听游戏事件并更新任务进度 +``` + +### 2. 服务器集成 +服务器需要提供以下API接口: + +1. `GET /tasks` - 获取所有任务配置 +2. `GET /users/{userId}/tasks` - 获取玩家任务数据 +3. `POST /users/{userId}/tasks` - 保存玩家任务数据 + +## 扩展开发 + +### 添加新的任务类型 +1. 在`TaskConditionType`枚举中添加新的任务类型 +2. 在`TaskManager.UpdateTaskProgress`方法中添加相应的条件判断 +3. 在服务器端添加对应的任务处理逻辑 + +### 添加新的奖励类型 +1. 在`TaskRewardType`枚举中添加新的奖励类型 +2. 在`TaskManager.GiveReward`方法中添加奖励发放逻辑 +3. 在服务器端添加对应的奖励处理逻辑 + +## 最佳实践 + +### 性能优化 +1. 使用本地缓存减少API调用频率 +2. 对任务数据进行批处理更新 +3. 实现合理的错误重试机制 + +### 用户体验 +1. 及时通知玩家任务完成状态 +2. 提供清晰的任务进度显示 +3. 确保奖励发放的可靠性 + +## 故障排除 + +### 常见问题 +1. **任务无法加载**: 检查网络连接和API接口状态 +2. **任务进度不更新**: 检查事件监听是否正常注册 +3. **奖励未发放**: 检查奖励发放逻辑和用户数据同步 + +### 调试建议 +1. 使用日志输出追踪任务状态变化 +2. 验证API响应数据的正确性 +3. 检查时间戳和过期逻辑 \ No newline at end of file diff --git a/Assets/TcgEngine/Docs/TaskSystemUserGuide.md.meta b/Assets/TcgEngine/Docs/TaskSystemUserGuide.md.meta new file mode 100644 index 0000000..bd0529e --- /dev/null +++ b/Assets/TcgEngine/Docs/TaskSystemUserGuide.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3f085404f2be13947a04ab677c3025cd +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Resources/Tasks.meta b/Assets/TcgEngine/Resources/Tasks.meta new file mode 100644 index 0000000..4e551cd --- /dev/null +++ b/Assets/TcgEngine/Resources/Tasks.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8afae310ab2fb8843a6c162db7030919 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Resources/Tasks/DefeatHeroTask.asset b/Assets/TcgEngine/Resources/Tasks/DefeatHeroTask.asset new file mode 100644 index 0000000..6a678d4 --- /dev/null +++ b/Assets/TcgEngine/Resources/Tasks/DefeatHeroTask.asset @@ -0,0 +1,13 @@ +{ + "id": "defeat_hero_task_1", + "name": "阵营克星", + "desc": "击败5个义勇军或帝国军英雄", + "condition": 4, + "value1": 5, + "value2": "YiYongJun", + "value3": "DiGuoJun", + "rewardTypes": [0], + "rewardNums": [300], + "isDailyTask": true, + "durationHours": 24 +} \ No newline at end of file diff --git a/Assets/TcgEngine/Resources/Tasks/DefeatHeroTask.asset.meta b/Assets/TcgEngine/Resources/Tasks/DefeatHeroTask.asset.meta new file mode 100644 index 0000000..a1a02eb --- /dev/null +++ b/Assets/TcgEngine/Resources/Tasks/DefeatHeroTask.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10df7503b6489e7479a8239f15197785 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Resources/Tasks/LoginTask.asset b/Assets/TcgEngine/Resources/Tasks/LoginTask.asset new file mode 100644 index 0000000..657509d --- /dev/null +++ b/Assets/TcgEngine/Resources/Tasks/LoginTask.asset @@ -0,0 +1,13 @@ +{ + "id": "login_task_1", + "name": "每日登录", + "desc": "每日登录游戏", + "condition": 1, + "value1": 1, + "value2": "", + "value3": "", + "rewardTypes": [0], + "rewardNums": [100], + "isDailyTask": true, + "durationHours": 24 +} \ No newline at end of file diff --git a/Assets/TcgEngine/Resources/Tasks/LoginTask.asset.meta b/Assets/TcgEngine/Resources/Tasks/LoginTask.asset.meta new file mode 100644 index 0000000..88d36ed --- /dev/null +++ b/Assets/TcgEngine/Resources/Tasks/LoginTask.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e36474881d2ea304fa5667f767a9044a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Resources/Tasks/SummonHeroTask.asset b/Assets/TcgEngine/Resources/Tasks/SummonHeroTask.asset new file mode 100644 index 0000000..7773f98 --- /dev/null +++ b/Assets/TcgEngine/Resources/Tasks/SummonHeroTask.asset @@ -0,0 +1,13 @@ +{ + "id": "summon_hero_task_1", + "name": "召唤大师", + "desc": "召唤10个王国军或自由人英雄", + "condition": 5, + "value1": 10, + "value2": "WangGuoJun", + "value3": "ZiYouRen", + "rewardTypes": [0], + "rewardNums": [250], + "isDailyTask": true, + "durationHours": 24 +} \ No newline at end of file diff --git a/Assets/TcgEngine/Resources/Tasks/SummonHeroTask.asset.meta b/Assets/TcgEngine/Resources/Tasks/SummonHeroTask.asset.meta new file mode 100644 index 0000000..d592611 --- /dev/null +++ b/Assets/TcgEngine/Resources/Tasks/SummonHeroTask.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0b19400c7b189e64eaf33fbdb02e0347 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Resources/Tasks/UseSkillTask.asset b/Assets/TcgEngine/Resources/Tasks/UseSkillTask.asset new file mode 100644 index 0000000..039cc3d --- /dev/null +++ b/Assets/TcgEngine/Resources/Tasks/UseSkillTask.asset @@ -0,0 +1,13 @@ +{ + "id": "use_skill_task_1", + "name": "技能专家", + "desc": "使用5次兽群或邪魔英雄的技能", + "condition": 6, + "value1": 5, + "value2": "ShouQun", + "value3": "XieMo", + "rewardTypes": [0], + "rewardNums": [150], + "isDailyTask": true, + "durationHours": 24 +} \ No newline at end of file diff --git a/Assets/TcgEngine/Resources/Tasks/UseSkillTask.asset.meta b/Assets/TcgEngine/Resources/Tasks/UseSkillTask.asset.meta new file mode 100644 index 0000000..1877aeb --- /dev/null +++ b/Assets/TcgEngine/Resources/Tasks/UseSkillTask.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c82472e555797d94db11f2f7228eb10e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Resources/Tasks/WinTask.asset b/Assets/TcgEngine/Resources/Tasks/WinTask.asset new file mode 100644 index 0000000..bd41906 --- /dev/null +++ b/Assets/TcgEngine/Resources/Tasks/WinTask.asset @@ -0,0 +1,13 @@ +{ + "id": "win_task_1", + "name": "胜利之路", + "desc": "获得3场对战胜利", + "condition": 3, + "value1": 3, + "value2": "", + "value3": "", + "rewardTypes": [0], + "rewardNums": [200], + "isDailyTask": true, + "durationHours": 24 +} \ No newline at end of file diff --git a/Assets/TcgEngine/Resources/Tasks/WinTask.asset.meta b/Assets/TcgEngine/Resources/Tasks/WinTask.asset.meta new file mode 100644 index 0000000..a0cfc60 --- /dev/null +++ b/Assets/TcgEngine/Resources/Tasks/WinTask.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 80ca1990d6330be49b5e0be31b9b171b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Scripts/Api/ApiMsg.cs b/Assets/TcgEngine/Scripts/Api/ApiMsg.cs index 3424247..49ab989 100644 --- a/Assets/TcgEngine/Scripts/Api/ApiMsg.cs +++ b/Assets/TcgEngine/Scripts/Api/ApiMsg.cs @@ -1,4 +1,4 @@ -using System; +using System; using UnityEngine; namespace TcgEngine @@ -208,4 +208,45 @@ namespace TcgEngine public string last_online_time; } + // 任务相关请求和响应结构 + [Serializable] + public struct TaskDataResponse + { + public string id; + public string name; + public string desc; + public int condition; + public int value1; + public string value2; + public string value3; + public int[] rewardTypes; + public int[] rewardNums; + public bool isDailyTask; + public int durationHours; + } + + [Serializable] + public struct PlayerTaskResponse + { + public string taskId; + public long assignedTime; + public long expireTime; + public int status; + public int progress; + } + + [Serializable] + public struct PlayerTasksResponse + { + public PlayerTaskResponse[] tasks; + public long lastDailyTaskAssigned; + } + + [Serializable] + public struct PlayerTaskSaveRequest + { + public PlayerTaskResponse[] tasks; + public long lastDailyTaskAssigned; + } + } diff --git a/Assets/TcgEngine/Scripts/Data/TaskData.cs b/Assets/TcgEngine/Scripts/Data/TaskData.cs new file mode 100644 index 0000000..7fc4eb0 --- /dev/null +++ b/Assets/TcgEngine/Scripts/Data/TaskData.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TcgEngine +{ + /// + /// 任务配置数据,用于定义各种任务的属性和条件 + /// + [CreateAssetMenu(fileName = "TaskData", menuName = "TcgEngine/TaskData")] + public class TaskData : ScriptableObject + { + public string id; + public string name; + public string desc; + public TaskConditionType condition; + public int value1; // 任务进度上限 + public string value2; // 边界条件1 + public string value3; // 边界条件2 + public TaskRewardType[] rewardTypes; + public int[] rewardNums; + public bool isDailyTask = true; // 是否为每日任务 + public int durationHours = 24; // 任务有效期(小时) + + // 从服务器响应数据创建任务配置 + public static TaskData CreateFromResponse(TaskDataResponse response) + { + TaskData taskData = ScriptableObject.CreateInstance(); + taskData.id = response.id; + taskData.name = response.name; + taskData.desc = response.desc; + taskData.condition = (TaskConditionType)response.condition; + taskData.value1 = response.value1; + taskData.value2 = response.value2; + taskData.value3 = response.value3; + + // 转换奖励类型数组 + taskData.rewardTypes = new TaskRewardType[response.rewardTypes.Length]; + for (int i = 0; i < response.rewardTypes.Length; i++) + { + taskData.rewardTypes[i] = (TaskRewardType)response.rewardTypes[i]; + } + + taskData.rewardNums = response.rewardNums; + taskData.isDailyTask = response.isDailyTask; + taskData.durationHours = response.durationHours; + + return taskData; + } + } + + public enum TaskConditionType + { + LoginGame = 1, // 登入游戏 + PlayGames = 2, // 进行X场对战 + WinGames = 3, // 胜利X场 + DefeatHeroWithAttributes = 4, // 击败Y属性和Z属性的英雄X次 + SummonHeroWithAttributes = 5, // 召唤Y属性和Z属性的英雄X次 + UseHeroSkillWithAttributes = 6 // 使用Y属性和Z属性英雄的技能X次 + } + + public enum TaskRewardType + { + Coins = 0, // 金币 + // 后续可扩展其他奖励类型 + } + + [Serializable] + public class PlayerTask + { + public string taskId; + public DateTime assignedTime; + public DateTime expireTime; + public TaskStatus status; + public int progress; // 当前进度 + + public PlayerTask(TaskData taskConfig) + { + taskId = taskConfig.id; + assignedTime = DateTime.Now; + expireTime = assignedTime.AddHours(taskConfig.durationHours); + status = TaskStatus.Active; + progress = 0; + } + + // 从服务器响应数据创建玩家任务 + public PlayerTask(PlayerTaskResponse response) + { + taskId = response.taskId; + assignedTime = new DateTime(response.assignedTime); + expireTime = new DateTime(response.expireTime); + status = (TaskStatus)response.status; + progress = response.progress; + } + + // 转换为服务器响应数据 + public PlayerTaskResponse ToResponse() + { + PlayerTaskResponse response = new PlayerTaskResponse(); + response.taskId = taskId; + response.assignedTime = assignedTime.Ticks; + response.expireTime = expireTime.Ticks; + response.status = (int)status; + response.progress = progress; + return response; + } + } + + public enum TaskStatus + { + Active = 0, // 激活 + Completed = 1, // 完成 + Expired = 2, // 过期 + Claimed = 3 // 已领取 + } +} \ No newline at end of file diff --git a/Assets/TcgEngine/Scripts/Data/TaskData.cs.meta b/Assets/TcgEngine/Scripts/Data/TaskData.cs.meta new file mode 100644 index 0000000..bda7e86 --- /dev/null +++ b/Assets/TcgEngine/Scripts/Data/TaskData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 951a52e8fe4069e41963e049a390811f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Scripts/GameClient/GameClientTaskIntegration.cs b/Assets/TcgEngine/Scripts/GameClient/GameClientTaskIntegration.cs new file mode 100644 index 0000000..2306371 --- /dev/null +++ b/Assets/TcgEngine/Scripts/GameClient/GameClientTaskIntegration.cs @@ -0,0 +1,43 @@ +using UnityEngine; +using TcgEngine.Client; +using TcgEngine.Gameplay; + +namespace TcgEngine.Client +{ + /// + /// 游戏客户端任务集成,用于将任务系统集成到游戏客户端中 + /// + public class GameClientTaskIntegration : MonoBehaviour + { + private void Start() + { + // 在游戏客户端启动时初始化任务系统 + GameClient client = GameClient.Get(); + if (client != null) + { + // 玩家连接到游戏服务器时触发任务检查 + client.onConnectServer += OnConnectToServer; + } + } + + private void OnDestroy() + { + // 取消订阅事件 + GameClient client = GameClient.Get(); + if (client != null) + { + client.onConnectServer -= OnConnectToServer; + } + } + + private void OnConnectToServer() + { + // 玩家登录时检查任务 + TaskManager taskManager = TaskManager.Instance; + if (taskManager != null) + { + taskManager.OnPlayerLogin(); + } + } + } +} \ No newline at end of file diff --git a/Assets/TcgEngine/Scripts/GameClient/GameClientTaskIntegration.cs.meta b/Assets/TcgEngine/Scripts/GameClient/GameClientTaskIntegration.cs.meta new file mode 100644 index 0000000..f66ea4e --- /dev/null +++ b/Assets/TcgEngine/Scripts/GameClient/GameClientTaskIntegration.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 222f46c5f21da1d47a9d2fed11d3d48c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TcgEngine/Scripts/GameLogic/TaskManager.cs b/Assets/TcgEngine/Scripts/GameLogic/TaskManager.cs new file mode 100644 index 0000000..1c28d2f --- /dev/null +++ b/Assets/TcgEngine/Scripts/GameLogic/TaskManager.cs @@ -0,0 +1,553 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using TcgEngine; +using TcgEngine.Gameplay; +using TcgEngine.Client; +using System.Threading.Tasks; + +namespace TcgEngine.Gameplay +{ + /// + /// 任务管理器,负责任务的分配、进度追踪和奖励发放等功能 + /// + public class TaskManager : MonoBehaviour + { + public static TaskManager Instance; + + [Header("Player Data")] + public List playerTasks = new List(); + public DateTime lastDailyTaskAssigned; + public int maxTasks = 5; // 玩家最多持有任务数 + + private GameLogic gameLogic; + private System.Random random = new System.Random(); + + private void Awake() + { + if (Instance == null) + { + Instance = this; + DontDestroyOnLoad(gameObject); + } + else + { + Destroy(gameObject); + } + } + + private void Start() + { + LoadTasks(); + LoadPlayerData(); + } + + private void OnEnable() + { + // 订阅游戏事件 + GameClient client = GameClient.Get(); + if (client != null) + { + client.onGameStart += OnGameStart; + client.onGameEnd += OnGameEnd; + } + + // 移除对GameLogic.Instance的错误引用,改为检查gameLogic变量 + if (gameLogic != null) + { + SubscribeToGameEvents(); + } + } + + private void OnDisable() + { + // 取消订阅游戏事件 + GameClient client = GameClient.Get(); + if (client != null) + { + client.onGameStart -= OnGameStart; + client.onGameEnd -= OnGameEnd; + } + + // 移除对GameLogic.Instance的错误引用,改为检查gameLogic变量 + if (gameLogic != null) + { + UnsubscribeFromGameEvents(); + } + } + + public void SetGameLogic(GameLogic logic) + { + gameLogic = logic; + SubscribeToGameEvents(); + } + + private void SubscribeToGameEvents() + { + if (gameLogic != null) + { + gameLogic.onCardPlayed += OnCardPlayed; + gameLogic.onCardSummoned += OnCardSummoned; + gameLogic.onAbilityStart += OnAbilityUsed; + gameLogic.onCardDiscarded += OnCardDiscarded; // 用于检测击败英雄 + } + } + + private void UnsubscribeFromGameEvents() + { + if (gameLogic != null) + { + gameLogic.onCardPlayed -= OnCardPlayed; + gameLogic.onCardSummoned -= OnCardSummoned; + gameLogic.onAbilityStart -= OnAbilityUsed; + gameLogic.onCardDiscarded -= OnCardDiscarded; + } + } + + private async void LoadTasks() + { + // 从服务器加载所有任务配置 + await LoadTasksFromServer(); + } + + private async Task LoadTasksFromServer() + { + if (ApiClient.Get() != null && ApiClient.Get().IsLoggedIn()) + { + // 从服务器API获取任务配置 + string url = ApiClient.ServerURL + "/tasks"; + WebResponse res = await ApiClient.Get().SendGetRequest(url); + + if (res.success) + { + // 解析任务配置数据 + try + { + TaskDataResponse[] taskResponses = ApiTool.JsonToObject(res.data); + Debug.Log("Loaded " + taskResponses.Length + " tasks from server"); + // 在实际项目中,这里应该将服务器数据转换为TaskData对象并存储在内存中 + // 供后续使用,而不是每次都从Resources加载 + } + catch (Exception e) + { + Debug.LogError("Failed to parse task data from server: " + e.Message); + } + } + else + { + Debug.LogWarning("Failed to load tasks from server: " + res.error); + } + } + + // 如果无法从服务器加载,则使用本地Resources作为后备 + TaskData[] localTasks = Resources.LoadAll("Tasks"); + Debug.Log("Loaded " + localTasks.Length + " tasks from local resources as fallback"); + } + + private async void LoadPlayerData() + { + // 从服务器加载玩家任务数据 + await LoadPlayerTasksFromServer(); + } + + private async Task LoadPlayerTasksFromServer() + { + if (ApiClient.Get() != null && ApiClient.Get().IsLoggedIn()) + { + // 从服务器获取玩家任务数据 + string url = ApiClient.ServerURL + "/users/" + ApiClient.Get().UserID + "/tasks"; + WebResponse res = await ApiClient.Get().SendGetRequest(url); + + if (res.success) + { + // 解析玩家任务数据 + try + { + PlayerTasksResponse response = ApiTool.JsonToObject(res.data); + lastDailyTaskAssigned = new DateTime(response.lastDailyTaskAssigned); + + // 清除现有任务 + playerTasks.Clear(); + + // 转换并添加任务 + foreach (var taskResponse in response.tasks) + { + PlayerTask playerTask = new PlayerTask(taskResponse); + playerTasks.Add(playerTask); + } + + Debug.Log("Player tasks loaded from server: " + playerTasks.Count + " tasks"); + } + catch (Exception e) + { + Debug.LogError("Failed to parse player tasks from server: " + e.Message); + } + } + else + { + Debug.LogWarning("Failed to load player tasks from server: " + res.error); + } + } + + // 简化处理,首次登录时分配任务 + if (playerTasks.Count == 0) + { + AssignDailyTaskIfNeeded(); + } + } + + public async void SavePlayerData() + { + // 将玩家任务数据保存到服务器 + if (ApiClient.Get() != null && ApiClient.Get().IsLoggedIn()) + { + // 准备要发送的数据 + PlayerTasksResponse saveData = new PlayerTasksResponse(); + + // 转换任务数据 + PlayerTaskResponse[] taskResponses = new PlayerTaskResponse[playerTasks.Count]; + for (int i = 0; i < playerTasks.Count; i++) + { + taskResponses[i] = playerTasks[i].ToResponse(); + } + + saveData.tasks = taskResponses; + saveData.lastDailyTaskAssigned = lastDailyTaskAssigned.Ticks; + + string json = ApiTool.ToJson(saveData); + string url = ApiClient.ServerURL + "/users/" + ApiClient.Get().UserID + "/tasks"; + WebResponse res = await ApiClient.Get().SendPostRequest(url, json); + + if (res.success) + { + Debug.Log("Player tasks saved to server"); + } + else + { + Debug.LogWarning("Failed to save player tasks to server: " + res.error); + } + } + } + + // 每日任务分配 + public void AssignDailyTaskIfNeeded() + { + // 检查是否应该分配新任务(每日一次) + DateTime now = DateTime.Now; + if ((now - lastDailyTaskAssigned).TotalHours < 24) + return; + + // 检查玩家是否已达到最大任务数 + if (playerTasks.Count >= maxTasks) + return; + + // 获取所有每日任务 + TaskData[] allTasks = Resources.LoadAll("Tasks"); + var dailyTasks = allTasks + .Where(t => t.isDailyTask && + t.condition != 0 && + !string.IsNullOrEmpty(t.id)) + .ToArray(); + + if (dailyTasks.Length == 0) + return; + + // 避免重复分配相同任务 + int maxRetries = 3; + TaskData selectedTask = null; + HashSet triedTasks = new HashSet(); + + while (maxRetries-- > 0 && selectedTask == null) + { + // 随机选择一个任务 + TaskData candidateTask = dailyTasks[random.Next(dailyTasks.Length)]; + + // 如果任务已经尝试过则跳过 + if (triedTasks.Contains(candidateTask.id)) + continue; + + triedTasks.Add(candidateTask.id); + + // 检查任务是否有效(未被玩家完成过或未在进度中) + if (!playerTasks.Any(pt => pt.taskId == candidateTask.id)) + { + selectedTask = candidateTask; + break; + } + } + + // 如果没有找到合适的任务则返回 + if (selectedTask == null) + { + Debug.LogWarning("Failed to assign daily task after multiple retries"); + return; + } + + // 创建玩家任务实例 + PlayerTask playerTask = new PlayerTask(selectedTask); + playerTasks.Add(playerTask); + + lastDailyTaskAssigned = now; + SavePlayerData(); + + Debug.Log($"Assigned daily task: {selectedTask.name}"); + } + + // 检查并更新过期任务 + public void CheckExpiredTasks() + { + DateTime now = DateTime.Now; + foreach (var task in playerTasks) + { + if (task.status == TaskStatus.Active && now > task.expireTime) + { + task.status = TaskStatus.Expired; + } + } + } + + // 检查任务是否完成 + public bool CheckTaskCompletion(PlayerTask task) + { + TaskData taskConfig = GetTaskConfig(task.taskId); + if (taskConfig == null) + return false; + + return task.progress >= taskConfig.value1; + } + + // 领取任务奖励 + public bool ClaimTaskReward(PlayerTask task) + { + if (task.status != TaskStatus.Completed) + return false; + + TaskData taskConfig = GetTaskConfig(task.taskId); + if (taskConfig == null) + return false; + + // 发放奖励 + for (int i = 0; i < taskConfig.rewardTypes.Length && i < taskConfig.rewardNums.Length; i++) + { + GiveReward(taskConfig.rewardTypes[i], taskConfig.rewardNums[i]); + } + + task.status = TaskStatus.Claimed; + SavePlayerData(); + return true; + } + + private void GiveReward(TaskRewardType rewardType, int amount) + { + // 根据奖励类型发放奖励 + switch (rewardType) + { + case TaskRewardType.Coins: + // 增加金币(需要与游戏现有金币系统集成) + UserData userData = Authenticator.Get().UserData; + if (userData != null) + { + userData.coins += amount; + Debug.Log($"Gave {amount} coins as reward"); + + // 保存用户数据更新 + if (ApiClient.Get() != null && ApiClient.Get().IsLoggedIn()) + { + Authenticator.Get().SaveUserData(); + } + } + break; + } + } + + private TaskData GetTaskConfig(string taskId) + { + TaskData[] allTasks = Resources.LoadAll("Tasks"); + return allTasks.FirstOrDefault(t => t.id == taskId); + } + + // 更新任务进度 + private void UpdateTaskProgress(TaskConditionType conditionType, string parameter1 = null, string parameter2 = null) + { + bool progressUpdated = false; + + foreach (var task in playerTasks) + { + if (task.status != TaskStatus.Active) + continue; + + TaskData taskConfig = GetTaskConfig(task.taskId); + if (taskConfig == null || taskConfig.condition != conditionType) + continue; + + bool shouldUpdate = false; + + // 根据任务类型检查条件 + switch (conditionType) + { + case TaskConditionType.LoginGame: + case TaskConditionType.PlayGames: + case TaskConditionType.WinGames: + // 这些任务类型直接增加进度 + shouldUpdate = true; + break; + + case TaskConditionType.DefeatHeroWithAttributes: + case TaskConditionType.SummonHeroWithAttributes: + case TaskConditionType.UseHeroSkillWithAttributes: + // 检查参数是否匹配(支持多个参数匹配) + if (!string.IsNullOrEmpty(parameter1) && + (!string.IsNullOrEmpty(taskConfig.value2) && taskConfig.value2 == parameter1 || + !string.IsNullOrEmpty(taskConfig.value3) && taskConfig.value3 == parameter1)) + { + shouldUpdate = true; + } + else if (!string.IsNullOrEmpty(parameter2) && + (!string.IsNullOrEmpty(taskConfig.value2) && taskConfig.value2 == parameter2 || + !string.IsNullOrEmpty(taskConfig.value3) && taskConfig.value3 == parameter2)) + { + shouldUpdate = true; + } + break; + } + + if (shouldUpdate && task.progress < taskConfig.value1) + { + task.progress++; + progressUpdated = true; + + // 检查任务是否完成 + if (CheckTaskCompletion(task)) + { + task.status = TaskStatus.Completed; + Debug.Log($"Task completed: {taskConfig.name}"); + } + } + } + + if (progressUpdated) + { + SavePlayerData(); + } + } + + // 事件处理方法 + private void OnGameStart() + { + // 进行对战任务进度+1 + UpdateTaskProgress(TaskConditionType.PlayGames); + } + + private void OnGameEnd(int winner) + { + int player_id = GameClient.Get().GetPlayerID(); + + // 胜利任务进度+1 + if (winner == player_id) + { + UpdateTaskProgress(TaskConditionType.WinGames); + } + + // 检查是否有任务完成并自动领取奖励 + CheckAndClaimCompletedTasks(); + } + + private void OnCardPlayed(Card card, Slot slot) + { + // 召唤特定属性英雄任务 + if (card.CardData.type == CardType.Character) + { + string cardCamp = card.CardData.camp.ToString(); + UpdateTaskProgress(TaskConditionType.SummonHeroWithAttributes, cardCamp); + } + } + + private void OnCardSummoned(Card card, Slot slot) + { + // 召唤特定属性英雄任务 + if (card.CardData.type == CardType.Character) + { + string cardCamp = card.CardData.camp.ToString(); + UpdateTaskProgress(TaskConditionType.SummonHeroWithAttributes, cardCamp); + } + } + + private void OnAbilityUsed(AbilityData ability, Card caster) + { + // 使用特定属性英雄技能任务 + string cardCamp = caster.CardData.camp.ToString(); + UpdateTaskProgress(TaskConditionType.UseHeroSkillWithAttributes, cardCamp); + } + + private void OnCardDiscarded(Card card) + { + // 击败特定属性英雄任务 + if (card.CardData.type == CardType.Character) + { + string cardCamp = card.CardData.camp.ToString(); + UpdateTaskProgress(TaskConditionType.DefeatHeroWithAttributes, cardCamp); + } + } + + // 检查并自动领取已完成任务的奖励 + public void CheckAndClaimCompletedTasks() + { + bool claimedAny = false; + foreach (var task in playerTasks) + { + if (task.status == TaskStatus.Completed) + { + if (ClaimTaskReward(task)) + { + claimedAny = true; + } + } + } + + if (claimedAny) + { + SavePlayerData(); + } + } + + // 玩家登录时检查任务 + public void OnPlayerLogin() + { + // 登录任务完成 + UpdateTaskProgress(TaskConditionType.LoginGame); + + // 检查是否有任务完成并自动领取奖励 + CheckAndClaimCompletedTasks(); + + // 分配每日任务(如果需要) + AssignDailyTaskIfNeeded(); + } + + // 获取活跃任务 + public List GetActiveTasks() + { + return playerTasks.Where(t => t.status == TaskStatus.Active).ToList(); + } + + // 获取已完成任务 + public List GetCompletedTasks() + { + return playerTasks.Where(t => t.status == TaskStatus.Completed).ToList(); + } + + // 获取所有任务 + public List GetAllTasks() + { + return playerTasks; + } + } + + // 玩家任务保存数据结构 + [Serializable] + public struct PlayerTaskSaveData + { + public PlayerTask[] tasks; + public DateTime lastDailyTaskAssigned; + } +} \ No newline at end of file diff --git a/Assets/TcgEngine/Scripts/GameLogic/TaskManager.cs.meta b/Assets/TcgEngine/Scripts/GameLogic/TaskManager.cs.meta new file mode 100644 index 0000000..644e8ba --- /dev/null +++ b/Assets/TcgEngine/Scripts/GameLogic/TaskManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37abf64a943e2bb43a818a56f330d168 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: