Files
tcg-client/Assets/TcgEngine/Scripts/GameLogic/TaskManager.cs
2025-09-12 11:39:17 +08:00

700 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
{
/// <summary>
/// 任务管理器,负责任务的分配、进度追踪和奖励发放等功能
/// </summary>
public class TaskManager : MonoBehaviour
{
public static TaskManager Instance;
[Header("Player Data")]
public List<PlayerTask> playerTasks = new List<PlayerTask>();
public bool isClearPlayerTasks = false;
public long lastDailyTaskAssigned = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
public int maxTasks = 5; // 玩家最多持有任务数
private GameLogic gameLogic;
private System.Random random = new System.Random();
public Action<List<PlayerTask>> refreshTaskUI;
private GameClient gameClient;
public string userID;
// 任务缓存处
public Dictionary<string,TaskData> taskConfigs = new Dictionary<string,TaskData>();
// 玩家任务快速索引
private Dictionary<string, PlayerTask> assignedTaskDict = new Dictionary<string, PlayerTask>();
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
private void Start()
{
userID = ApiClient.Get().UserID;
}
private void OnEnable()
{
// 订阅游戏事件
gameClient = FindFirstObjectByType<GameClient>();
gameClient = GameClient.Get();
if (gameClient != null)
{
LoadTasks();
LoadPlayerData();
gameClient.onGameStart += OnGameStart;
gameClient.onGameEnd += OnGameEnd;
// gameClient.onConnectServer?.Invoke();
}
// 移除对GameLogic.Instance的错误引用改为检查gameLogic变量
if (gameLogic != null)
{
SubscribeToGameEvents();
}
}
private void OnDisable()
{
// 取消订阅游戏事件
gameClient = FindFirstObjectByType<GameClient>();
gameClient = GameClient.Get();
if (gameClient != null)
{
gameClient.onGameStart -= OnGameStart;
gameClient.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 + "/api/tasks";
WebResponse res = await ApiClient.Get().SendGetRequest(url);
Debug.Log("从服务器API获取任务配置" + res.data + res.status);
if (res.success)
{
// 解析任务配置数据
try
{
TaskDataResponse[] taskResponses = ApiTool.JsonToArray<TaskDataResponse>(res.data);
// 在实际项目中这里应该将服务器数据转换为TaskData对象并存储在内存中
// 供后续使用而不是每次都从Resources加载
foreach (var item in taskResponses)
{
// Debug.Log($"缓存ID处<color=pink>{item.id}</color>");
taskConfigs[item.id] =
TaskData.CreateFromResponse(item);
}
// Debug.Log("共储存:" + taskConfigs.Count + "条信息");
foreach (var kvp in taskConfigs)
{
TaskData task = kvp.Value;
// Debug.Log($"分别为 <color=red>{task.id}</color>");
}
}
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<TaskData>("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 + $"/api/tasks/"+ApiClient.Get().UserID;
WebResponse res = await ApiClient.Get().SendGetRequest(url);
// Debug.Log($"<color=red>LoadPlayerTasksFromServer:{url}</color>");
Debug.LogWarning($"从服务器获取玩家任务数据res_data--:{res.data},{res.status}");
if (res.success)
{
// 解析玩家任务数据
try
{
PlayerTasksResponse response = ApiTool.JsonToObject<PlayerTasksResponse>(res.data);
lastDailyTaskAssigned = PlayerTask.Iso8601ToTimestamp(response.lastDailyTaskAssigned);
// 清除现有任务
playerTasks.Clear();
assignedTaskDict.Clear();
// 转换并添加任务
foreach (var taskResponse in response.tasks)
{
PlayerTask playerTask = new PlayerTask(taskResponse);
playerTasks.Add(playerTask);
assignedTaskDict[playerTask.taskId] = playerTask;
Debug.Log($"已分配任务: {playerTask.taskId}");
}
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);
}
}
}
public async void SavePlayerData()
{
// 将玩家任务数据保存到服务器
if (ApiClient.Get() != null)
{
if (isClearPlayerTasks)
{
playerTasks.Clear();
isClearPlayerTasks = false;
}
// 准备要发送的数据
PlayerTaskSaveRequest saveData = new PlayerTaskSaveRequest();
// 转换任务数据
PlayerTaskResponse[] taskResponses = new PlayerTaskResponse[playerTasks.Count];
for (int i = 0; i < playerTasks.Count; i++)
{
taskResponses[i] = playerTasks[i].ToResponse();
}
Debug.Log($"<color=red>{taskResponses.Length}</color>");
saveData.tasks = taskResponses;
saveData.lastDailyTaskAssigned = PlayerTask.TimestampToIso8601(lastDailyTaskAssigned);
Debug.Log($"saveData.tasks---{saveData.tasks.Length}");
string json = ApiTool.ToJson(saveData);
string url = ApiClient.ServerURL + $"/api/tasks/{userID}";
WebResponse res = await ApiClient.Get().SendPostRequest(url, json);
Debug.Log(json);
Debug.Log($"<color=red>SavePlayerData:{url}</color>");
if (res.success)
{
Debug.Log("玩家任务已保存到服务器");
ResetUIPanel();
CheckExpiredTasks(playerTasks);
}
else
{
Debug.LogWarning("未能将玩家任务保存到服务器:" + res.error+"错误码:"+res.status);
}
}
}
private void Update()
{
if (isClearPlayerTasks)
{
ClearAllSaveData();
}
if (Input.GetKeyDown(KeyCode.S))
{
CheckExpiredTasks(playerTasks);
SavePlayerData();
}
}
private void ClearAllSaveData()
{
if (!isClearPlayerTasks)
{
Debug.LogWarning("清除失败");
return;
}
playerTasks.Clear();
assignedTaskDict.Clear();
SavePlayerData();
Debug.Log("清除成功");
}
// 每日任务分配
public void AssignDailyTaskIfNeeded()
{
long now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
long secondsSinceLastTask = now - lastDailyTaskAssigned;
// 转换为小时
double hoursSinceLastTask = secondsSinceLastTask / 3600.0;
Debug.Log($"当前时间:{now},最后下发时间:{lastDailyTaskAssigned},减去时间{secondsSinceLastTask},小时时间:{hoursSinceLastTask}");
if (hoursSinceLastTask < 24 && assignedTaskDict.Count == 5)
return;
// 检查玩家是否已达到最大任务数
if (playerTasks.Count >= maxTasks)
return;
TaskData[] allTasks;
if (taskConfigs.Count!=0)
{
// 从缓存中取 Value 部分TaskData转成数组
allTasks = taskConfigs.Values.ToArray();
Debug.Log("读取任务缓存成功!");
}
else
{
// 如果缓存没有任务采用本地任务
allTasks = Resources.LoadAll<TaskData>("Tasks");
Debug.LogError("读取任务缓存失败,采用本地任务");
}
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<string> triedTasks = new HashSet<string>();
while (maxRetries-- > 0 && selectedTask == null)
{
// 随机选择一个任务
TaskData candidateTask = dailyTasks[random.Next(dailyTasks.Length)];
// 如果任务已经尝试过则跳过
if (triedTasks.Contains(candidateTask.id))
continue;
triedTasks.Add(candidateTask.id);
// 用字典判断是否已分配过
if (!assignedTaskDict.ContainsKey(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($"分配任务: {selectedTask.name}");
}
// 检查并更新过期任务
public void CheckExpiredTasks(List<PlayerTask> tasksList)
{
long now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); // 当前时间戳(秒)
foreach (var task in tasksList)
{
long unixTime = task.expireTime;
if (task.status == TaskStatus.Active && now > unixTime)
{
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)
{
UserData userData = Authenticator.Get().UserData;
// 根据奖励类型发放奖励
switch (rewardType)
{
case TaskRewardType.Coins:
// 增加金币(需要与游戏现有金币系统集成)
if (userData != null)
{
userData.coins += amount;
Debug.Log($"Gave {amount} coins as reward");
}
break;
case TaskRewardType.Crystal:
if (userData != null)
{
userData.crystal += amount;
Debug.Log($"获取{amount}个钻石");
}
break;
}
// 保存用户数据更新
if (ApiClient.Get() != null && ApiClient.Get().IsLoggedIn())
{
Authenticator.Get().SaveUserData();
}
}
private TaskData GetTaskConfig(string taskId)
{
TaskData[] allTasks;
if (taskConfigs!=null)
{
allTasks = taskConfigs.Values.ToArray();
}
else
{
allTasks = Resources.LoadAll<TaskData>("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()
{
// 检查是否已有登录任务
bool hasLoginTask = assignedTaskDict.Values.Any(t =>
{
TaskData config = GetTaskConfig(t.taskId);
return config != null && config.condition == TaskConditionType.LoginGame;
});
Debug.Log("hasLoginTask:"+hasLoginTask);
// 如果没有登录任务,就分配一个
if (!hasLoginTask)
{
AssignLoginTask();
}
else
{
// 如过有就随机分配一个新任务
AssignDailyTaskIfNeeded();
}
}
/// <summary>
/// 专门分配一个登录任务
/// </summary>
private void AssignLoginTask()
{
TaskData[] allTasks;
if (taskConfigs != null)
{
allTasks = taskConfigs.Values.ToArray();
}
else
{
allTasks = Resources.LoadAll<TaskData>("Tasks");
}
var loginTask = allTasks.FirstOrDefault(t => t.isDailyTask && t.condition == TaskConditionType.LoginGame);
if (loginTask != null)
{
PlayerTask playerTask = new PlayerTask(loginTask);
playerTasks.Add(playerTask);
lastDailyTaskAssigned = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
SavePlayerData();
Debug.Log($"分配登录任务: {loginTask.name}");
// 登录任务完成
UpdateTaskProgress(TaskConditionType.LoginGame);
}
else
{
Debug.LogWarning("未找到登录任务配置!");
}
}
// 获取活跃任务
public List<PlayerTask> GetActiveTasks()
{
return playerTasks.Where(t => t.status == TaskStatus.Active).ToList();
}
// 获取已完成任务
public List<PlayerTask> GetCompletedTasks()
{
return playerTasks.Where(t => t.status == TaskStatus.Completed).ToList();
}
// 获取所有任务
public List<PlayerTask> GetAllTasks()
{
return playerTasks;
}
/// <summary>
/// 重置面板
/// </summary>
public void ResetUIPanel()
{
refreshTaskUI?.Invoke(playerTasks);
}
}
}