From ca5b081eaf9cf3bece761cc738fd3b1e87dc3e00 Mon Sep 17 00:00:00 2001 From: Shun Moriya <23472415+shun126@users.noreply.github.com> Date: Thu, 20 Apr 2023 01:32:32 +0900 Subject: [PATCH] Copy LevelStreaming actors in editor mode to level --- .../Private/DungeonGenerateActor.cpp | 22 +- .../Private/DungeonGenerateParameter.cpp | 5 + .../Private/DungeonGeneratorCore.cpp | 129 +++++--- .../Private/DungeonLevelStreamingDynamic.cpp | 6 + .../Public/DungeonGenerateParameter.h | 6 + .../Public/DungeonGeneratorCore.h | 6 +- .../Public/DungeonLevelStreamingDynamic.h | 26 ++ .../DungeonGenerateParameterTypeActions.cpp | 2 +- .../Private/DungeonGeneratorEditorModule.cpp | 277 ++++++++++-------- .../Private/DungeonRoomAssetTypeActions.cpp | 2 +- .../Public/DungeonGeneratorEditorModule.h | 24 ++ 11 files changed, 338 insertions(+), 167 deletions(-) create mode 100644 Source/DungeonGenerator/Private/DungeonLevelStreamingDynamic.cpp create mode 100644 Source/DungeonGenerator/Public/DungeonLevelStreamingDynamic.h diff --git a/Source/DungeonGenerator/Private/DungeonGenerateActor.cpp b/Source/DungeonGenerator/Private/DungeonGenerateActor.cpp index 23885ff..21f07e3 100644 --- a/Source/DungeonGenerator/Private/DungeonGenerateActor.cpp +++ b/Source/DungeonGenerator/Private/DungeonGenerateActor.cpp @@ -341,15 +341,18 @@ void ADungeonGenerateActor::DestroyImplementation() */ void ADungeonGenerateActor::MovePlayerStart() { - if (mDungeonGeneratorCore != nullptr) + if (DungeonGenerateParameter && DungeonGenerateParameter->IsMovePlayerStartToStartingPoint()) { - if (OnMovePlayerStart.IsBound()) + if (mDungeonGeneratorCore) { - OnMovePlayerStart.Broadcast(mDungeonGeneratorCore->GetStartLocation()); - } - else - { - mDungeonGeneratorCore->MovePlayerStart(); + if (OnMovePlayerStart.IsBound()) + { + OnMovePlayerStart.Broadcast(mDungeonGeneratorCore->GetStartLocation()); + } + else + { + mDungeonGeneratorCore->MovePlayerStart(); + } } } } @@ -378,11 +381,6 @@ void ADungeonGenerateActor::Tick(float DeltaSeconds) { mPostGenerated = true; PostGenerateImplementation(); - -#if !WITH_EDITOR - // ティック無効化 - PrimaryActorTick.bCanEverTick = false; -#endif } // 部屋の生成通知 diff --git a/Source/DungeonGenerator/Private/DungeonGenerateParameter.cpp b/Source/DungeonGenerator/Private/DungeonGenerateParameter.cpp index d920bd6..94baf91 100644 --- a/Source/DungeonGenerator/Private/DungeonGenerateParameter.cpp +++ b/Source/DungeonGenerator/Private/DungeonGenerateParameter.cpp @@ -314,6 +314,11 @@ const FDungeonDoorActorParts* UDungeonGenerateParameter::SelectDoorParts(const s return SelectParts(gridIndex, grid, random, DoorParts, DoorPartsSelectionMethod); } +bool UDungeonGenerateParameter::IsMovePlayerStartToStartingPoint() const noexcept +{ + return MovePlayerStartToStartingPoint; +} + const FDungeonActorPartsWithDirection& UDungeonGenerateParameter::GetStartParts() const { return StartParts; diff --git a/Source/DungeonGenerator/Private/DungeonGeneratorCore.cpp b/Source/DungeonGenerator/Private/DungeonGeneratorCore.cpp index 2ec3ebd..41f84ba 100644 --- a/Source/DungeonGenerator/Private/DungeonGeneratorCore.cpp +++ b/Source/DungeonGenerator/Private/DungeonGeneratorCore.cpp @@ -7,6 +7,7 @@ All Rights Reserved. #include "DungeonGeneratorCore.h" #include "DungeonGenerateParameter.h" #include "DungeonDoor.h" +#include "DungeonLevelStreamingDynamic.h" #include "DungeonRoomProps.h" #include "DungeonRoomSensor.h" #include "Core/Debug/Debug.h" @@ -28,6 +29,7 @@ All Rights Reserved. #if WITH_EDITOR // UnrealEd +#include #include #endif @@ -1021,9 +1023,6 @@ bool CDungeonGeneratorCore::RequestStreamLevel(const FSoftObjectPath& levelPath, if (requestStreamLevel != mRequestLoadStreamLevels.end()) return false; - if (mLoadedStreamLevels.Contains(levelPath)) - return false; - mRequestLoadStreamLevels.emplace_back(levelPath, levelLocation); return true; @@ -1036,44 +1035,89 @@ void CDungeonGeneratorCore::AsyncLoadStreamLevels() LoadStreamLevelParameter requestStreamLevel = mRequestLoadStreamLevels.front(); mRequestLoadStreamLevels.pop_front(); - LoadStreamLevel(requestStreamLevel.mPath, requestStreamLevel.mLocation); + if (FindLoadedStreamLevel(requestStreamLevel.mPath) == nullptr) + { + UWorld* world = mWorld.Get(); + if (IsValid(world)) + { + const FTransform transform(FRotator::ZeroRotator, requestStreamLevel.mLocation); + ULevelStreamingDynamic::FLoadLevelInstanceParams parameter(world, requestStreamLevel.mPath.GetLongPackageName(), transform); + parameter.OptionalLevelStreamingClass = UDungeonLevelStreamingDynamic::StaticClass(); + bool bSuccess = false; + ULevelStreamingDynamic* levelStreaming = ULevelStreamingDynamic::LoadLevelInstance(parameter, bSuccess); + if (bSuccess && IsValid(levelStreaming)) + { + mLoadedStreamLevels.Add(levelStreaming); + + DUNGEON_GENERATOR_LOG(TEXT("Load Level (%s)"), *requestStreamLevel.mPath.GetLongPackageName()); + } + else + { + DUNGEON_GENERATOR_ERROR(TEXT("Failed to Load Level (%s)"), *requestStreamLevel.mPath.GetLongPackageName()); + } + } + } } } void CDungeonGeneratorCore::SyncLoadStreamLevels() { - for (const auto& requestStreamLevel : mRequestLoadStreamLevels) + UWorld* world = mWorld.Get(); + if (IsValid(world)) { - LoadStreamLevel(requestStreamLevel.mPath, requestStreamLevel.mLocation); - } - mRequestLoadStreamLevels.clear(); -} + TArray moveActors; -void CDungeonGeneratorCore::LoadStreamLevel(const FSoftObjectPath& levelPath, const FVector& levelLocation) -{ - if (!mLoadedStreamLevels.Contains(levelPath)) - { - UWorld* world = mWorld.Get(); - if (IsValid(world)) + for (const auto& requestStreamLevel : mRequestLoadStreamLevels) { - bool bSuccess; - /*ULevelStreamingDynamic* levelStreaming = */ ULevelStreamingDynamic::LoadLevelInstanceBySoftObjectPtr( - world, - TSoftObjectPtr(levelPath), - levelLocation, - FRotator::ZeroRotator, - bSuccess - ); - if (bSuccess) + if (FindLoadedStreamLevel(requestStreamLevel.mPath)) + continue; + + const FTransform transform(FRotator::ZeroRotator, requestStreamLevel.mLocation); + ULevelStreamingDynamic::FLoadLevelInstanceParams parameter(world, requestStreamLevel.mPath.GetLongPackageName(), transform); + parameter.OptionalLevelStreamingClass = UDungeonLevelStreamingDynamic::StaticClass(); + bool bSuccess = false; + ULevelStreamingDynamic* levelStreaming = ULevelStreamingDynamic::LoadLevelInstance(parameter, bSuccess); + if (bSuccess && IsValid(levelStreaming)) { - mLoadedStreamLevels.Emplace(levelPath); - DUNGEON_GENERATOR_LOG(TEXT("Load Level (%s)"), *levelPath.GetLongPackageName()); + levelStreaming->bShouldBlockOnLoad = true; + world->FlushLevelStreaming(); + //world->UpdateLevelStreaming(); + + ULevel* loadedLevel = levelStreaming->GetLoadedLevel(); + if (IsValid(loadedLevel)) + { +#if WITH_EDITOR + FString path, filename, extension; + FPaths::Split(levelStreaming->PackageNameToLoad.ToString(), path, filename, extension); +#endif + for (AActor* actor : loadedLevel->Actors) + { + actor->Tags.Add(GetDungeonGeneratorTag()); +#if WITH_EDITOR + const FName folderPath(FString(TEXT("Dungeon/Levels/")) + filename); + actor->SetFolderPath(folderPath); +#endif + } + + moveActors.Append(loadedLevel->Actors); + } + + mLoadedStreamLevels.Add(levelStreaming); + + DUNGEON_GENERATOR_LOG(TEXT("Load Level (%s)"), *requestStreamLevel.mPath.GetLongPackageName()); } else { - DUNGEON_GENERATOR_ERROR(TEXT("Failed to Load Level (%s)"), *levelPath.GetLongPackageName()); + DUNGEON_GENERATOR_ERROR(TEXT("Failed to Load Level (%s)"), *requestStreamLevel.mPath.GetLongPackageName()); } } + + if (moveActors.Num() > 0) + { + EditorLevelUtils::MoveActorsToLevel(moveActors, world->PersistentLevel); + } + + mRequestLoadStreamLevels.clear(); } } @@ -1084,10 +1128,9 @@ void CDungeonGeneratorCore::UnloadStreamLevels() UWorld* world = mWorld.Get(); if (IsValid(world)) { - for (const auto& levelPath : mLoadedStreamLevels) + for (const TSoftObjectPtr& streamLevel : mLoadedStreamLevels) { - FLatentActionInfo LatentInfo; - UGameplayStatics::UnloadStreamLevelBySoftObjectPtr(world, TSoftObjectPtr(levelPath), LatentInfo, false); + world->RemoveStreamingLevel(streamLevel.Get()); } mLoadedStreamLevels.Empty(); } @@ -1095,19 +1138,37 @@ void CDungeonGeneratorCore::UnloadStreamLevels() void CDungeonGeneratorCore::UnloadStreamLevel(const FSoftObjectPath& levelPath) { + SyncLoadStreamLevels(); + UWorld* world = mWorld.Get(); if (IsValid(world)) { - if (mLoadedStreamLevels.Contains(levelPath)) + for (int32 i = 0; i < mLoadedStreamLevels.Num(); ++i) { - FLatentActionInfo LatentInfo; - UGameplayStatics::UnloadStreamLevelBySoftObjectPtr(world, TSoftObjectPtr(levelPath), LatentInfo, false); + const TSoftObjectPtr& loadedStreamLevel = mLoadedStreamLevels[i]; + if (loadedStreamLevel->PackageNameToLoad == levelPath.GetAssetPathName()) + { + world->RemoveStreamingLevel(loadedStreamLevel.Get()); - mLoadedStreamLevels.Remove(levelPath); + mLoadedStreamLevels.RemoveAt(i); + break; + } } } } +TSoftObjectPtr CDungeonGeneratorCore::FindLoadedStreamLevel(const FSoftObjectPath& levelPath) const +{ + for (const TSoftObjectPtr& loadedStreamLevel : mLoadedStreamLevels) + { + if (loadedStreamLevel.IsValid()) + { + if (loadedStreamLevel->PackageNameToLoad == levelPath.GetAssetPathName()) + return loadedStreamLevel; + } + } + return nullptr; +} //////////////////////////////////////////////////////////////////////////////////////////////////// #if WITH_EDITOR diff --git a/Source/DungeonGenerator/Private/DungeonLevelStreamingDynamic.cpp b/Source/DungeonGenerator/Private/DungeonLevelStreamingDynamic.cpp new file mode 100644 index 0000000..cbfbf8f --- /dev/null +++ b/Source/DungeonGenerator/Private/DungeonLevelStreamingDynamic.cpp @@ -0,0 +1,6 @@ +#include "DungeonLevelStreamingDynamic.h" + +UDungeonLevelStreamingDynamic::UDungeonLevelStreamingDynamic(const FObjectInitializer& initializer) + : Super(initializer) +{ +} diff --git a/Source/DungeonGenerator/Public/DungeonGenerateParameter.h b/Source/DungeonGenerator/Public/DungeonGenerateParameter.h index 6b15148..c5477cc 100644 --- a/Source/DungeonGenerator/Public/DungeonGenerateParameter.h +++ b/Source/DungeonGenerator/Public/DungeonGenerateParameter.h @@ -215,6 +215,8 @@ class DUNGEONGENERATOR_API UDungeonGenerateParameter : public UObject const FDungeonDoorActorParts* SelectDoorParts(const size_t gridIndex, const dungeon::Grid& grid, dungeon::Random& random) const; + bool IsMovePlayerStartToStartingPoint() const noexcept; + const FDungeonActorPartsWithDirection& GetStartParts() const; const FDungeonActorPartsWithDirection& GetGoalParts() const; @@ -371,6 +373,10 @@ class DUNGEONGENERATOR_API UDungeonGenerateParameter : public UObject UPROPERTY(EditAnywhere, Category = "DungeonGenerator|Door", BlueprintReadWrite) TArray DoorParts; + // Move PlayerStart to the starting point. + UPROPERTY(EditAnywhere, Category = "DungeonGenerator|Door", BlueprintReadWrite) + bool MovePlayerStartToStartingPoint = true; + // starting point UPROPERTY(EditAnywhere, Category = "DungeonGenerator", BlueprintReadWrite) FDungeonActorPartsWithDirection StartParts; diff --git a/Source/DungeonGenerator/Public/DungeonGeneratorCore.h b/Source/DungeonGenerator/Public/DungeonGeneratorCore.h index 79e644a..95a8350 100644 --- a/Source/DungeonGenerator/Public/DungeonGeneratorCore.h +++ b/Source/DungeonGenerator/Public/DungeonGeneratorCore.h @@ -16,6 +16,7 @@ All Rights Reserved. // Forward declaration class UDungeonGenerateParameter; +class ULevelStreamingDynamic; class UStaticMesh; class ANavMeshBoundsVolume; class AStaticMeshActor; @@ -181,8 +182,8 @@ class DUNGEONGENERATOR_API CDungeonGeneratorCore final : public std::enable_shar void AsyncLoadStreamLevels(); void SyncLoadStreamLevels(); void UnloadStreamLevels(); - void LoadStreamLevel(const FSoftObjectPath& levelPath, const FVector& levelLocation); void UnloadStreamLevel(const FSoftObjectPath& levelPath); + TSoftObjectPtr FindLoadedStreamLevel(const FSoftObjectPath& levelPath) const; //////////////////////////////////////////////////////////////////////////// UTexture2D* GenerateMiniMapTexture(uint32_t worldToTextureScale, uint32_t textureWidthHeight, uint32_t currentLevel) const; @@ -222,7 +223,8 @@ class DUNGEONGENERATOR_API CDungeonGeneratorCore final : public std::enable_shar }; std::list mRequestLoadStreamLevels; - TSet mLoadedStreamLevels; + TArray> mLoadedStreamLevels; + // friend class friend class ADungeonGenerateActor; diff --git a/Source/DungeonGenerator/Public/DungeonLevelStreamingDynamic.h b/Source/DungeonGenerator/Public/DungeonLevelStreamingDynamic.h new file mode 100644 index 0000000..69e2cc7 --- /dev/null +++ b/Source/DungeonGenerator/Public/DungeonLevelStreamingDynamic.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include "DungeonLevelStreamingDynamic.generated.h" + +class ULevelStreamingDynamic; + +UCLASS(Blueprintable, BlueprintType) +class DUNGEONGENERATOR_API UDungeonLevelStreamingDynamic : public ULevelStreamingDynamic +{ + GENERATED_BODY() + +public: + /* + constructor + */ + explicit UDungeonLevelStreamingDynamic(const FObjectInitializer& initializer); + + /* + destructor + */ + virtual ~UDungeonLevelStreamingDynamic() = default; + + //virtual bool ShouldBeAlwaysLoaded() const override { return true; } +}; diff --git a/Source/DungeonGeneratorEditor/Private/DungeonGenerateParameterTypeActions.cpp b/Source/DungeonGeneratorEditor/Private/DungeonGenerateParameterTypeActions.cpp index 087f640..30b539d 100644 --- a/Source/DungeonGeneratorEditor/Private/DungeonGenerateParameterTypeActions.cpp +++ b/Source/DungeonGeneratorEditor/Private/DungeonGenerateParameterTypeActions.cpp @@ -14,7 +14,7 @@ UDungeonGenerateParameterTypeActions::UDungeonGenerateParameterTypeActions(EAsse FColor UDungeonGenerateParameterTypeActions::GetTypeColor() const { - return FColor::Orange; + return FColor::Emerald; } void UDungeonGenerateParameterTypeActions::OpenAssetEditor(const TArray& InObjects, TSharedPtr EditWithinLevelEditor) diff --git a/Source/DungeonGeneratorEditor/Private/DungeonGeneratorEditorModule.cpp b/Source/DungeonGeneratorEditor/Private/DungeonGeneratorEditorModule.cpp index 4fba7aa..9e27d38 100644 --- a/Source/DungeonGeneratorEditor/Private/DungeonGeneratorEditorModule.cpp +++ b/Source/DungeonGeneratorEditor/Private/DungeonGeneratorEditorModule.cpp @@ -31,6 +31,14 @@ static const FName DungeonGeneratorTabName("DungeonGenerator"); #define LOCTEXT_NAMESPACE "FDungeonGenerateEditorModule" +DECLARE_LOG_CATEGORY_EXTERN(DungeonGeneratorLogger, Log, All); +#define DUNGEON_GENERATOR_ERROR(Format, ...) UE_LOG(DungeonGeneratorLogger, Error, Format, ##__VA_ARGS__) +#define DUNGEON_GENERATOR_WARNING(Format, ...) UE_LOG(DungeonGeneratorLogger, Warning, Format, ##__VA_ARGS__) +#define DUNGEON_GENERATOR_DISPLAY(Format, ...) UE_LOG(DungeonGeneratorLogger, Display, Format, ##__VA_ARGS__) +#define DUNGEON_GENERATOR_LOG(Format, ...) UE_LOG(DungeonGeneratorLogger, Log, Format, ##__VA_ARGS__) +#define DUNGEON_GENERATOR_VERBOSE(Format, ...) UE_LOG(DungeonGeneratorLogger, Verbose, Format, ##__VA_ARGS__) +DEFINE_LOG_CATEGORY(DungeonGeneratorLogger); + void FDungeonGenerateEditorModule::StartupModule() { FDungeonGeneratorStyle::Initialize(); @@ -145,7 +153,7 @@ TSharedRef FDungeonGenerateEditorModule::OnSpawnPluginTab(const FSpawn .FillHeight(1.f) .Padding(2.f) [ - SNew(SButton) + SAssignNew(mGenerateDungeonButton, SButton) .Text(LOCTEXT("GenerateDungeonButton", "Generate dungeon")) .OnClicked_Raw(this, &FDungeonGenerateEditorModule::OnClickedGenerateButton) ] @@ -156,7 +164,7 @@ TSharedRef FDungeonGenerateEditorModule::OnSpawnPluginTab(const FSpawn .Padding(2.f) [ SNew(SButton) - .Text(LOCTEXT("GenerateDungeonButton", "Clear dungeon")) + .Text(LOCTEXT("ClearDungeonButton", "Clear dungeon")) .OnClicked_Raw(this, &FDungeonGenerateEditorModule::OnClickedClearButton) ] @@ -194,7 +202,7 @@ TSharedRef FDungeonGenerateEditorModule::OnSpawnPluginTab(const FSpawn .FillHeight(1.f) .Padding(2.f) [ - SNew(SButton) + SAssignNew(mGenerateTextureSizeButton, SButton) .Text(LOCTEXT("GenerateTextureSizeButton", "Generate texture with size")) .OnClicked_Raw(this, &FDungeonGenerateEditorModule::OnClickedGenerateTextureWithSizeButton) ] @@ -232,7 +240,7 @@ TSharedRef FDungeonGenerateEditorModule::OnSpawnPluginTab(const FSpawn .FillHeight(1.f) .Padding(2.f) [ - SNew(SButton) + SAssignNew(mGenerateTextureScaleButton, SButton) .Text(LOCTEXT("GenerateTextureScaleButton", "Generate texture with scale")) .OnClicked_Raw(this, &FDungeonGenerateEditorModule::OnClickedGenerateTextureWithScaleButton) ] @@ -261,6 +269,8 @@ TSharedRef FDungeonGenerateEditorModule::OnSpawnPluginTab(const FSpawn ] ]; + SetAssetData(FAssetData()); + return dockTab; } @@ -302,7 +312,13 @@ FString FDungeonGenerateEditorModule::GetObjectPath() const void FDungeonGenerateEditorModule::SetAssetData(const FAssetData& assetData) { - mDungeonGenerateParameter = Cast(assetData.GetAsset()); + UDungeonGenerateParameter* dungeonGenerateParameter = Cast(assetData.GetAsset()); + mDungeonGenerateParameter = dungeonGenerateParameter; + + // Enable buttons the parameters are set. + const bool enabled = dungeonGenerateParameter != nullptr; + mGenerateDungeonButton->SetEnabled(enabled); + UpdateGenerateTextureButtons(); } FReply FDungeonGenerateEditorModule::OnClickedGenerateButton() @@ -310,124 +326,137 @@ FReply FDungeonGenerateEditorModule::OnClickedGenerateButton() UWorld* world = GetWorldFromGameViewport(); if (!IsValid(world)) { - // TODO:エラーログを出力してください + DUNGEON_GENERATOR_ERROR(TEXT("Failed to find World object")); return FReply::Unhandled(); } - // 生成した全アクターを削除 + // Delete all generated actors CDungeonGeneratorCore::DestroySpawnedActors(world); - // アクターを生成 - if (UDungeonGenerateParameter* dungeonGenerateParameter = mDungeonGenerateParameter.Get()) + // Release generated dungeons + if (mDungeonGeneratorCore) { - mDungeonGeneratorCore = std::make_shared(world); - if (mDungeonGeneratorCore == nullptr) - { - // TODO:エラーログを出力してください - return FReply::Unhandled(); - } - - mDungeonGeneratorCore->Create(dungeonGenerateParameter); - mDungeonGeneratorCore->MovePlayerStart(); - - const int32 value = dungeonGenerateParameter->GetGeneratedRandomSeed(); - mRandomSeedValue->SetText(FText::FromString(FString::FromInt(value))); + mDungeonGeneratorCore->UnloadStreamLevels(); + } - // TODO:ミニマップテクスチャの出力を検討して下さい + // Get dungeon generation parameters + const UDungeonGenerateParameter* dungeonGenerateParameter = mDungeonGenerateParameter.Get(); + if (dungeonGenerateParameter == nullptr) + { + DUNGEON_GENERATOR_ERROR(TEXT("Set the DungeonGenerateParameter")); + return FReply::Unhandled(); + } - return FReply::Handled(); + // Generate dungeon + mDungeonGeneratorCore = std::make_shared(world); + if (mDungeonGeneratorCore == nullptr) + { + DUNGEON_GENERATOR_ERROR(TEXT("Failed to create dungeon generator object")); + return FReply::Unhandled(); } - else + if (!mDungeonGeneratorCore->Create(dungeonGenerateParameter)) { - // TODO:エラーログを出力してください + DUNGEON_GENERATOR_ERROR(TEXT("Failed to generate dungeon")); + OnClickedClearButton(); return FReply::Unhandled(); } -} + mDungeonGeneratorCore->SyncLoadStreamLevels(); + if (dungeonGenerateParameter->IsMovePlayerStartToStartingPoint()) + { + mDungeonGeneratorCore->MovePlayerStart(); + } -FReply FDungeonGenerateEditorModule::OnClickedClearButton() -{ - // 生成した全アクターを削除 - CDungeonGeneratorCore::DestroySpawnedActors(GetWorldFromGameViewport()); + // Set random seeds for generated dungeons + const int32 value = dungeonGenerateParameter->GetGeneratedRandomSeed(); + mRandomSeedValue->SetText(FText::FromString(FString::FromInt(value))); - mDungeonGeneratorCore.reset(); + UpdateGenerateTextureButtons(); return FReply::Handled(); } -TOptional FDungeonGenerateEditorModule::OnGetGenerateTextureSize() const +FReply FDungeonGenerateEditorModule::OnClickedClearButton() { - return mGenerateTextureSize; -} + // Release generated dungeons + if (mDungeonGeneratorCore) + { + mDungeonGeneratorCore->UnloadStreamLevels(); + } + mDungeonGeneratorCore.reset(); -void FDungeonGenerateEditorModule::OnSetGenerateTextureSize(int32 value) -{ - mGenerateTextureSize = value; -} + // Delete all generated actors + CDungeonGeneratorCore::DestroySpawnedActors(GetWorldFromGameViewport()); -TOptional FDungeonGenerateEditorModule::OnGetGenerateTextureScale() const -{ - return mGenerateTextureScale; + UpdateGenerateTextureButtons(); + + return FReply::Handled(); } -void FDungeonGenerateEditorModule::OnSetGenerateTextureScale(int32 value) +void FDungeonGenerateEditorModule::UpdateGenerateTextureButtons() { - mGenerateTextureScale = value; + const bool enabled = mDungeonGenerateParameter.IsValid() && mDungeonGeneratorCore != nullptr; + mGenerateTextureSizeButton->SetEnabled(enabled); + mGenerateTextureScaleButton->SetEnabled(enabled); } FReply FDungeonGenerateEditorModule::OnClickedGenerateTextureWithSizeButton() { - if (UDungeonGenerateParameter* dungeonGenerateParameter = mDungeonGenerateParameter.Get()) + const UDungeonGenerateParameter* dungeonGenerateParameter = mDungeonGenerateParameter.Get(); + if (dungeonGenerateParameter == nullptr) { - if (mDungeonGeneratorCore == nullptr) - { - // TODO:エラーログを出力してください - return FReply::Unhandled(); - } + DUNGEON_GENERATOR_ERROR(TEXT("Set the DungeonGenerateParameter")); + return FReply::Unhandled(); + } - UDungeonMiniMapTextureLayer* dungeonMiniMapTextureLayer = NewObject(); - if (!IsValid(dungeonMiniMapTextureLayer)) - { - return FReply::Unhandled(); - } + if (mDungeonGeneratorCore == nullptr) + { + DUNGEON_GENERATOR_ERROR(TEXT("Generate the dungeon first.")); + return FReply::Unhandled(); + } - if (dungeonMiniMapTextureLayer->GenerateMiniMapTextureWithSize(mDungeonGeneratorCore, mGenerateTextureSize, dungeonGenerateParameter->GetGridSize()) == false) - { - // TODO:エラーログを出力してください - return FReply::Unhandled(); - } + UDungeonMiniMapTextureLayer* dungeonMiniMapTextureLayer = NewObject(); + if (!IsValid(dungeonMiniMapTextureLayer)) + { + DUNGEON_GENERATOR_ERROR(TEXT("Failed to create DungeonMiniMapTextureLayer object")); + return FReply::Unhandled(); + } - return SaveTextures(dungeonMiniMapTextureLayer); + if (!dungeonMiniMapTextureLayer->GenerateMiniMapTextureWithSize(mDungeonGeneratorCore, mGenerateTextureSize, dungeonGenerateParameter->GetGridSize())) + { + return FReply::Unhandled(); } - return FReply::Unhandled(); + return SaveTextures(dungeonMiniMapTextureLayer); } FReply FDungeonGenerateEditorModule::OnClickedGenerateTextureWithScaleButton() { - if (UDungeonGenerateParameter* dungeonGenerateParameter = mDungeonGenerateParameter.Get()) + const UDungeonGenerateParameter* dungeonGenerateParameter = mDungeonGenerateParameter.Get(); + if (dungeonGenerateParameter == nullptr) { - if (mDungeonGeneratorCore == nullptr) - { - // TODO:エラーログを出力してください - return FReply::Unhandled(); - } + DUNGEON_GENERATOR_ERROR(TEXT("Set the DungeonGenerateParameter")); + return FReply::Unhandled(); + } - UDungeonMiniMapTextureLayer* dungeonMiniMapTextureLayer = NewObject(); - if (!IsValid(dungeonMiniMapTextureLayer)) - { - return FReply::Unhandled(); - } + if (mDungeonGeneratorCore == nullptr) + { + DUNGEON_GENERATOR_ERROR(TEXT("Generate the dungeon first.")); + return FReply::Unhandled(); + } - if (dungeonMiniMapTextureLayer->GenerateMiniMapTextureWithScale(mDungeonGeneratorCore, mGenerateTextureScale, dungeonGenerateParameter->GetGridSize()) == false) - { - // TODO:エラーログを出力してください - return FReply::Unhandled(); - } + UDungeonMiniMapTextureLayer* dungeonMiniMapTextureLayer = NewObject(); + if (!IsValid(dungeonMiniMapTextureLayer)) + { + DUNGEON_GENERATOR_ERROR(TEXT("Failed to create DungeonMiniMapTextureLayer object")); + return FReply::Unhandled(); + } - return SaveTextures(dungeonMiniMapTextureLayer); + if (!dungeonMiniMapTextureLayer->GenerateMiniMapTextureWithScale(mDungeonGeneratorCore, mGenerateTextureScale, dungeonGenerateParameter->GetGridSize())) + { + return FReply::Unhandled(); } - return FReply::Unhandled(); + return SaveTextures(dungeonMiniMapTextureLayer); } FReply FDungeonGenerateEditorModule::SaveTextures(const UDungeonMiniMapTextureLayer* dungeonMiniMapTextureLayer) const @@ -441,72 +470,86 @@ FReply FDungeonGenerateEditorModule::SaveTextures(const UDungeonMiniMapTextureLa std::function mFunction; }; + // Mount the package destination const TCHAR* basePath = TEXT("/Game/ProceduralTextures/"); const FString absoluteBasePath = FPaths::ProjectContentDir() + TEXT("/ProceduralTextures/"); FPackageName::RegisterMountPoint(basePath, absoluteBasePath); + // Reserve unmounted package destination Finalizer unmount([basePath, &absoluteBasePath]() { FPackageName::UnRegisterMountPoint(basePath, absoluteBasePath); } ); - TArray packages; - - const int32 floorHeight = dungeonMiniMapTextureLayer->GetFloorHeight(); - for (int32 floor = 0; floor < floorHeight; ++floor) + // Save textures as assets { - const FString packageName = FString::Printf(TEXT("Floor%d"), floor); - const FString packagePath = basePath + packageName; - UPackage* package = CreatePackage(*packagePath); - if (!IsValid(package)) + TArray packages; + + // Generate texture assets per floors + const int32 floorHeight = dungeonMiniMapTextureLayer->GetFloorHeight(); + for (int32 floor = 0; floor < floorHeight; ++floor) { - // TODO:エラーログを出力してください - return FReply::Unhandled(); - } - packages.Add(package); + // Create package + const FString packageName = FString::Printf(TEXT("Floor%d"), floor); + const FString packagePath = basePath + packageName; + UPackage* package = CreatePackage(*packagePath); + if (!IsValid(package)) + { + DUNGEON_GENERATOR_ERROR(TEXT("Failed to create Package")); + return FReply::Unhandled(); + } - package->FullyLoad(); - package->MarkPackageDirty(); + // Load package + package->FullyLoad(); + package->MarkPackageDirty(); - UDungeonMiniMapTexture* dungeonMiniMapTexture = dungeonMiniMapTextureLayer->GetByFloor(floor); + // Get minimap texture + UDungeonMiniMapTexture* dungeonMiniMapTexture = dungeonMiniMapTextureLayer->GetByFloor(floor); + // Duplicate texture object and change to saveable #if UE_VERSION_NEWER_THAN(5, 1, 0) - FName textureName = MakeUniqueObjectName(package, UTexture2D::StaticClass(), FName(*packageName), EUniqueObjectNameOptions::GloballyUnique); + FName textureName = MakeUniqueObjectName(package, UTexture2D::StaticClass(), FName(*packageName), EUniqueObjectNameOptions::GloballyUnique); #else - FName textureName = MakeUniqueObjectName(package, UTexture2D::StaticClass(), FName(*packageName)); + FName textureName = MakeUniqueObjectName(package, UTexture2D::StaticClass(), FName(*packageName)); #endif - UTexture2D* texture = DuplicateObject(dungeonMiniMapTexture->GetTexture(), package, textureName); - texture->SetFlags(RF_Public | RF_Standalone); - texture->ClearFlags(RF_Transient); + UTexture2D* texture = DuplicateObject(dungeonMiniMapTexture->GetTexture(), package, textureName); + texture->SetFlags(RF_Public | RF_Standalone); + texture->ClearFlags(RF_Transient); - FAssetRegistryModule::AssetCreated(texture); + // Register texture objects as assets + FAssetRegistryModule::AssetCreated(texture); - const FString longPackageName = FPackageName::LongPackageNameToFilename(packagePath, FPackageName::GetAssetPackageExtension()); - -#if UE_VERSION_OLDER_THAN(5, 0, 0) - const bool saved = UPackage::SavePackage(package, texture, RF_Public | RF_Standalone, *longPackageName); + // Package and save texture objects + const FString longPackageName = FPackageName::LongPackageNameToFilename(packagePath, FPackageName::GetAssetPackageExtension()); +#if UE_VERSION_NEWER_THAN(5, 1, 0) + FSavePackageArgs saveArgs; + saveArgs.TopLevelFlags = RF_Public | RF_Standalone; + saveArgs.SaveFlags = SAVE_NoError; + const bool saved = UPackage::SavePackage(package, texture, *longPackageName, saveArgs); #else - FSavePackageArgs saveArgs; - saveArgs.TopLevelFlags = RF_Public | RF_Standalone; - saveArgs.SaveFlags = SAVE_NoError; - const bool saved = UPackage::SavePackage(package, texture, *longPackageName, saveArgs); + const bool saved = UPackage::SavePackage(package, texture, RF_Public | RF_Standalone, *longPackageName); #endif - if (saved == false) + if (saved == false) + { + DUNGEON_GENERATOR_ERROR(TEXT("Failed to save Package '%s'"), *longPackageName); + return FReply::Unhandled(); + } + + // Record saved packages + packages.Add(package); + } + + // Unload packages + if (!PackageTools::UnloadPackages(packages)) { - // TODO:エラーログを出力してください + DUNGEON_GENERATOR_ERROR(TEXT("Failed to unload Packages")); return FReply::Unhandled(); } - } - if (!PackageTools::UnloadPackages(packages)) - { - // TODO:エラーログを出力してください - return FReply::Unhandled(); + packages.Empty(); } - packages.Empty(); - return FReply::Handled(); } diff --git a/Source/DungeonGeneratorEditor/Private/DungeonRoomAssetTypeActions.cpp b/Source/DungeonGeneratorEditor/Private/DungeonRoomAssetTypeActions.cpp index 73a73ad..b40a50f 100644 --- a/Source/DungeonGeneratorEditor/Private/DungeonRoomAssetTypeActions.cpp +++ b/Source/DungeonGeneratorEditor/Private/DungeonRoomAssetTypeActions.cpp @@ -14,7 +14,7 @@ FDungeonRoomAssetTypeActions::FDungeonRoomAssetTypeActions(EAssetTypeCategories: FColor FDungeonRoomAssetTypeActions::GetTypeColor() const { - return FColor::Orange; + return FColor::Emerald; } void FDungeonRoomAssetTypeActions::OpenAssetEditor(const TArray& InObjects, TSharedPtr EditWithinLevelEditor) diff --git a/Source/DungeonGeneratorEditor/Public/DungeonGeneratorEditorModule.h b/Source/DungeonGeneratorEditor/Public/DungeonGeneratorEditorModule.h index a6ec32e..bf71d37 100644 --- a/Source/DungeonGeneratorEditor/Public/DungeonGeneratorEditorModule.h +++ b/Source/DungeonGeneratorEditor/Public/DungeonGeneratorEditorModule.h @@ -43,6 +43,7 @@ class FDungeonGenerateEditorModule : public IModuleInterface TOptional OnGetGenerateTextureScale() const; void OnSetGenerateTextureScale(int32 value); + void UpdateGenerateTextureButtons(); FReply OnClickedGenerateTextureWithSizeButton(); FReply OnClickedGenerateTextureWithScaleButton(); @@ -55,7 +56,30 @@ class FDungeonGenerateEditorModule : public IModuleInterface TSharedPtr PluginCommands; TSharedPtr mRandomSeedValue; + TSharedPtr mGenerateDungeonButton; + TSharedPtr mGenerateTextureSizeButton; + TSharedPtr mGenerateTextureScaleButton; TWeakObjectPtr mDungeonGenerateParameter = nullptr; int32 mGenerateTextureSize = 512; int32 mGenerateTextureScale = 1; }; + +inline TOptional FDungeonGenerateEditorModule::OnGetGenerateTextureSize() const +{ + return mGenerateTextureSize; +} + +inline void FDungeonGenerateEditorModule::OnSetGenerateTextureSize(int32 value) +{ + mGenerateTextureSize = value; +} + +inline TOptional FDungeonGenerateEditorModule::OnGetGenerateTextureScale() const +{ + return mGenerateTextureScale; +} + +inline void FDungeonGenerateEditorModule::OnSetGenerateTextureScale(int32 value) +{ + mGenerateTextureScale = value; +}