Compare commits
11 Commits
016199c0a5
...
a07705c683
| Author | SHA1 | Date | |
|---|---|---|---|
| a07705c683 | |||
| c07849c95b | |||
| 4821d206c0 | |||
| 0f942b0b77 | |||
| 111f68fa10 | |||
| 1ccc1d8796 | |||
| f07e298eb8 | |||
| 3c084a8795 | |||
| 8917abed28 | |||
| 10d2c7e354 | |||
| a8756f2e4c |
9
ProjectFish/.claude/settings.local.json
Normal file
9
ProjectFish/.claude/settings.local.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(dir:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
BIN
ProjectFish/Binaries/Win64/UnrealEditor-ProjectFish-0001.dll
Normal file
BIN
ProjectFish/Binaries/Win64/UnrealEditor-ProjectFish-0001.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -2,7 +2,7 @@
|
||||
"BuildId": "37670630",
|
||||
"Modules":
|
||||
{
|
||||
"ProjectFish": "UnrealEditor-ProjectFish.dll",
|
||||
"ProjectFishEditor": "UnrealEditor-ProjectFishEditor.dll"
|
||||
"ProjectFish": "UnrealEditor-ProjectFish-0001.dll",
|
||||
"ProjectFishEditor": "UnrealEditor-ProjectFishEditor-0001.dll"
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,7 @@ FixedCameraDistance=1500.0
|
||||
+PrimaryAssetTypesToScan=(PrimaryAssetType="PrimaryAssetLabel",AssetBaseClass="/Script/Engine.PrimaryAssetLabel",bHasBlueprintClasses=False,bIsEditorOnly=True,Directories=((Path="/Game")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=Unknown))
|
||||
+PrimaryAssetTypesToScan=(PrimaryAssetType="FishingRewardDataAsset",AssetBaseClass="/Script/ProjectFish.FishingRewardDataAsset",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/DataAssets/FishReward")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=AlwaysCook))
|
||||
+PrimaryAssetTypesToScan=(PrimaryAssetType="ShapeAsset",AssetBaseClass="/Script/ProjectFish.ShapeAsset",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/DataAssets")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=AlwaysCook))
|
||||
+PrimaryAssetTypesToScan=(PrimaryAssetType="QuestAsset",AssetBaseClass="/Script/ProjectFish.QuestAsset",bHasBlueprintClasses=False,bIsEditorOnly=False,Directories=((Path="/Game/DataAssets/Quest")),SpecificAssets=,Rules=(Priority=-1,ChunkId=-1,bApplyRecursively=True,CookRule=AlwaysCook))
|
||||
bOnlyCookProductionAssets=False
|
||||
bShouldManagerDetermineTypeAndName=False
|
||||
bShouldGuessTypeAndNameInEditor=True
|
||||
|
||||
@ -10,5 +10,8 @@ InvalidTagCharacters="\"\',"
|
||||
+GameplayTagRedirects=(OldTagName="Skill.PoserPull",NewTagName="Skill.PowerPull")
|
||||
NumBitsForContainerSize=6
|
||||
NetIndexFirstBitSegment=16
|
||||
+GameplayTagList=(Tag="FishReward",DevComment="鱼获")
|
||||
+GameplayTagList=(Tag="FishReward.Fish1",DevComment="")
|
||||
+GameplayTagList=(Tag="FishReward.Fish2",DevComment="")
|
||||
+GameplayTagList=(Tag="Skill.PowerPull",DevComment="")
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
ProjectFish/Content/UI/Main/UMG_MainWindow.uasset
Normal file
BIN
ProjectFish/Content/UI/Main/UMG_MainWindow.uasset
Normal file
Binary file not shown.
Binary file not shown.
BIN
ProjectFish/Content/UI/Quest/Widget/UMG_QuestInfo_Widget.uasset
Normal file
BIN
ProjectFish/Content/UI/Quest/Widget/UMG_QuestInfo_Widget.uasset
Normal file
Binary file not shown.
BIN
ProjectFish/Content/UI/Quest/Widget/UMG_Quest_Switcher.uasset
Normal file
BIN
ProjectFish/Content/UI/Quest/Widget/UMG_Quest_Switcher.uasset
Normal file
Binary file not shown.
BIN
ProjectFish/Content/UI/Quest/Window/UMG_QuestWindow.uasset
Normal file
BIN
ProjectFish/Content/UI/Quest/Window/UMG_QuestWindow.uasset
Normal file
Binary file not shown.
Binary file not shown.
@ -2,6 +2,6 @@
|
||||
"BuildId": "37670630",
|
||||
"Modules":
|
||||
{
|
||||
"DeskMode": "UnrealEditor-DeskMode.dll"
|
||||
"DeskMode": "UnrealEditor-DeskMode-0001.dll"
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@
|
||||
#include "ContainerInfo.h"
|
||||
#include "GameFramework/SaveGame.h"
|
||||
#include "ProjectFish/Definations.h"
|
||||
#include "ProjectFish/Quest/QuestTypes.h"
|
||||
#include "PlayerInfoSaveGame.generated.h"
|
||||
|
||||
/**
|
||||
@ -43,4 +44,8 @@ public:
|
||||
// 玩家仓库物品存档数据
|
||||
UPROPERTY(SaveGame, BlueprintReadWrite, meta = (ToolTip = "玩家仓库物品数据"))
|
||||
TArray<FContainerItemSaveData> PlayerContainerItems;
|
||||
|
||||
// 任务存档数据
|
||||
UPROPERTY(SaveGame, BlueprintReadWrite, meta = (ToolTip = "任务存档数据"))
|
||||
TArray<FQuestSaveData> QuestSaveData;
|
||||
};
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "CoreMinimal.h"
|
||||
#include "ShapeAsset.h"
|
||||
#include "Engine/DataAsset.h"
|
||||
#include "ProjectFish/Quest/QuestTypes.h"
|
||||
#include "FishingRewardDataAsset.generated.h"
|
||||
|
||||
UENUM(BlueprintType)
|
||||
@ -36,4 +37,7 @@ public:
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Fishing Reward Data" , meta = (ToolTip = "鱼获稀有度"))
|
||||
ERewardRarityType RewardRarityType;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Fishing Reward Data" , meta = (ToolTip = "鱼获对应的任务信息"))
|
||||
FQuestTargetInfo QuestTargetInfo;
|
||||
};
|
||||
|
||||
88
ProjectFish/Source/ProjectFish/DataAsset/QuestAsset.cpp
Normal file
88
ProjectFish/Source/ProjectFish/DataAsset/QuestAsset.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "QuestAsset.h"
|
||||
|
||||
#if WITH_EDITOR
|
||||
#include "AssetRegistry/AssetRegistryModule.h"
|
||||
#include "AssetRegistry/AssetData.h"
|
||||
#include "Misc/MessageDialog.h"
|
||||
|
||||
void UQuestAsset::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
||||
{
|
||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
||||
|
||||
// 检查是否修改了 QuestID 属性
|
||||
if (PropertyChangedEvent.Property != nullptr &&
|
||||
PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UQuestAsset, QuestID))
|
||||
{
|
||||
// 获取资产注册表模块
|
||||
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
|
||||
IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
|
||||
|
||||
// 查找所有 QuestAsset 资产
|
||||
TArray<FAssetData> AssetDataList;
|
||||
AssetRegistry.GetAssetsByClass(UQuestAsset::StaticClass()->GetClassPathName(), AssetDataList, true);
|
||||
|
||||
// 检查是否有其他资产使用了相同的 QuestID
|
||||
for (const FAssetData& AssetData : AssetDataList)
|
||||
{
|
||||
// 跳过自己
|
||||
if (AssetData.GetAsset() == this)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (UQuestAsset* OtherQuestAsset = Cast<UQuestAsset>(AssetData.GetAsset()))
|
||||
{
|
||||
if (OtherQuestAsset->QuestID == this->QuestID)
|
||||
{
|
||||
// 发现重复的 QuestID,显示警告并建议修改
|
||||
FText WarningTitle = FText::FromString(TEXT("QuestID 重复警告"));
|
||||
FText WarningMessage = FText::FromString(FString::Printf(
|
||||
TEXT("QuestID %d 已被其他任务资产使用:\n%s\n\n请修改为不同的ID以避免冲突。"),
|
||||
this->QuestID,
|
||||
*AssetData.AssetName.ToString()
|
||||
));
|
||||
|
||||
FMessageDialog::Open(EAppMsgType::Ok, WarningMessage, WarningTitle);
|
||||
|
||||
UE_LOG(LogTemp, Warning, TEXT("QuestID %d 重复!已存在于资产: %s"),
|
||||
this->QuestID, *AssetData.AssetName.ToString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UQuestAsset::PostDuplicate(bool bDuplicateForPIE)
|
||||
{
|
||||
Super::PostDuplicate(bDuplicateForPIE);
|
||||
if (!bDuplicateForPIE)
|
||||
{
|
||||
int32 MaxQuestID = 0;
|
||||
|
||||
// 获取资产注册表模块
|
||||
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
|
||||
IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
|
||||
|
||||
// 查找所有 QuestAsset 资产
|
||||
TArray<FAssetData> AssetDataList;
|
||||
AssetRegistry.GetAssetsByClass(UQuestAsset::StaticClass()->GetClassPathName(), AssetDataList, true);
|
||||
|
||||
// 遍历所有已存在的任务资产,找到最大的 QuestID
|
||||
for (const FAssetData& AssetData : AssetDataList)
|
||||
{
|
||||
if (UQuestAsset* QuestAsset = Cast<UQuestAsset>(AssetData.GetAsset()))
|
||||
{
|
||||
if (QuestAsset->QuestID > MaxQuestID)
|
||||
{
|
||||
MaxQuestID = QuestAsset->QuestID;
|
||||
}
|
||||
}
|
||||
}
|
||||
QuestID += 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
58
ProjectFish/Source/ProjectFish/DataAsset/QuestAsset.h
Normal file
58
ProjectFish/Source/ProjectFish/DataAsset/QuestAsset.h
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/DataAsset.h"
|
||||
#include "../Quest/QuestTypes.h"
|
||||
#include "QuestAsset.generated.h"
|
||||
|
||||
/**
|
||||
* 任务数据资产
|
||||
* 在编辑器中创建并配置任务内容
|
||||
*/
|
||||
UCLASS(BlueprintType)
|
||||
class PROJECTFISH_API UQuestAsset : public UDataAsset
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
#if WITH_EDITOR
|
||||
// 编辑器中属性修改后的回调
|
||||
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
|
||||
|
||||
virtual void PostDuplicate(bool bDuplicateForPIE) override;
|
||||
#endif
|
||||
/** 任务编号ID */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest|Basic")
|
||||
int32 QuestID = 0;
|
||||
|
||||
/** 任务名称 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest|Basic")
|
||||
FText QuestName;
|
||||
|
||||
/** 任务描述 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest|Basic", meta = (MultiLine = true))
|
||||
FText QuestDescription;
|
||||
|
||||
/** 前置任务ID列表() */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest|Trigger", meta = (ToolTip = "完成这些任务后才能触发当前任务, 不填写默认激活接受"))
|
||||
TArray<int32> PrerequisiteQuestIDs;
|
||||
|
||||
/** 任务触发条件(预留,可在蓝图中实现) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest|Trigger")
|
||||
FString TriggerCondition;
|
||||
|
||||
/** 任务目标列表 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest|Objectives")
|
||||
TArray<FQuestObjective> Objectives;
|
||||
|
||||
/** 任务奖励列表 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest|Rewards")
|
||||
TArray<FQuestReward> Rewards;
|
||||
|
||||
/** 任务完成条件描述(预留,可在蓝图中实现) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Quest|Completion")
|
||||
FString CompletionCondition;
|
||||
|
||||
};
|
||||
@ -3,22 +3,37 @@
|
||||
|
||||
#include "GameInfoManager.h"
|
||||
|
||||
#include "QuestManager.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
FString UGameInfoManager::SaveGameSlotName = TEXT("GameInfo");
|
||||
void UGameInfoManager::Initialize(FSubsystemCollectionBase& Collection)
|
||||
{
|
||||
Super::Initialize(Collection);
|
||||
Collection.InitializeDependency<UQuestManager>();
|
||||
if (!LoadGameInfo())
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("本地存档不存在加载失败"));
|
||||
}
|
||||
}
|
||||
|
||||
void UGameInfoManager::NewSaveGame()
|
||||
{
|
||||
UGameplayStatics::DeleteGameInSlot(SaveGameSlotName, 0);
|
||||
}
|
||||
|
||||
void UGameInfoManager::SaveGameInfo()
|
||||
{
|
||||
if (IsValid(PlayerInfo.Get()))
|
||||
if (!IsValid(PlayerInfo.Get()))
|
||||
{
|
||||
PlayerInfo = NewObject<UPlayerInfoSaveGame>(this);
|
||||
}
|
||||
// 保存任务数据
|
||||
if (UQuestManager* QuestManager = GetGameInstance()->GetSubsystem<UQuestManager>())
|
||||
{
|
||||
PlayerInfo->QuestSaveData = QuestManager->GetQuestSaveData();
|
||||
}
|
||||
|
||||
if (UGameplayStatics::SaveGameToSlot(PlayerInfo.Get(), SaveGameSlotName, 0))
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("存档保存成功"));
|
||||
@ -27,11 +42,6 @@ void UGameInfoManager::SaveGameInfo()
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("存档保存失败"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("存档保存失败, PlayerInfo为空"));
|
||||
}
|
||||
}
|
||||
|
||||
bool UGameInfoManager::LoadGameInfo()
|
||||
@ -39,8 +49,26 @@ bool UGameInfoManager::LoadGameInfo()
|
||||
if (UGameplayStatics::DoesSaveGameExist(SaveGameSlotName, 0))
|
||||
{
|
||||
PlayerInfo = Cast<UPlayerInfoSaveGame>(UGameplayStatics::LoadGameFromSlot(SaveGameSlotName, 0));
|
||||
|
||||
// 加载任务数据
|
||||
if (UQuestManager* QuestManager = GetGameInstance()->GetSubsystem<UQuestManager>())
|
||||
{
|
||||
if (PlayerInfo && GetGameInstance())
|
||||
{
|
||||
QuestManager->LoadFromSaveData(PlayerInfo->QuestSaveData);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 加载任务数据
|
||||
if (UQuestManager* QuestManager = GetGameInstance()->GetSubsystem<UQuestManager>())
|
||||
{
|
||||
TArray<FQuestSaveData> SaveData;
|
||||
QuestManager->LoadFromSaveData(SaveData);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,9 @@ class PROJECTFISH_API UGameInfoManager : public UGameInstanceSubsystem
|
||||
public:
|
||||
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||
|
||||
protected:
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void NewSaveGame();
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SaveGameInfo();
|
||||
UFUNCTION(BlueprintCallable)
|
||||
@ -30,5 +32,6 @@ protected:
|
||||
protected:
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
TObjectPtr<class UPlayerInfoSaveGame> PlayerInfo;
|
||||
|
||||
static FString SaveGameSlotName;
|
||||
};
|
||||
|
||||
@ -0,0 +1,449 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "QuestManager.h"
|
||||
|
||||
#include "GameInfoManager.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(bool bSaveGameInfo)
|
||||
{
|
||||
for (auto QuestAsset : QuestAssets)
|
||||
{
|
||||
if (!ActiveQuestsMap.Find(QuestAsset->QuestID) && !CompletedQuestIDs.Contains(QuestAsset->QuestID))
|
||||
{
|
||||
//任务不在当前已激活的任务 和 已完成的任务列表中
|
||||
AcceptQuest(QuestAsset, bSaveGameInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool UQuestManager::AcceptQuest(UQuestAsset* QuestAsset, bool bSaveGameInfo )
|
||||
{
|
||||
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());
|
||||
|
||||
if (bSaveGameInfo)
|
||||
{
|
||||
//更新存档数据
|
||||
GetGameInstance()->GetSubsystem<UGameInfoManager>()->SaveGameInfo();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
//更新存档数据
|
||||
GetGameInstance()->GetSubsystem<UGameInfoManager>()->SaveGameInfo();
|
||||
|
||||
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);
|
||||
//更新存档数据
|
||||
GetGameInstance()->GetSubsystem<UGameInfoManager>()->SaveGameInfo();
|
||||
|
||||
|
||||
|
||||
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(FGameplayTag TargetTag, 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.TargetTag == TargetTag)
|
||||
{
|
||||
// 增加进度
|
||||
int32 NewProgress = RuntimeData.ObjectiveProgress[i].CurrentProgress + ProgressDelta;
|
||||
UpdateObjectiveProgress(Pair.Key, i, NewProgress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//检测是否有其他可接受的任务
|
||||
CheckAcceptableQuests();
|
||||
}
|
||||
|
||||
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::GetFollowingQuests() const
|
||||
{
|
||||
TArray<UQuestAsset*> Result;
|
||||
for (const TPair<int32, FQuestRuntimeData>& Pair : ActiveQuestsMap)
|
||||
{
|
||||
if (FollowingQuestIDs.Contains(Pair.Key))
|
||||
{
|
||||
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::GetQuestRuntimeData(int32 QuestID, FQuestRuntimeData& OutData) const
|
||||
{
|
||||
const FQuestRuntimeData* RuntimeData = ActiveQuestsMap.Find(QuestID);
|
||||
if (RuntimeData)
|
||||
{
|
||||
OutData = *RuntimeData;
|
||||
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 < Data.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(true);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
160
ProjectFish/Source/ProjectFish/Gameplay/Subsystem/QuestManager.h
Normal file
160
ProjectFish/Source/ProjectFish/Gameplay/Subsystem/QuestManager.h
Normal file
@ -0,0 +1,160 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Subsystems/GameInstanceSubsystem.h"
|
||||
#include "../../Quest/QuestTypes.h"
|
||||
#include "QuestManager.generated.h"
|
||||
|
||||
class UQuestAsset;
|
||||
|
||||
/**
|
||||
* 任务运行时数据
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FQuestRuntimeData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** 任务资产引用 */
|
||||
UPROPERTY(BlueprintReadOnly)
|
||||
TObjectPtr<UQuestAsset> QuestAsset;
|
||||
|
||||
/** 任务状态 */
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
EQuestState State = EQuestState::NotStarted;
|
||||
|
||||
/** 目标进度 */
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
TArray<FQuestProgress> ObjectiveProgress;
|
||||
};
|
||||
|
||||
// 任务事件委托
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnQuestStateChanged, int32, QuestID);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnQuestObjectiveUpdated, int32, QuestID, int32, ObjectiveIndex);
|
||||
|
||||
/**
|
||||
* 任务管理器子系统
|
||||
* 负责管理所有任务的状态、进度和存档
|
||||
*/
|
||||
UCLASS()
|
||||
class PROJECTFISH_API UQuestManager : public UGameInstanceSubsystem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||
virtual void Deinitialize() override;
|
||||
|
||||
// ========== 任务操作 ==========
|
||||
/** 加载本地所有任务 */
|
||||
void LoadAllQuests();
|
||||
|
||||
/** 检测所有可接收的任务 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Quest")
|
||||
void CheckAcceptableQuests(bool bSaveGameInfo = false);
|
||||
|
||||
/** 接受任务 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Quest")
|
||||
bool AcceptQuest(UQuestAsset* QuestAsset, bool bSaveGameInfo = false);
|
||||
|
||||
/** 接受任务 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Quest")
|
||||
bool FollowQuest(int32 QuestID, bool Follow);
|
||||
|
||||
/** 完成任务 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Quest")
|
||||
bool CompleteQuest(int32 QuestID);
|
||||
|
||||
/** 放弃任务 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Quest")
|
||||
bool AbandonQuest(int32 QuestID);
|
||||
|
||||
// ========== 任务进度 ==========
|
||||
|
||||
/** 更新任务目标进度(收集物品、击败敌人、到达地点) */
|
||||
UFUNCTION(BlueprintCallable, Category = "Quest")
|
||||
void UpdateObjectiveProgress(int32 QuestID, int32 ObjectiveIndex, int32 Progress);
|
||||
|
||||
/** 通过目标ID更新进度(自动查找对应目标) */
|
||||
UFUNCTION(BlueprintCallable, Category = "Quest")
|
||||
void UpdateObjectiveByTargetID(FGameplayTag TargetTag, int32 ProgressDelta = 1);
|
||||
|
||||
// ========== 任务查询 ==========
|
||||
|
||||
/** 获取任务状态 */
|
||||
UFUNCTION(BlueprintPure, Category = "Quest")
|
||||
EQuestState GetQuestState(int32 QuestID) const;
|
||||
|
||||
/** 任务是否正在被追踪 */
|
||||
UFUNCTION(BlueprintPure, Category = "Quest")
|
||||
bool IsQuestFollowing(int32 QuestID) const;
|
||||
|
||||
/** 获取所有进行中的任务 */
|
||||
UFUNCTION(BlueprintPure, Category = "Quest")
|
||||
TArray<UQuestAsset*> GetActiveQuests() const;
|
||||
|
||||
/** 获取所有追踪的任务 */
|
||||
UFUNCTION(BlueprintPure, Category = "Quest")
|
||||
TArray<UQuestAsset*> GetFollowingQuests() const;
|
||||
|
||||
/** 获取所有已完成的任务 */
|
||||
UFUNCTION(BlueprintPure, Category = "Quest")
|
||||
TArray<UQuestAsset*> GetCompletedQuests() const;
|
||||
|
||||
/** 获取任务进度 */
|
||||
UFUNCTION(BlueprintPure, Category = "Quest")
|
||||
bool GetQuestProgress(int32 QuestID, TArray<FQuestProgress>& OutProgress) const;
|
||||
|
||||
/** 获取任务进度 */
|
||||
UFUNCTION(BlueprintPure, Category = "Quest")
|
||||
bool GetQuestRuntimeData(int32 QuestID, FQuestRuntimeData& OutData) const;
|
||||
|
||||
/** 检查是否可以接受任务(前置任务检查) */
|
||||
UFUNCTION(BlueprintPure, Category = "Quest")
|
||||
bool CanAcceptQuest(UQuestAsset* QuestAsset) const;
|
||||
|
||||
// ========== 存档相关 ==========
|
||||
|
||||
/** 获取所有任务的存档数据 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Quest")
|
||||
TArray<FQuestSaveData> GetQuestSaveData() const;
|
||||
|
||||
/** 从存档数据加载任务 */
|
||||
UFUNCTION(BlueprintCallable, Category = "Quest")
|
||||
void LoadFromSaveData(const TArray<FQuestSaveData>& SaveData);
|
||||
|
||||
// ========== 事件 ==========
|
||||
|
||||
/** 任务状态改变事件 */
|
||||
UPROPERTY(BlueprintAssignable, Category = "Quest|Events")
|
||||
FOnQuestStateChanged OnQuestStateChanged;
|
||||
|
||||
/** 任务目标更新事件 */
|
||||
UPROPERTY(BlueprintAssignable, Category = "Quest|Events")
|
||||
FOnQuestObjectiveUpdated OnQuestObjectiveUpdated;
|
||||
|
||||
protected:
|
||||
/** 检查任务是否完成 */
|
||||
void CheckQuestCompletion(int32 QuestID);
|
||||
|
||||
/** 初始化任务运行时数据 */
|
||||
FQuestRuntimeData CreateRuntimeData(UQuestAsset* QuestAsset);
|
||||
|
||||
private:
|
||||
/** 运行时任务数据映射 (QuestID -> RuntimeData) */
|
||||
UPROPERTY()
|
||||
TMap<int32, FQuestRuntimeData> ActiveQuestsMap;
|
||||
|
||||
/** 正在追踪的任务列表 */
|
||||
UPROPERTY(BlueprintReadOnly, meta = (AllowPrivateAccess = true))
|
||||
TSet<int32> FollowingQuestIDs;
|
||||
|
||||
/** 已完成的任务ID列表 */
|
||||
UPROPERTY()
|
||||
TSet<int32> CompletedQuestIDs;
|
||||
|
||||
UPROPERTY()
|
||||
TArray<UQuestAsset*> QuestAssets;
|
||||
};
|
||||
140
ProjectFish/Source/ProjectFish/Quest/QuestTypes.h
Normal file
140
ProjectFish/Source/ProjectFish/Quest/QuestTypes.h
Normal file
@ -0,0 +1,140 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "QuestTypes.generated.h"
|
||||
|
||||
/**
|
||||
* 任务目标类型
|
||||
*/
|
||||
UENUM(BlueprintType)
|
||||
enum class EQuestObjectiveType : uint8
|
||||
{
|
||||
CollectItem UMETA(DisplayName = "收集物品并交付"),
|
||||
DefeatEnemy UMETA(DisplayName = "战胜指定的敌人"),
|
||||
ReachLocation UMETA(DisplayName = "到达指定地点")
|
||||
};
|
||||
|
||||
/**
|
||||
* 任务状态
|
||||
*/
|
||||
UENUM(BlueprintType)
|
||||
enum class EQuestState : uint8
|
||||
{
|
||||
NotStarted UMETA(DisplayName = "未开始"),
|
||||
InProgress UMETA(DisplayName = "进行中"),
|
||||
Completed UMETA(DisplayName = "已完成"),
|
||||
Failed UMETA(DisplayName = "失败")
|
||||
};
|
||||
|
||||
/**
|
||||
* 任务奖励数据
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FQuestReward
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** 奖励物品资产ID */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Quest")
|
||||
FPrimaryAssetId RewardItemAssetId;
|
||||
|
||||
/** 奖励数量 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Quest")
|
||||
int32 Amount = 1;
|
||||
|
||||
/** 奖励金币 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Quest")
|
||||
int32 GoldAmount = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* 任务目标数据
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FQuestTargetInfo
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** 目标名称*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Quest")
|
||||
FText QuestTargetName;
|
||||
|
||||
/** 目标ID */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Quest")
|
||||
FGameplayTag TargetTag;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* 任务目标数据
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FQuestObjective
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** 目标类型 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Quest")
|
||||
EQuestObjectiveType ObjectiveType = EQuestObjectiveType::CollectItem;
|
||||
|
||||
/** 目标描述 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Quest")
|
||||
FText ObjectiveDescription;
|
||||
|
||||
/** 目标ID(物品ID、敌人ID、地点Tag等) */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Quest")
|
||||
FQuestTargetInfo TargetID;
|
||||
|
||||
/** 需要完成的数量 */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Quest")
|
||||
int32 RequiredAmount = 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* 任务进度数据(运行时)
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FQuestProgress
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** 当前进度 */
|
||||
UPROPERTY(BlueprintReadWrite, Category = "Quest")
|
||||
int32 CurrentProgress = 0;
|
||||
|
||||
/** 是否已完成 */
|
||||
UPROPERTY(BlueprintReadWrite, Category = "Quest")
|
||||
bool bCompleted = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 任务存档数据
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FQuestSaveData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** 任务ID */
|
||||
UPROPERTY(SaveGame, BlueprintReadWrite)
|
||||
int32 QuestID = 0;
|
||||
|
||||
/** 是否正在追踪 */
|
||||
UPROPERTY(SaveGame, BlueprintReadWrite)
|
||||
bool bFollowing = false;
|
||||
|
||||
/** 任务状态 */
|
||||
UPROPERTY(SaveGame, BlueprintReadWrite)
|
||||
EQuestState QuestState = EQuestState::NotStarted;
|
||||
|
||||
/** 目标进度列表 */
|
||||
UPROPERTY(SaveGame, BlueprintReadWrite)
|
||||
TArray<int32> ObjectiveProgress;
|
||||
|
||||
/** 目标完成状态列表 */
|
||||
UPROPERTY(SaveGame, BlueprintReadWrite)
|
||||
TArray<bool> ObjectiveCompleted;
|
||||
};
|
||||
@ -0,0 +1,14 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "AssetActions/QuestAssetTypeAction.h"
|
||||
#include "ProjectFish/DataAsset/QuestAsset.h"
|
||||
|
||||
UClass* FQuestAssetTypeAction::GetSupportedClass() const
|
||||
{
|
||||
return UQuestAsset::StaticClass();
|
||||
}
|
||||
|
||||
uint32 FQuestAssetTypeAction::GetCategories()
|
||||
{
|
||||
return MyAssetCategory;
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Factory/QuestAssetFactory.h"
|
||||
#include "ProjectFish/DataAsset/QuestAsset.h"
|
||||
#include "AssetRegistry/AssetRegistryModule.h"
|
||||
#include "AssetRegistry/AssetData.h"
|
||||
|
||||
UQuestAssetFactory::UQuestAssetFactory()
|
||||
{
|
||||
SupportedClass = UQuestAsset::StaticClass();
|
||||
bCreateNew = true;
|
||||
bEditAfterNew = true;
|
||||
}
|
||||
|
||||
UObject* UQuestAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags,
|
||||
UObject* Context, FFeedbackContext* Warn)
|
||||
{
|
||||
UQuestAsset* NewQuestAsset = NewObject<UQuestAsset>(InParent, Class, Name, Flags | RF_Transactional);
|
||||
|
||||
// 自动生成唯一的 QuestID
|
||||
if (NewQuestAsset)
|
||||
{
|
||||
NewQuestAsset->QuestID = GenerateUniqueQuestID();
|
||||
}
|
||||
|
||||
return NewQuestAsset;
|
||||
}
|
||||
|
||||
int32 UQuestAssetFactory::GenerateUniqueQuestID() const
|
||||
{
|
||||
int32 MaxQuestID = 0;
|
||||
|
||||
// 获取资产注册表模块
|
||||
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
|
||||
IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
|
||||
|
||||
// 查找所有 QuestAsset 资产
|
||||
TArray<FAssetData> AssetDataList;
|
||||
AssetRegistry.GetAssetsByClass(UQuestAsset::StaticClass()->GetClassPathName(), AssetDataList, true);
|
||||
|
||||
// 遍历所有已存在的任务资产,找到最大的 QuestID
|
||||
for (const FAssetData& AssetData : AssetDataList)
|
||||
{
|
||||
if (UQuestAsset* QuestAsset = Cast<UQuestAsset>(AssetData.GetAsset()))
|
||||
{
|
||||
if (QuestAsset->QuestID > MaxQuestID)
|
||||
{
|
||||
MaxQuestID = QuestAsset->QuestID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 返回最大ID + 1,如果没有现有任务则从1开始
|
||||
return MaxQuestID + 1;
|
||||
}
|
||||
|
||||
bool UQuestAssetFactory::ShouldShowInNewMenu() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -4,12 +4,13 @@
|
||||
#include "DataTableRowSelectorCustomization.h"
|
||||
#include "AssetActions/BagConfigAssetTypeAction.h"
|
||||
#include "AssetActions/ShapeAssetTypeAction.h"
|
||||
#include "AssetActions/SkillAssetTypeAction.h"
|
||||
#include "AssetActions/QuestAssetTypeAction.h"
|
||||
#include "AssetRegistry/AssetRegistryModule.h"
|
||||
#include "ProjectFish/DataAsset/ShapeAsset.h"
|
||||
#include "ProjectFish/DataAsset/BagConfigAsset.h"
|
||||
#include "../Public/Thumbnail/ShapeAssetThumbnailRenderer.h"
|
||||
#include "../Public/Thumbnail/BagConfigThumbnailRenderer.h"
|
||||
#include "AssetActions/SkillAssetTypeAction.h"
|
||||
#include "ProjectFish/DataAsset/BagConfigAsset.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FProjectFishEditorModule"
|
||||
|
||||
@ -42,7 +43,7 @@ void FProjectFishEditorModule::RegisterAssetTypeActions()
|
||||
FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
|
||||
IAssetTools& AssetTools = AssetToolsModule.Get();
|
||||
//注册背包形状的菜单
|
||||
EAssetTypeCategories::Type BogShapeAssetCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("BagShape")), FText::FromString(TEXT("BagSystem")));
|
||||
EAssetTypeCategories::Type BogShapeAssetCategory = AssetTools.RegisterAdvancedAssetCategory(FName(TEXT("BagShape")), FText::FromString(TEXT("ProjectFish")));
|
||||
//BagShape
|
||||
TSharedRef<FAssetTypeActions_Base> BagShapeAction = MakeShareable(new FShapeAssetTypeAction(BogShapeAssetCategory));
|
||||
AssetTools.RegisterAssetTypeActions(BagShapeAction);
|
||||
@ -58,6 +59,11 @@ void FProjectFishEditorModule::RegisterAssetTypeActions()
|
||||
TSharedRef<FAssetTypeActions_Base> SkillAssetAction = MakeShareable(new FSkillAssetTypeAction(BogShapeAssetCategory));
|
||||
AssetTools.RegisterAssetTypeActions(SkillAssetAction);
|
||||
CreatedAssetTypeActions.Add(SkillAssetAction);
|
||||
|
||||
//注册任务资源菜单
|
||||
TSharedRef<FAssetTypeActions_Base> QuestAssetAction = MakeShareable(new FQuestAssetTypeAction(BogShapeAssetCategory));
|
||||
AssetTools.RegisterAssetTypeActions(QuestAssetAction);
|
||||
CreatedAssetTypeActions.Add(QuestAssetAction);
|
||||
}
|
||||
|
||||
void FProjectFishEditorModule::UnregisterAssetTypeActions()
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "AssetTypeActions_Base.h"
|
||||
|
||||
/**
|
||||
* 任务资产类型动作
|
||||
*/
|
||||
class PROJECTFISHEDITOR_API FQuestAssetTypeAction : public FAssetTypeActions_Base
|
||||
{
|
||||
public:
|
||||
FQuestAssetTypeAction(EAssetTypeCategories::Type InAssetCategory)
|
||||
: MyAssetCategory(InAssetCategory)
|
||||
{
|
||||
}
|
||||
|
||||
virtual FText GetName() const override { return FText::FromString("Quest Asset"); }
|
||||
virtual FColor GetTypeColor() const override { return FColor(255, 215, 0); } // 金色
|
||||
virtual UClass* GetSupportedClass() const override;
|
||||
virtual uint32 GetCategories() override;
|
||||
virtual bool CanFilter() override { return true; }
|
||||
|
||||
private:
|
||||
EAssetTypeCategories::Type MyAssetCategory;
|
||||
};
|
||||
@ -0,0 +1,27 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Factories/Factory.h"
|
||||
#include "QuestAssetFactory.generated.h"
|
||||
|
||||
/**
|
||||
* 任务资产工厂
|
||||
*/
|
||||
UCLASS()
|
||||
class PROJECTFISHEDITOR_API UQuestAssetFactory : public UFactory
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UQuestAssetFactory();
|
||||
|
||||
// UFactory interface
|
||||
virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;
|
||||
virtual bool ShouldShowInNewMenu() const override;
|
||||
|
||||
private:
|
||||
/** 生成唯一的任务ID */
|
||||
int32 GenerateUniqueQuestID() const;
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user