409 lines
9.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "QuestManager.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "Engine/AssetManager.h"
#include "ProjectFish/DataAsset/QuestAsset.h"
#include "ProjectFish/Quest/QuestTypes.h"
void UQuestManager::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
}
void UQuestManager::Deinitialize()
{
Super::Deinitialize();
ActiveQuestsMap.Empty();
CompletedQuestIDs.Empty();
}
void UQuestManager::LoadAllQuests()
{
if (QuestAssets.Num() == 0)
{
// 获得所有任务资源id
TArray<FPrimaryAssetId> QuestAssetIds;
UAssetManager::Get().GetPrimaryAssetIdList(TEXT("QuestAsset"), QuestAssetIds);
// 异步加载所有任务资产
TSharedPtr<FStreamableHandle> LoadHandle = UAssetManager::Get().LoadPrimaryAssets(QuestAssetIds);
if (LoadHandle.IsValid())
{
LoadHandle->WaitUntilComplete();
TArray<UObject*> Assets;
LoadHandle->GetLoadedAssets(Assets); // 获取所有加载成功的资源
for (auto questAsset : Assets)
{
QuestAssets.Add(Cast<UQuestAsset>(questAsset));
}
}
}
}
void UQuestManager::CheckAcceptableQuests()
{
for (auto QuestAsset : QuestAssets)
{
if (!ActiveQuestsMap.Find(QuestAsset->QuestID) && !CompletedQuestIDs.Contains(QuestAsset->QuestID))
{
//任务不在当前已激活的任务 和 已完成的任务列表中
AcceptQuest(QuestAsset);
}
}
}
bool UQuestManager::AcceptQuest(UQuestAsset* QuestAsset)
{
if (!QuestAsset)
{
return false;
}
// 检查是否已经接受或完成
if (ActiveQuestsMap.Contains(QuestAsset->QuestID) || CompletedQuestIDs.Contains(QuestAsset->QuestID))
{
return false;
}
// 检查前置任务
if (!CanAcceptQuest(QuestAsset))
{
return false;
}
// 创建运行时数据
FQuestRuntimeData RuntimeData = CreateRuntimeData(QuestAsset);
RuntimeData.State = EQuestState::InProgress;
ActiveQuestsMap.Add(QuestAsset->QuestID, RuntimeData);
// 触发事件
OnQuestStateChanged.Broadcast(QuestAsset->QuestID);
UE_LOG(LogTemp, Warning, TEXT("Quest %s Accepted"), *QuestAsset->QuestName.ToString());
return true;
}
bool UQuestManager::FollowQuest(int32 QuestID, bool Follow)
{
FQuestRuntimeData* RuntimeData = ActiveQuestsMap.Find(QuestID);
if (!RuntimeData)
{
return false;
}
if (Follow)
{
FollowingQuestIDs.Add(QuestID);
}
else
{
FollowingQuestIDs.Remove(QuestID);
}
return true;
}
bool UQuestManager::CompleteQuest(int32 QuestID)
{
FQuestRuntimeData* RuntimeData = ActiveQuestsMap.Find(QuestID);
if (!RuntimeData)
{
return false;
}
// 检查所有目标是否完成
for (const FQuestProgress& Progress : RuntimeData->ObjectiveProgress)
{
if (!Progress.bCompleted)
{
return false;
}
}
// 标记为已完成
RuntimeData->State = EQuestState::Completed;
CompletedQuestIDs.Add(QuestID);
// 触发事件
OnQuestStateChanged.Broadcast(QuestID);
UE_LOG(LogTemp, Warning, TEXT("Quest id = %d Complete"), QuestID);
// 从活动任务中移除
ActiveQuestsMap.Remove(QuestID);
//检测是否有其他可接受的任务
CheckAcceptableQuests();
return true;
}
bool UQuestManager::AbandonQuest(int32 QuestID)
{
if (!ActiveQuestsMap.Contains(QuestID))
{
return false;
}
ActiveQuestsMap.Remove(QuestID);
OnQuestStateChanged.Broadcast(QuestID);
return true;
}
void UQuestManager::UpdateObjectiveProgress(int32 QuestID, int32 ObjectiveIndex, int32 Progress)
{
FQuestRuntimeData* RuntimeData = ActiveQuestsMap.Find(QuestID);
if (!RuntimeData || !RuntimeData->QuestAsset)
{
return;
}
// 检查索引有效性
if (!RuntimeData->ObjectiveProgress.IsValidIndex(ObjectiveIndex))
{
return;
}
// 获取目标配置
const FQuestObjective& Objective = RuntimeData->QuestAsset->Objectives[ObjectiveIndex];
FQuestProgress& ProgressData = RuntimeData->ObjectiveProgress[ObjectiveIndex];
// 更新进度
ProgressData.CurrentProgress = FMath::Clamp(Progress, 0, Objective.RequiredAmount);
// 检查是否完成
if (ProgressData.CurrentProgress >= Objective.RequiredAmount)
{
ProgressData.bCompleted = true;
}
// 触发事件
OnQuestObjectiveUpdated.Broadcast(QuestID, ObjectiveIndex);
// 检查任务是否完成
CheckQuestCompletion(QuestID);
}
void UQuestManager::UpdateObjectiveByTargetID(FName TargetID, int32 ProgressDelta)
{
// 遍历所有活动任务,查找匹配的目标
for (TPair<int32, FQuestRuntimeData>& Pair : ActiveQuestsMap)
{
FQuestRuntimeData& RuntimeData = Pair.Value;
if (!RuntimeData.QuestAsset)
{
continue;
}
// 查找匹配的目标
for (int32 i = 0; i < RuntimeData.QuestAsset->Objectives.Num(); ++i)
{
const FQuestObjective& Objective = RuntimeData.QuestAsset->Objectives[i];
if (Objective.TargetID == TargetID)
{
// 增加进度
int32 NewProgress = RuntimeData.ObjectiveProgress[i].CurrentProgress + ProgressDelta;
UpdateObjectiveProgress(Pair.Key, i, NewProgress);
}
}
}
}
EQuestState UQuestManager::GetQuestState(int32 QuestID) const
{
if (CompletedQuestIDs.Contains(QuestID))
{
return EQuestState::Completed;
}
const FQuestRuntimeData* RuntimeData = ActiveQuestsMap.Find(QuestID);
if (RuntimeData)
{
return RuntimeData->State;
}
return EQuestState::NotStarted;
}
bool UQuestManager::IsQuestFollowing(int32 QuestID) const
{
return FollowingQuestIDs.Contains(QuestID);
}
TArray<UQuestAsset*> UQuestManager::GetActiveQuests() const
{
TArray<UQuestAsset*> Result;
for (const TPair<int32, FQuestRuntimeData>& Pair : ActiveQuestsMap)
{
if (Pair.Value.State == EQuestState::InProgress && Pair.Value.QuestAsset)
{
Result.Add(Pair.Value.QuestAsset);
}
}
return Result;
}
TArray<UQuestAsset*> UQuestManager::GetCompletedQuests() const
{
TArray<UQuestAsset*> Result;
for (const TPair<int32, FQuestRuntimeData>& Pair : ActiveQuestsMap)
{
if (Pair.Value.State == EQuestState::Completed && Pair.Value.QuestAsset)
{
Result.Add(Pair.Value.QuestAsset);
}
}
return Result;
}
bool UQuestManager::GetQuestProgress(int32 QuestID, TArray<FQuestProgress>& OutProgress) const
{
const FQuestRuntimeData* RuntimeData = ActiveQuestsMap.Find(QuestID);
if (RuntimeData)
{
OutProgress = RuntimeData->ObjectiveProgress;
return true;
}
return false;
}
bool UQuestManager::CanAcceptQuest(UQuestAsset* QuestAsset) const
{
if (!QuestAsset)
{
return false;
}
// 检查所有前置任务是否完成
for (int32 PrerequisiteID : QuestAsset->PrerequisiteQuestIDs)
{
if (!CompletedQuestIDs.Contains(PrerequisiteID))
{
return false;
}
}
return true;
}
TArray<FQuestSaveData> UQuestManager::GetQuestSaveData() const
{
TArray<FQuestSaveData> SaveDataArray;
for (const TPair<int32, FQuestRuntimeData>& Pair : ActiveQuestsMap)
{
FQuestSaveData SaveData;
SaveData.QuestID = Pair.Key;
SaveData.QuestState = Pair.Value.State;
// 保存目标进度
for (const FQuestProgress& Progress : Pair.Value.ObjectiveProgress)
{
SaveData.ObjectiveProgress.Add(Progress.CurrentProgress);
SaveData.ObjectiveCompleted.Add(Progress.bCompleted);
}
//设置追踪状态
if (FollowingQuestIDs.Contains(Pair.Key))
{
SaveData.bFollowing = true;
}
else
{
SaveData.bFollowing = false;
}
SaveDataArray.Add(SaveData);
}
return SaveDataArray;
}
void UQuestManager::LoadFromSaveData(const TArray<FQuestSaveData>& SaveData)
{
// 清空现有数据
ActiveQuestsMap.Empty();
CompletedQuestIDs.Empty();
FollowingQuestIDs.Empty();
LoadAllQuests();
for (const FQuestSaveData& Data : SaveData)
{
if (Data.QuestState == EQuestState::Completed)
{
CompletedQuestIDs.Add(Data.QuestID);
}
else if (Data.QuestState == EQuestState::InProgress)
{
for (auto questAsset: QuestAssets)
{
if (questAsset->QuestID == Data.QuestID)
{
FQuestRuntimeData RuntimeData = CreateRuntimeData(questAsset);
for (int i =0; i < RuntimeData.ObjectiveProgress.Num(); i++)
{
RuntimeData.ObjectiveProgress[i].CurrentProgress = Data.ObjectiveProgress[i];
RuntimeData.ObjectiveProgress[i].bCompleted = Data.ObjectiveCompleted[i];
}
RuntimeData.State = EQuestState::InProgress;
ActiveQuestsMap.Add(questAsset->QuestID, RuntimeData);
//添加追踪任务列表
if (Data.bFollowing)
{
FollowingQuestIDs.Add(questAsset->QuestID);
}
return;
}
}
}
}
CheckAcceptableQuests();
}
void UQuestManager::CheckQuestCompletion(int32 QuestID)
{
FQuestRuntimeData* RuntimeData = ActiveQuestsMap.Find(QuestID);
if (!RuntimeData)
{
return;
}
// 检查所有目标是否完成
bool bAllCompleted = true;
for (const FQuestProgress& Progress : RuntimeData->ObjectiveProgress)
{
if (!Progress.bCompleted)
{
bAllCompleted = false;
break;
}
}
// 如果所有目标完成,自动完成任务
if (bAllCompleted)
{
CompleteQuest(QuestID);
}
}
FQuestRuntimeData UQuestManager::CreateRuntimeData(UQuestAsset* QuestAsset)
{
FQuestRuntimeData RuntimeData;
RuntimeData.QuestAsset = QuestAsset;
RuntimeData.State = EQuestState::NotStarted;
// 初始化目标进度
for (int32 i = 0; i < QuestAsset->Objectives.Num(); ++i)
{
FQuestProgress Progress;
Progress.CurrentProgress = 0;
Progress.bCompleted = false;
RuntimeData.ObjectiveProgress.Add(Progress);
}
return RuntimeData;
}