diff --git a/CHANGELOG.md b/CHANGELOG.md index 3063c48..dcb5e6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log - Procedural 3D Dungeon Generator Plug-in +## 20251004-1.7.8 (61) +### Changes +* Added the ability to assist actors spawning into the aisle grid +* Changed DungeonRoomSensor to not spawn on the client side +* Fixed several bugs +### 変更点 +* 通路グリッドへのアクターをスポーンを補助する機能を追加 +* DungeonRoomSensorをクライアント側でスポーンしないように変更 +* いくつかの不具合を修正 + ## 20250903-1.7.7 (60) ### Changes * Add DungeonRoomSensorDatabase diff --git a/Content/Actors/BP_SampleDungeonDoor.uasset b/Content/Actors/BP_SampleDungeonDoor.uasset index 1e8bc0d..7ed36c5 100644 Binary files a/Content/Actors/BP_SampleDungeonDoor.uasset and b/Content/Actors/BP_SampleDungeonDoor.uasset differ diff --git a/Content/Actors/BP_SampleDungeonRoomSensor.uasset b/Content/Actors/BP_SampleDungeonRoomSensor.uasset index 96db687..b60b2ac 100644 Binary files a/Content/Actors/BP_SampleDungeonRoomSensor.uasset and b/Content/Actors/BP_SampleDungeonRoomSensor.uasset differ diff --git a/Content/Maps/Demonstration.umap b/Content/Maps/Demonstration.umap index 59bc59d..0c7d71f 100644 Binary files a/Content/Maps/Demonstration.umap and b/Content/Maps/Demonstration.umap differ diff --git a/Content/Parameters/DGP_Sample.uasset b/Content/Parameters/DGP_Sample.uasset index 91941d6..afcece1 100644 Binary files a/Content/Parameters/DGP_Sample.uasset and b/Content/Parameters/DGP_Sample.uasset differ diff --git a/Content/Parameters/DRSD_Sample.uasset b/Content/Parameters/DRSD_Sample.uasset new file mode 100644 index 0000000..c9cb955 Binary files /dev/null and b/Content/Parameters/DRSD_Sample.uasset differ diff --git a/DungeonGenerator.uplugin b/DungeonGenerator.uplugin index 8a76e38..54d9275 100644 --- a/DungeonGenerator.uplugin +++ b/DungeonGenerator.uplugin @@ -1,15 +1,15 @@ { "FileVersion": 3, - "Version": 60, - "VersionName": "1.7.7", + "Version": 61, + "VersionName": "1.7.8", "FriendlyName": "Dungeon Generator", "Description": "Procedural 3d dungeon generator plugin. Easy generation of levels, mini-maps and missions.", "Category": "Procedural Systems", "CreatedBy": "Narcis Software", - "CreatedByURL": "https://github.com/shun126/UE5-DungeonGeneratorDemo", + "CreatedByURL": "https://github.com/shun126/DungeonGenerator", "DocsURL": "https://github.com/shun126/UE5-DungeonGeneratorDemo/wiki", "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/36a8b87d859f44439cfe1515975d7197", - "SupportURL": "https://github.com/shun126/UE5-DungeonGeneratorDemo/issues", + "SupportURL": "https://github.com/shun126/DungeonGenerator/discussions", "CanContainContent": true, "IsBetaVersion": true, "IsExperimentalVersion": false, @@ -18,19 +18,12 @@ { "Name": "DungeonGenerator", "Type": "Runtime", - "LoadingPhase": "Default", - "PlatformAllowList": [ - "Win64", - "Android" - ] + "LoadingPhase": "Default" }, { "Name": "DungeonGeneratorEditor", "Type": "UncookedOnly", - "LoadingPhase": "Default", - "PlatformAllowList": [ - "Win64" - ] + "LoadingPhase": "Default" } ] } diff --git a/Source/DungeonGenerator/Private/DungeonGenerateActor.cpp b/Source/DungeonGenerator/Private/DungeonGenerateActor.cpp index b479891..ff2a10a 100644 --- a/Source/DungeonGenerator/Private/DungeonGenerateActor.cpp +++ b/Source/DungeonGenerator/Private/DungeonGenerateActor.cpp @@ -16,6 +16,7 @@ ADungeonGenerateActorは配置可能(Placeable)、ADungeonGeneratedActorは配 #include "Core/Math/Vector.h" #include "Core/Voxelization/Grid.h" #include "Core/Voxelization/Voxel.h" +#include "Helper/DungeonAisleGridMap.h" #include "MainLevel/DungeonMainLevelScriptActor.h" #include "Parameter/DungeonGenerateParameter.h" #include diff --git a/Source/DungeonGenerator/Private/DungeonGenerateBase.cpp b/Source/DungeonGenerator/Private/DungeonGenerateBase.cpp index ec87f5a..a66af4c 100644 --- a/Source/DungeonGenerator/Private/DungeonGenerateBase.cpp +++ b/Source/DungeonGenerator/Private/DungeonGenerateBase.cpp @@ -73,6 +73,7 @@ ADungeonGenerateActorは配置可能(Placeable)、ADungeonGeneratedActorは配 namespace { + const FString ActorsFolderPath = TEXT("Actors"); const FString DoorsFolderPath = TEXT("Actors/Doors"); const FString TorchesFolderPath = TEXT("Actors/Torches"); const FString SensorsFolderPath = TEXT("Actors/Sensors"); @@ -422,11 +423,12 @@ bool ADungeonGenerateBase::BeginDungeonGeneration(const UDungeonGenerateParamete dungeon::CreateDebugDirectory(); #endif - DUNGEON_GENERATOR_LOG(TEXT("version '%s', license '%s', uuid '%s', commit '%s'"), + DUNGEON_GENERATOR_LOG(TEXT("version '%s', license '%s', uuid '%s', commit '%s', HasAuthority '%s'"), TEXT(DUNGENERATOR_PLUGIN_VERSION_NAME), TEXT(JENKINS_LICENSE), TEXT(JENKINS_UUID), - TEXT(JENKINS_GIT_COMMIT) + TEXT(JENKINS_GIT_COMMIT), + hasAuthority ? TEXT("Yes") : TEXT("No") ); // CRC32の値を初期化 @@ -528,7 +530,7 @@ bool ADungeonGenerateBase::BeginDungeonGeneration(const UDungeonGenerateParamete mAisleGridMap = NewObject(this); // 生成終了イベントの登録 - dungeon::Finalizer finalizer([this]() + dungeon::Finalizer finalizer([this, hasAuthority]()->void { #if defined(DEBUG_ENABLE_MEASURE_GENERATION_TIME) dungeon::Stopwatch stopwatch; @@ -540,6 +542,21 @@ bool ADungeonGenerateBase::BeginDungeonGeneration(const UDungeonGenerateParamete EndGeneration(random, mAisleGridMap); OnEndGeneration.Broadcast(random, mAisleGridMap); + mParameter->OnEndGeneration(random, mAisleGridMap, [this, hasAuthority](const FSoftObjectPath& spawnPath, const FTransform& transform) + { + if (hasAuthority) + { + const FSoftObjectPath path(spawnPath.ToString() + "_C"); + const TSoftClassPtr softClassPointer(path); + auto* actorClass = softClassPointer.LoadSynchronous(); + + FActorSpawnParameters actorSpawnParameters; + actorSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding; + SpawnActorImpl(actorClass, ActorsFolderPath, transform, actorSpawnParameters); + } + } + ); + #if defined(DEBUG_ENABLE_MEASURE_GENERATION_TIME) DUNGEON_GENERATOR_LOG(TEXT("On end generation event: %lf seconds"), stopwatch.Lap()); #endif @@ -595,7 +612,7 @@ bool ADungeonGenerateBase::BeginDungeonGeneration(const UDungeonGenerateParamete // メッシュの生成 { RoomAndRoomSensorMap roomSensorCache; - CreateImplement_PrepareSpawnRoomSensor(roomSensorCache); + CreateImplement_PrepareSpawnRoomSensor(roomSensorCache, hasAuthority); CreateImplement_QueryAisleGeneration(hasAuthority); CreateImplement_AddTerrain(roomSensorCache, hasAuthority); /* @@ -1303,7 +1320,7 @@ void ADungeonGenerateBase::CreateImplement_AddPillarAndTorch(const CreateImpleme ADungeonRoomSensorBaseはリプリケートされない前提のアクターなので 必ず同期乱数(GetSynchronizedRandom)を使ってください。 */ -void ADungeonGenerateBase::CreateImplement_PrepareSpawnRoomSensor(RoomAndRoomSensorMap& roomSensorCache) const +void ADungeonGenerateBase::CreateImplement_PrepareSpawnRoomSensor(RoomAndRoomSensorMap& roomSensorCache, const bool hasAuthority) const { check(IsValid(mParameter)); @@ -1311,8 +1328,7 @@ void ADungeonGenerateBase::CreateImplement_PrepareSpawnRoomSensor(RoomAndRoomSen dungeon::Stopwatch stopwatch; #endif - // RoomSensorActorを生成 - mGenerator->ForEach([this, &roomSensorCache](const std::shared_ptr& room) + mGenerator->ForEach([this, &roomSensorCache, hasAuthority](const std::shared_ptr& room) { auto* roomSensorClass = mParameter->GetRoomSensorClass(); if (const auto* roomSensorDatabase = mParameter->GetRoomSensorDatabase()) @@ -1328,20 +1344,24 @@ void ADungeonGenerateBase::CreateImplement_PrepareSpawnRoomSensor(RoomAndRoomSen GetSynchronizedRandom() ); } - if (roomSensorClass) + // サーバーならRoomSensorActorを生成 + if (hasAuthority) { - auto* roomSensorActor = SpawnRoomSensorActorDeferred( - roomSensorClass, - room->GetIdentifier(), - room->GetCenter() * mParameter->GetGridSize().To3D() + GetActorLocation(), - room->GetExtent() * mParameter->GetGridSize().To3D(), - static_cast(room->GetParts()), - static_cast(room->GetItem()), - room->GetBranchId(), - room->GetDepthFromStart(), - mGenerator->GetDeepestDepthFromStart() - ); - roomSensorCache[room.get()] = roomSensorActor; + if (roomSensorClass) + { + auto* roomSensorActor = SpawnRoomSensorActorDeferred( + roomSensorClass, + room->GetIdentifier(), + room->GetCenter() * mParameter->GetGridSize().To3D() + GetActorLocation(), + room->GetExtent() * mParameter->GetGridSize().To3D(), + static_cast(room->GetParts()), + static_cast(room->GetItem()), + room->GetBranchId(), + room->GetDepthFromStart(), + mGenerator->GetDeepestDepthFromStart() + ); + roomSensorCache[room.get()] = roomSensorActor; + } } } ); @@ -1636,7 +1656,7 @@ AStaticMeshActor* ADungeonGenerateBase::SpawnStaticMeshActor(UStaticMesh* static if (auto* staticMeshComponent = GetValid(actor->GetStaticMeshComponent())) { - if (const UWorld* world = actor->GetWorld()) + if (const auto* world = actor->GetWorld()) { if (world->HasBegunPlay() == true) actor->SetMobility(EComponentMobility::Movable); diff --git a/Source/DungeonGenerator/Private/Helper/DungeonAisleGridMap.cpp b/Source/DungeonGenerator/Private/Helper/DungeonAisleGridMap.cpp index 4248a94..a18588b 100644 --- a/Source/DungeonGenerator/Private/Helper/DungeonAisleGridMap.cpp +++ b/Source/DungeonGenerator/Private/Helper/DungeonAisleGridMap.cpp @@ -34,14 +34,17 @@ void UDungeonAisleGridMap::Register(const int32 identifier, const EDungeonDirect } } -void UDungeonAisleGridMapBlueprintFunctionLibrary::ForEach(const UDungeonAisleGridMap* aisleGridArray, const FDungeonAisleGridMapLoopSignature& OnLoop) +void UDungeonAisleGridMap::ForEach(const FDungeonAisleGridMapLoopSignature& OnLoop) const { - if (aisleGridArray) + for (const auto& aisleGrid : mAisleGridMap) { - for (const auto& aisleGrid : aisleGridArray->mAisleGridMap) - { - if (OnLoop.ExecuteIfBound(aisleGrid.second) == false) - break; - } + if (OnLoop.ExecuteIfBound(aisleGrid.second) == false) + break; } } + +void UDungeonAisleGridMapBlueprintFunctionLibrary::ForEach(const UDungeonAisleGridMap* aisleGridArray, const FDungeonAisleGridMapLoopSignature& OnLoop) +{ + if (aisleGridArray) + aisleGridArray->ForEach(OnLoop); +} diff --git a/Source/DungeonGenerator/Private/Parameter/DungeonGenerateParameter.cpp b/Source/DungeonGenerator/Private/Parameter/DungeonGenerateParameter.cpp index e3b319b..1665adb 100644 --- a/Source/DungeonGenerator/Private/Parameter/DungeonGenerateParameter.cpp +++ b/Source/DungeonGenerator/Private/Parameter/DungeonGenerateParameter.cpp @@ -10,6 +10,7 @@ All Rights Reserved. #include "Core/Debug/Debug.h" #include "Core/Math/Random.h" #include "Core/Voxelization/Grid.h" +#include "SubActor/DungeonRoomSensorDatabase.h" #include #include @@ -17,6 +18,7 @@ All Rights Reserved. #if WITH_EDITOR #include #endif +#include UDungeonGenerateParameter::UDungeonGenerateParameter(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -485,4 +487,10 @@ void UDungeonGenerateParameter::EachAisleCatwalkParts(const std::function& function) const { FDungeonMeshSet::EachParts(PillarParts, function); -} \ No newline at end of file +} + +void UDungeonGenerateParameter::OnEndGeneration(UDungeonRandom* synchronizedRandom, const UDungeonAisleGridMap* aisleGridMap, const std::function& spawnActor) const +{ + if (DungeonRoomSensorDatabase) + DungeonRoomSensorDatabase->OnEndGeneration(synchronizedRandom, aisleGridMap, VerticalGridSize, spawnActor); +} diff --git a/Source/DungeonGenerator/Private/SubActor/DungeonRoomSensorDatabase.cpp b/Source/DungeonGenerator/Private/SubActor/DungeonRoomSensorDatabase.cpp index f792b62..cc5bce5 100644 --- a/Source/DungeonGenerator/Private/SubActor/DungeonRoomSensorDatabase.cpp +++ b/Source/DungeonGenerator/Private/SubActor/DungeonRoomSensorDatabase.cpp @@ -7,8 +7,11 @@ All Rights Reserved. #include "SubActor/DungeonRoomSensorDatabase.h" #include "Core/Math/Random.h" #include "Core/Debug/Debug.h" +#include "Helper/DungeonAisleGridMap.h" +#include "Helper/DungeonRandom.h" #include "Parameter/DungeonMeshSetDatabase.h" #include +#include UDungeonRoomSensorDatabase::UDungeonRoomSensorDatabase(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -51,3 +54,40 @@ UClass* UDungeonRoomSensorDatabase::Select(const uint16_t identifier, const uint return nullptr; } } + +void UDungeonRoomSensorDatabase::OnEndGeneration(UDungeonRandom* synchronizedRandom, const UDungeonAisleGridMap* aisleGridMap, const float verticalGridSize, const std::function& spawnActor) const +{ + if (synchronizedRandom == nullptr) + return; + if (aisleGridMap == nullptr) + return; + if (SpawnActorInAisle.IsEmpty()) + return; + aisleGridMap->Each([this, synchronizedRandom, verticalGridSize, spawnActor](const TArray& aisleGridArray) + { + // スポーン先グリッドを抽選します + std::unordered_set gridIndexes; + const int32 totalGrids = aisleGridArray.Num(); + const int32 count = totalGrids / 3; + for (int32 i = 0; i < count; ++i) + { + gridIndexes.emplace(synchronizedRandom->GetIntegerFrom(totalGrids)); + } + + const int32 totalActors = SpawnActorInAisle.Num(); + for (const auto gridIndex : gridIndexes) + { + // スポーンする姿勢を求める + const auto& aisleGrid = aisleGridArray[gridIndex]; + const FTransform transform( + dungeon::detail::ToRotator(aisleGrid.Direction), + aisleGrid.Location + FVector(0, 0, verticalGridSize / 2.f) + ); + + // アクターをスポーンします + const int32 actorType = synchronizedRandom->GetIntegerFrom(totalActors); + spawnActor(SpawnActorInAisle[actorType], transform); + } + } + ); +} diff --git a/Source/DungeonGenerator/Public/DungeonBlueprint.h b/Source/DungeonGenerator/Public/DungeonBlueprint.h index 9ec0667..1b25a78 100644 --- a/Source/DungeonGenerator/Public/DungeonBlueprint.h +++ b/Source/DungeonGenerator/Public/DungeonBlueprint.h @@ -15,7 +15,7 @@ class ADungeonRoomSensorBase; BluePrint function library ダンジョン生成ブループリント関数 */ -UCLASS() +UCLASS(ClassGroup = "DungeonGenerator") class UDungeonBlueprint : public UBlueprintFunctionLibrary { GENERATED_BODY() diff --git a/Source/DungeonGenerator/Public/DungeonGenerateBase.h b/Source/DungeonGenerator/Public/DungeonGenerateBase.h index a9b4441..a4ca3bf 100644 --- a/Source/DungeonGenerator/Public/DungeonGenerateBase.h +++ b/Source/DungeonGenerator/Public/DungeonGenerateBase.h @@ -5,7 +5,7 @@ All Rights Reserved. */ #pragma once -#include "helper/DungeonRandom.h" +#include "Helper/DungeonRandom.h" #include "Mission/DungeonRoomItem.h" #include "Mission/DungeonRoomParts.h" #include "Mission/DungeonRoomProps.h" @@ -159,10 +159,10 @@ class DUNGEONGENERATOR_API ADungeonGenerateBase : public AActor // アクターのスポーンと破棄 public: /** - アクターをスポーンします。 - DungeonGeneratorというタグを追加します。 - スポーンしたアクターはDestroySpawnedActorsで破棄されます。 - */ + * アクターをスポーンします。 + * DungeonGeneratorというタグを追加します。 + * スポーンしたアクターはDestroySpawnedActorsで破棄されます。 + */ static AActor* SpawnActorImpl(UWorld* world, UClass* actorClass, const FString& folderPath, const FTransform& transform, const FActorSpawnParameters& actorSpawnParameters); /** @@ -237,14 +237,24 @@ class DUNGEONGENERATOR_API ADungeonGenerateBase : public AActor /** * Event called at the end of the Create function + * synchronizedRandom is a random number that is synchronized between clients. It must always be called the same number of times on server and client. + * aisleGridMap is a container for the generated aisle grid + * * Create関数終了時に呼び出されるイベントです + * synchronizedRandomは、クライアント間で同期する乱数です。かならずサーバーとクライアントで同じ回数を呼び出す必要があります + * aisleGridMapは、生成された通路グリッドのコンテナ */ UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "DungeonGenerator") void EndGeneration(UDungeonRandom* synchronizedRandom, const UDungeonAisleGridMap* aisleGridMap); /** * Event called at the end of the Create function + * synchronizedRandom is a random number that is synchronized between clients. It must always be called the same number of times on server and client. + * aisleGridMap is a container for the generated aisle grid + * * Create関数終了時に呼び出されるイベントです + * synchronizedRandomは、クライアント間で同期する乱数です。かならずサーバーとクライアントで同じ回数を呼び出す必要があります + * aisleGridMapは、生成された通路グリッドのコンテナ */ UPROPERTY(BlueprintAssignable, Category = "DungeonGenerator|Event") FDungeonGenerateBaseOnEndGenerateSignature OnEndGeneration; @@ -302,7 +312,7 @@ class DUNGEONGENERATOR_API ADungeonGenerateBase : public AActor void CreateImplement_AddPillarAndTorch(const CreateImplementParameter& cp, ADungeonRoomSensorBase* dungeonRoomSensorBase, const bool hasAuthority) const; // Room sensor - void CreateImplement_PrepareSpawnRoomSensor(RoomAndRoomSensorMap& roomSensorCache) const; + void CreateImplement_PrepareSpawnRoomSensor(RoomAndRoomSensorMap& roomSensorCache, const bool hasAuthority) const; static void CreateImplement_FinishSpawnRoomSensor(const RoomAndRoomSensorMap& roomSensorCache); // Navigation diff --git a/Source/DungeonGenerator/Public/Helper/DungeonAisleGridMap.h b/Source/DungeonGenerator/Public/Helper/DungeonAisleGridMap.h index 9972370..a4e20d1 100644 --- a/Source/DungeonGenerator/Public/Helper/DungeonAisleGridMap.h +++ b/Source/DungeonGenerator/Public/Helper/DungeonAisleGridMap.h @@ -8,6 +8,7 @@ All Rights Reserved. #include "Helper/DungeonDirection.h" #include #include +#include #include #include "DungeonAisleGridMap.generated.h" @@ -41,13 +42,20 @@ DECLARE_DYNAMIC_DELEGATE_OneParam(FDungeonAisleGridMapLoopSignature, const TArra * Record aisle grid for each aisle * 通路毎に通路グリッドを記録します */ -UCLASS() +UCLASS(ClassGroup = "DungeonGenerator") class DUNGEONGENERATOR_API UDungeonAisleGridMap : public UObject { GENERATED_BODY() public: + /** + * コンストラクタ + */ explicit UDungeonAisleGridMap(const FObjectInitializer& initializer); + + /** + * デストラクタ + */ virtual ~UDungeonAisleGridMap() override = default; /** @@ -56,6 +64,23 @@ class DUNGEONGENERATOR_API UDungeonAisleGridMap : public UObject */ void Register(const int32 identifier, const EDungeonDirection direction, const FVector& location); + /** + * Update aisle grid + * 通路グリッドを更新します + */ + UFUNCTION(BlueprintCallable, Category = "DungeonGenerator") + void ForEach(const FDungeonAisleGridMapLoopSignature& OnLoop) const; + + /** + * Update aisle grid + * 通路グリッドを更新します + */ + void Each(const std::function& aisleGridArray)>& func) const + { + for (const auto& aisleGrid : mAisleGridMap) + func(aisleGrid.second); + } + private: std::unordered_map> mAisleGridMap; @@ -66,7 +91,7 @@ class DUNGEONGENERATOR_API UDungeonAisleGridMap : public UObject * Class for BluePrint function to manipulate UDungeonAisleGridMap * UDungeonAisleGridMapを操作するBluePrint関数のクラス */ -UCLASS() +UCLASS(ClassGroup = "DungeonGenerator") class UDungeonAisleGridMapBlueprintFunctionLibrary : public UBlueprintFunctionLibrary { GENERATED_BODY() diff --git a/Source/DungeonGenerator/Public/Helper/DungeonDirection.h b/Source/DungeonGenerator/Public/Helper/DungeonDirection.h index 0365759..f1f3d44 100644 --- a/Source/DungeonGenerator/Public/Helper/DungeonDirection.h +++ b/Source/DungeonGenerator/Public/Helper/DungeonDirection.h @@ -24,3 +24,19 @@ enum class EDungeonDirection : uint8 South, West, }; + +namespace dungeon +{ + namespace detail + { + inline double ToDegree(const EDungeonDirection dungeonDirection) noexcept + { + return static_cast(dungeonDirection) * 90; + } + + inline FRotator ToRotator(const EDungeonDirection dungeonDirection) + { + return FRotator(0, ToDegree(dungeonDirection), 0); + } + } +} diff --git a/Source/DungeonGenerator/Public/Helper/DungeonRandom.h b/Source/DungeonGenerator/Public/Helper/DungeonRandom.h index 9acac88..412b189 100644 --- a/Source/DungeonGenerator/Public/Helper/DungeonRandom.h +++ b/Source/DungeonGenerator/Public/Helper/DungeonRandom.h @@ -110,7 +110,7 @@ class DUNGEONGENERATOR_API CDungeonRandom * Random numbers for dungeon generation available from BluePrint * BluePrintから利用可能なダンジョン生成用乱数 */ -UCLASS() +UCLASS(ClassGroup = "DungeonGenerator") class DUNGEONGENERATOR_API UDungeonRandom : public UObject { GENERATED_BODY() diff --git a/Source/DungeonGenerator/Public/MainLevel/DungeonMainLevelScriptActor.h b/Source/DungeonGenerator/Public/MainLevel/DungeonMainLevelScriptActor.h index 0b027ce..d36d834 100644 --- a/Source/DungeonGenerator/Public/MainLevel/DungeonMainLevelScriptActor.h +++ b/Source/DungeonGenerator/Public/MainLevel/DungeonMainLevelScriptActor.h @@ -27,7 +27,7 @@ registered in the partition. ダンジョンを指定の範囲のパーティションで区切り、パーティションに登録されたコンポーネントの アクティブ性を制御します。 */ -UCLASS() +UCLASS(ClassGroup = "DungeonGenerator") class DUNGEONGENERATOR_API ADungeonMainLevelScriptActor : public ALevelScriptActor { GENERATED_BODY() diff --git a/Source/DungeonGenerator/Public/MainLevel/DungeonPartition.h b/Source/DungeonGenerator/Public/MainLevel/DungeonPartition.h index 3e3a3a3..1cff24c 100644 --- a/Source/DungeonGenerator/Public/MainLevel/DungeonPartition.h +++ b/Source/DungeonGenerator/Public/MainLevel/DungeonPartition.h @@ -23,7 +23,7 @@ If the partition is away from the player, deactivate it. プレイヤー周辺のパーティションならDungeonComponentActivatorComponentをアクティブ化します。 プレイヤーから離れているパーティションなら非アクティブ化します。 */ -UCLASS() +UCLASS(ClassGroup = "DungeonGenerator") class DUNGEONGENERATOR_API UDungeonPartition : public UObject { GENERATED_BODY() diff --git a/Source/DungeonGenerator/Public/Parameter/DungeonGenerateParameter.h b/Source/DungeonGenerator/Public/Parameter/DungeonGenerateParameter.h index a7a2965..2d2f757 100644 --- a/Source/DungeonGenerator/Public/Parameter/DungeonGenerateParameter.h +++ b/Source/DungeonGenerator/Public/Parameter/DungeonGenerateParameter.h @@ -14,12 +14,14 @@ All Rights Reserved. #include "DungeonGenerateParameter.generated.h" // forward declaration +class UDungeonAisleGridMap; +class UDungeonRandom; class UDungeonRoomSensorDatabase; /** -Frequency of generation -生成頻度 -*/ + * Frequency of generation + * 生成頻度 + */ UENUM() enum class EFrequencyOfGeneration : uint8 { @@ -32,52 +34,130 @@ enum class EFrequencyOfGeneration : uint8 }; /** -Dungeon generation parameter -ダンジョン生成パラメータ -*/ + * Dungeon generation parameter + * ダンジョン生成パラメータ + */ UCLASS(ClassGroup = "DungeonGenerator") class DUNGEONGENERATOR_API UDungeonGenerateParameter : public UObject { GENERATED_BODY() public: + /** + * コンストラクタ + */ explicit UDungeonGenerateParameter(const FObjectInitializer& ObjectInitializer); + + /** + * デストラクタ + */ virtual ~UDungeonGenerateParameter() override = default; + /** + * ダンジョン生成に使用する乱数の種を取得します + */ int32 GetRandomSeed() const; + + /** + * ダンジョン生成に使用した乱数の種を取得します + */ int32 GetGeneratedRandomSeed() const; + /** + * 生成する部屋の候補数を取得します + */ int32 GetNumberOfCandidateRooms() const; + /** + * 部屋の幅を取得します + */ const FInt32Interval& GetRoomWidth() const noexcept; + + /** + * 部屋の奥行を取得します + */ const FInt32Interval& GetRoomDepth() const noexcept; + + /** + * 部屋の高さを取得します + */ const FInt32Interval& GetRoomHeight() const noexcept; + /** + * 部屋と部屋の水平方向の間隔(余白)を取得します + */ int32 GetHorizontalRoomMargin() const noexcept; + + /** + * 部屋と部屋の垂直方向の間隔(余白)を取得します + */ int32 GetVerticalRoomMargin() const noexcept; + /** + * グリッドのサイズを取得します + */ FDungeonGridSize GetGridSize() const; + /** + * 部屋と部屋を結合するか取得します + */ bool IsMergeRooms() const noexcept; + + /** + * ゲーム開始時にPlayerStartアクターを移動するか?取得します + */ bool IsMovePlayerStartToStartingPoint() const noexcept; - + + /** + * ミッショングラフを有効にするか取得します + */ bool IsUseMissionGraph() const noexcept; + + /** + * 通路の複雑度を取得します + */ uint8 GetAisleComplexity() const noexcept; + + /** + * 通路の複雑度が有効か?取得します + */ bool IsAisleComplexity() const noexcept; + /** + * 燭台アクターの生成頻度を取得します + */ EFrequencyOfGeneration GetFrequencyOfTorchlightGeneration() const noexcept; + /** + * DungeonRoomSensorのクラスを取得します + */ UClass* GetRoomSensorClass() const; + + /** + * DungeonRoomSensorのデータベースを取得します + */ UDungeonRoomSensorDatabase* GetRoomSensorDatabase() const; - // Converts from a grid coordinate system to a world coordinate system + /** + * Converts from a grid coordinate system to a world coordinate system + * + * グリッド座標系からワールド座標系への変換 + */ FVector ToWorld(const FIntVector& location) const; - - // Converts from a grid coordinate system to a world coordinate system + + /** + * Converts from a grid coordinate system to a world coordinate system + * + * グリッド座標系からワールド座標系への変換 + */ FVector ToWorld(const uint32_t x, const uint32_t y, const uint32_t z) const; - // Converts from a grid coordinate system to a world coordinate system + /** + * Converts from a grid coordinate system to a world coordinate system + * + * グリッド座標系からワールド座標系への変換 + */ FIntVector ToGrid(const FVector& location) const; /** @@ -94,19 +174,26 @@ class DUNGEONGENERATOR_API UDungeonGenerateParameter : public UObject UFUNCTION(BlueprintCallable, Category = "DungeonGenerator") void SetRandomParameter() noexcept; -public: #if WITH_EDITOR /** - Output parameters in JSON format - パラメータをJSON形式で出力します - */ + * Output parameters in JSON format + * + * パラメータをJSON形式で出力します + */ UFUNCTION(Category = "DungeonGenerator", meta = (CallInEditor = "true")) void Dump() const; #endif private: + /** + * ダンジョン生成に使用する乱数の種を設定します + */ void SetRandomSeed(const int32 generateRandomSeed); + + /** + * ダンジョン生成に使用した乱数の種を設定します + */ void SetGeneratedRandomSeed(const int32 generatedRandomSeed); #if WITH_EDITOR @@ -116,8 +203,6 @@ class DUNGEONGENERATOR_API UDungeonGenerateParameter : public UObject static const FDungeonMeshSet* SelectParts(const UDungeonMeshSetDatabase* dungeonMeshSetDatabase, const dungeon::Grid& grid, const std::shared_ptr& random); - const FDungeonMeshParts* SelectSlopeParts(const size_t gridIndex, const dungeon::Grid& grid, const std::shared_ptr& random) const; - const UDungeonMeshSetDatabase* GetDungeonRoomMeshPartsDatabase() const noexcept; const UDungeonMeshSetDatabase* GetDungeonAisleMeshPartsDatabase() const noexcept; static const FDungeonMeshPartsWithDirection* SelectFloorParts(const UDungeonMeshSetDatabase* dungeonMeshSetDatabase, const size_t gridIndex, const dungeon::Grid& grid, const std::shared_ptr& random); @@ -136,7 +221,7 @@ class DUNGEONGENERATOR_API UDungeonGenerateParameter : public UObject void EachRoofParts(const std::function& function) const; void EachSlopeParts(const std::function& function) const; void EachCatwalkParts(const std::function& function) const; -void EachPillarParts(const std::function& function) const; + void EachPillarParts(const std::function& function) const; void EachRoomFloorParts(const std::function& function) const; void EachRoomWallParts(const std::function& function) const; @@ -152,7 +237,15 @@ void EachPillarParts(const std::function& functi int32 GetGeneratedDungeonCRC32() const noexcept; void SetGeneratedDungeonCRC32(const int32 generatedDungeonCRC32) noexcept; - + + /** + * ダンジョン生成終了時に通知されるイベント + * @param synchronizedRandom クライアント・サーバー間で同期される乱数 + * @param aisleGridMap 通路のグリッドを記録したコンテナ + * @param spawnActor アクターをスポーンする関数 + */ + void OnEndGeneration(UDungeonRandom* synchronizedRandom, const UDungeonAisleGridMap* aisleGridMap, const std::function& spawnActor) const; + public: // overrides virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; @@ -160,134 +253,134 @@ void EachPillarParts(const std::function& functi protected: /** - Seed of random number (if 0, auto-generated) - - 乱数のシード(0なら自動生成) - */ + * Seed of random number (if 0, auto-generated) + * + * 乱数のシード(0なら自動生成) + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DungeonGenerator", meta = (ClampMin = "0")) int32 RandomSeed = 0; /** - Seed of random numbers used for the last generation - - 最後の生成に使用された乱数のシード - */ + * Seed of random numbers used for the last generation + * + * 最後の生成に使用された乱数のシード + */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Transient, Category = "DungeonGenerator") int32 GeneratedRandomSeed = 0; /** - CRC32 of the last dungeon generated - - 最後に生成されたダンジョンのCRC32 - */ + * CRC32 of the last dungeon generated + * + * 最後に生成されたダンジョンのCRC32 + */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Transient, Category = "DungeonGenerator") int32 GeneratedDungeonCRC32 = 0; /** - Room Width - - 部屋の幅 - */ + * Room Width + * + * 部屋の幅 + */ UPROPERTY(EditAnywhere, Category = "DungeonGenerator", meta = (UIMin = 1, ClampMin = 1)) FInt32Interval RoomWidth = { 3, 8 }; /** - Room depth - - 部屋の奥行き - */ + * Room depth + * + * 部屋の奥行き + */ UPROPERTY(EditAnywhere, Category = "DungeonGenerator", meta = (UIMin = 1, ClampMin = 1)) FInt32Interval RoomDepth = { 3, 8 }; /** - Room height - - 部屋の高さ - */ + * Room height + * + * 部屋の高さ + */ UPROPERTY(EditAnywhere, Category = "DungeonGenerator", meta = (UIMin = 1, ClampMin = 1)) FInt32Interval RoomHeight = { 2, 4 }; /** - Horizontal room-to-room margins - MergeRooms must be unchecked to enable Room Horizontal Margin - - 水平方向の部屋と部屋の空白 - Room Horizontal Marginを有効にするにはMergeRoomsのチェックを外す必要があります - */ + * Horizontal room-to-room margins + * MergeRooms must be unchecked to enable Room Horizontal Margin + * + * 水平方向の部屋と部屋の空白 + * Room Horizontal Marginを有効にするにはMergeRoomsのチェックを外す必要があります + */ UPROPERTY(EditAnywhere, Category = "DungeonGenerator", BlueprintReadWrite, meta = (ClampMin = "1", EditCondition = "!MergeRooms"), DisplayName = "Horizontal Room Margin") uint8 RoomMargin = 2; /** - Vertical room-to-room margins - MergeRooms must be unchecked to enable Room Vertical Margin - - 垂直方向の部屋と部屋の空白 - Room Vertical Marginを有効にするにはMergeRoomsのチェックを外す必要があります - */ + * Vertical room-to-room margins + * MergeRooms must be unchecked to enable Room Vertical Margin + * + * 垂直方向の部屋と部屋の空白 + * Room Vertical Marginを有効にするにはMergeRoomsのチェックを外す必要があります + */ UPROPERTY(EditAnywhere, Category = "DungeonGenerator", BlueprintReadWrite, meta = (ClampMin = "0", EditCondition = "!MergeRooms && !Flat "), DisplayName = "Vertical Room Margin") uint8 VerticalRoomMargin = 0; /** - Candidate number of rooms to be generated - This is the initial number of rooms to be generated, not the final number of rooms to be generated. - - 生成される部屋数の候補 - これは最終的な部屋の数ではなく最初に生成される部屋の数です。 - */ + * Candidate number of rooms to be generated + * This is the initial number of rooms to be generated, not the final number of rooms to be generated. + * + * 生成される部屋数の候補 + * これは最終的な部屋の数ではなく最初に生成される部屋の数です + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DungeonGenerator", meta = (ClampMin = "3", ClampMax = "100")) uint8 NumberOfCandidateRooms = 10; /** - Horizontal room-to-room coupling - - 有効にすると部屋と部屋を結合します - */ + * Horizontal room-to-room coupling + * + * 有効にすると部屋と部屋を結合します + */ UPROPERTY(EditAnywhere, Category = "DungeonGenerator", BlueprintReadWrite) bool MergeRooms = false; /** - Candidate Number of Generated Hierarchies This is used as a reference number of hierarchies for generation, - not as the final number of hierarchies. - - 生成される階層数の候補 - これは最終的な階層の数ではなく生成時の参考階層数として利用されます。 - */ + * Candidate Number of Generated Hierarchies This is used as a reference number of hierarchies for generation, + * not as the final number of hierarchies. + * + * 生成される階層数の候補 + * これは最終的な階層の数ではなく生成時の参考階層数として利用されます。 + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DungeonGenerator", meta = (ClampMin = "0", ClampMax = "5", EditCondition = "!Flat")) uint8 NumberOfCandidateFloors = 3; /** - Generates a flat dungeon - - 平面的なダンジョンを生成します - */ + * Generates a flat dungeon + * + * 平面的なダンジョンを生成します + */ UPROPERTY(EditAnywhere, Category = "DungeonGenerator", BlueprintReadWrite, meta = (EditCondition = "!MergeRooms")) bool Flat = false; /** - PlayerStart is automatically moved to the start room at the start - - 開始時にPlayerStartを自動的にスタート部屋に移動します - */ + * PlayerStart is automatically moved to the start room at the start + * + * 開始時にPlayerStartを自動的にスタート部屋に移動します + */ UPROPERTY(EditAnywhere, Category = "DungeonGenerator", BlueprintReadWrite) bool MovePlayerStartToStartingPoint = true; /** - Enable MissionGraph to generate missions with keys. - MergeRooms must be unchecked and AisleComplexity must be 0 for UseMissionGraph to be enabled. - - MissionGraphを有効にして、鍵を使ったミッション情報を生成します - UseMissionGraphを有効にするには、MergeRoomsのチェックを外しAisleComplexityを0にする必要があります - */ + * Enable MissionGraph to generate missions with keys. + * MergeRooms must be unchecked and AisleComplexity must be 0 for UseMissionGraph to be enabled. + * + * MissionGraphを有効にして、鍵を使ったミッション情報を生成します + * UseMissionGraphを有効にするには、MergeRoomsのチェックを外しAisleComplexityを0にする必要があります + */ UPROPERTY(EditAnywhere, Category = "DungeonGenerator", BlueprintReadWrite, meta = (EditCondition = "!MergeRooms")) bool UseMissionGraph = false; /** - Aisle complexity (0 being the minimum aisle) - MergeRooms and UseMissionGraph must be unchecked to enable AisleComplexity - - 通路の複雑さ(0が最低限の通路) - AisleComplexityを有効にするには、MergeRoomsとUseMissionGraphのチェックを外す必要があります - */ + * Aisle complexity (0 being the minimum aisle) + * MergeRooms and UseMissionGraph must be unchecked to enable AisleComplexity + * + * 通路の複雑さ(0が最低限の通路) + * AisleComplexityを有効にするには、MergeRoomsとUseMissionGraphのチェックを外す必要があります + */ UPROPERTY(EditAnywhere, Category = "DungeonGenerator", BlueprintReadOnly, meta = (ClampMin = "0", ClampMax = "10", EditCondition = "!MergeRooms && !UseMissionGraph")) uint8 AisleComplexity = 5; @@ -312,90 +405,90 @@ void EachPillarParts(const std::function& functi bool GenerateStructuralColumn = false; /** - Horizontal voxel size - - 水平方向のボクセルサイズ - */ + * Horizontal voxel size + * + * 水平方向のボクセルサイズ + */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "DungeonGenerator|GridSize", meta = (ClampMin = 1), DisplayName = "Horizontal Size") float GridSize = 400.f; /** - Vertical voxel size - - 垂直方向のボクセルサイズ - */ + * Vertical voxel size + * + * 垂直方向のボクセルサイズ + */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "DungeonGenerator|GridSize", meta = (ClampMin = 1), DisplayName = "Vertical Size") float VerticalGridSize = 400.f; /** - Room mesh parts database - - 部屋のメッシュパーツデータベース - */ + * Room mesh parts database + * + * 部屋のメッシュパーツデータベース + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DungeonGenerator|Parts") TObjectPtr DungeonRoomMeshPartsDatabase; /** - Aisle mesh parts database - - 通路のメッシュパーツデータベース - */ + * Aisle mesh parts database + * + * 通路のメッシュパーツデータベース + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DungeonGenerator|Parts") TObjectPtr DungeonAisleMeshPartsDatabase; /** - How to generate parts of pillar - - 柱のパーツを生成する方法 - */ + * How to generate parts of pillar + * + * 柱のパーツを生成する方法 + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DungeonGenerator|Parts|Pillar") EDungeonPartsSelectionMethod PillarPartsSelectionMethod = EDungeonPartsSelectionMethod::Random; /** - Pillar Parts - - 柱のメッシュパーツデータベース - */ + * Pillar Parts + * + * 柱のメッシュパーツデータベース + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DungeonGenerator|Parts|Pillar") TArray PillarParts; /** - How to generate parts for torch - - 燭台のパーツを生成する方法 - */ + * How to generate parts for torch + * + * 燭台のパーツを生成する方法 + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DungeonGenerator|Parts|Torch") EDungeonPartsSelectionMethod TorchPartsSelectionMethod = EDungeonPartsSelectionMethod::Random; /** - Frequency of torchlight generation - - 燭台の生成頻度 - */ + * Frequency of torchlight generation + * + * 燭台の生成頻度 + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DungeonGenerator|Parts|Torch") EFrequencyOfGeneration FrequencyOfTorchlightGeneration = EFrequencyOfGeneration::Rarely; /** - Torch (pillar lighting) parts - - 燭台のメッシュパーツデータベース - */ + * Torch (pillar lighting) parts + * + * 燭台のメッシュパーツデータベース + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DungeonGenerator|Parts|Torch") TArray TorchParts; /** - How to generate door parts - - ドアのパーツを生成する方法 - */ + * How to generate door parts + * + * ドアのパーツを生成する方法 + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DungeonGenerator|Parts|Door") EDungeonPartsSelectionMethod DoorPartsSelectionMethod = EDungeonPartsSelectionMethod::Random; /** - Door Parts - - ドアのメッシュパーツデータベース - */ + * Door Parts + * + * ドアのメッシュパーツデータベース + */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DungeonGenerator|Parts|Door") TArray DoorParts; diff --git a/Source/DungeonGenerator/Public/SubActor/DungeonRoomSensorDatabase.h b/Source/DungeonGenerator/Public/SubActor/DungeonRoomSensorDatabase.h index f33e07a..3554030 100644 --- a/Source/DungeonGenerator/Public/SubActor/DungeonRoomSensorDatabase.h +++ b/Source/DungeonGenerator/Public/SubActor/DungeonRoomSensorDatabase.h @@ -6,9 +6,13 @@ All Rights Reserved. #pragma once #include "Parameter/DungeonMeshSetSelectionMethod.h" +#include #include #include "DungeonRoomSensorDatabase.generated.h" +class UDungeonAisleGridMap; +class UDungeonRandom; + namespace dungeon { class Random; @@ -50,19 +54,36 @@ class DUNGEONGENERATOR_API UDungeonRoomSensorDatabase : public UObject */ UClass* Select(const uint16_t identifier, const uint8_t depthRatioFromStart, const std::shared_ptr& random) const; + /** + * ダンジョン生成終了時に通知されるイベント + * @param synchronizedRandom クライアント・サーバー間で同期される乱数 + * @param aisleGridMap 通路のグリッドを記録したコンテナ + * @param verticalGridSize グリッドの垂直方向の大きさ + * @param spawnActor アクターをスポーンする関数 + */ + void OnEndGeneration(UDungeonRandom* synchronizedRandom, const UDungeonAisleGridMap* aisleGridMap, const float verticalGridSize, const std::function& spawnActor) const; + protected: /** * Room Sensor Generation Rules * ルームセンサーの生成ルール */ - UPROPERTY(EditAnywhere, Category = "DungeonGenerator") - EDungeonMeshSetSelectionMethod SelectionMethod = EDungeonMeshSetSelectionMethod::Identifier; + UPROPERTY(EditAnywhere, Category = "DungeonGenerator|RoomSensor") + EDungeonMeshSetSelectionMethod SelectionMethod = EDungeonMeshSetSelectionMethod::DepthFromStart; /** * Register the RoomSensor to be placed. * * 配置するRoomSensorを登録して下さい。 */ - UPROPERTY(EditAnywhere, Category = "DungeonGenerator", meta = (AllowedClasses = "DungeonRoomSensorBase")) + UPROPERTY(EditAnywhere, Category = "DungeonGenerator|RoomSensor", meta = (AllowedClasses = "DungeonRoomSensorBase")) TArray> DungeonRoomSensorClass; + + /** + * Actor spawning in an aisle + * + * 通路にスポーンするアクター + */ + UPROPERTY(EditAnywhere, Category = "DungeonGenerator|Aisle", meta = (AllowedClasses = "Blueprint")) + TArray SpawnActorInAisle; }; diff --git a/Source/DungeonGeneratorEditor/Public/Parameter/DungeonGenerateParameterFactory.h b/Source/DungeonGeneratorEditor/Public/Parameter/DungeonGenerateParameterFactory.h index 4b0a9c3..4c7691d 100644 --- a/Source/DungeonGeneratorEditor/Public/Parameter/DungeonGenerateParameterFactory.h +++ b/Source/DungeonGeneratorEditor/Public/Parameter/DungeonGenerateParameterFactory.h @@ -9,7 +9,7 @@ All Rights Reserved. #include #include "DungeonGenerateParameterFactory.generated.h" -UCLASS() +UCLASS(ClassGroup = "DungeonGenerator") class DUNGEONGENERATOREDITOR_API UDungeonGenerateParameterFactory : public UFactory { GENERATED_BODY() diff --git a/Source/DungeonGeneratorEditor/Public/Parameter/DungeonMeshSetDatabaseFactory.h b/Source/DungeonGeneratorEditor/Public/Parameter/DungeonMeshSetDatabaseFactory.h index a5b83fd..e2600fc 100644 --- a/Source/DungeonGeneratorEditor/Public/Parameter/DungeonMeshSetDatabaseFactory.h +++ b/Source/DungeonGeneratorEditor/Public/Parameter/DungeonMeshSetDatabaseFactory.h @@ -12,7 +12,7 @@ All Rights Reserved. /* UDungeonMeshSetDatabaseを生成するファクトリークラス */ -UCLASS() +UCLASS(ClassGroup = "DungeonGenerator") class DUNGEONGENERATOREDITOR_API UDungeonMeshSetDatabaseFactory : public UFactory { GENERATED_BODY() diff --git a/Source/DungeonGeneratorEditor/Public/SubActor/DungeonRoomSensorDatabaseFactory.h b/Source/DungeonGeneratorEditor/Public/SubActor/DungeonRoomSensorDatabaseFactory.h index a13d873..90b626b 100644 --- a/Source/DungeonGeneratorEditor/Public/SubActor/DungeonRoomSensorDatabaseFactory.h +++ b/Source/DungeonGeneratorEditor/Public/SubActor/DungeonRoomSensorDatabaseFactory.h @@ -9,7 +9,7 @@ All Rights Reserved. #include #include "DungeonRoomSensorDatabaseFactory.generated.h" -UCLASS() +UCLASS(ClassGroup = "DungeonGenerator") class DUNGEONGENERATOREDITOR_API UDungeonRoomSensorDatabaseFactory : public UFactory { GENERATED_BODY()