├── .gitattributes ├── .gitignore ├── Config ├── DefaultPCGLayeredBiomes.ini └── FilterPlugin.ini ├── Content ├── A_BiomesBlockingSpline.uasset ├── A_Biomes_BlockingSpline.uasset ├── A_Biomes_ExplicitBiome.uasset ├── A_ExplicitBiome.uasset ├── Details │ ├── B_Biomes_DetectBiome.uasset │ ├── PCG_Biomes_DetectAndExecuteBiomes.uasset │ ├── PCG_Biomes_ExecuteAllLayers.uasset │ └── PCG_Biomes_ExecuteSingleLayer.uasset ├── Filters │ ├── Filter_ByHeight.uasset │ └── Filter_ByLandscapeLayer.uasset ├── Layers │ ├── PCG_Layer_BiomeEdge.uasset │ ├── PCG_Layer_Generic.uasset │ ├── Spawners │ │ ├── PCG_Spawn_Default.uasset │ │ ├── PCG_Spawn_Default_CullFar.uasset │ │ └── PCG_Spawn_Default_CullNear.uasset │ └── Utils │ │ ├── PCG_Biome_GetExclusion.uasset │ │ ├── PCG_Biome_InExclusion_And_Debug.uasset │ │ └── PCG_SpawnMeshes.uasset ├── PCG_BIomes_PreFilters.uasset ├── PCG_Biomes_Main.uasset └── PCG_World_Exclusion.uasset ├── PCGLayeredBiomes.uplugin ├── README.md ├── Resources └── Icon128.png └── Source └── PCGLayeredBiomes ├── PCGLayeredBiomes.Build.cs ├── Private ├── Biomes │ ├── LBBiomesSettings.cpp │ └── Layers │ │ └── LBGenericBiomeLayer.cpp ├── Graph │ ├── LBPCGBiomesNoise.cpp │ ├── LBPCGExplicitBiomeFromSplines.cpp │ ├── LBPCGExtractBiomeData.cpp │ ├── LBPCGGetAttributes.cpp │ └── PCGSetWeightedMeshFromSet.cpp ├── LBBiomesLog.h ├── LBBiomesPCGUtils.cpp ├── LBBiomesSpawnManager.cpp ├── LBBiomesTagPacker.cpp ├── LBExplicitBiomeActor.cpp ├── LBPCGLayeredBiomes.cpp ├── LBPCGSpawnStructures.cpp ├── LBRandomUtils.cpp ├── LBRandomUtils.h └── Runtime │ ├── LBBiomesInstanceController.cpp │ └── LBBiomesInstanceTracker.cpp └── Public ├── Biomes ├── LBBiomesSettings.h ├── LBPCGBiomesBaseFilter.h └── Layers │ ├── LBBaseBiomeLayer.h │ ├── LBEdgeBiomeLayer.h │ └── LBGenericBiomeLayer.h ├── Graph ├── LBPCGBiomesNoise.h ├── LBPCGExplicitBiomeFromSplines.h ├── LBPCGExtractBiomeData.h ├── LBPCGGetAttributes.h └── LBPCGMeshFromSpawnManager.h ├── LBBiomesPCGUtils.h ├── LBBiomesSpawnManager.h ├── LBBiomesTagPacker.h ├── LBExplicitBiomeActor.h ├── LBPCGLayeredBiomes.h ├── LBPCGSpawnStructures.h └── Runtime ├── LBBiomesInstanceController.h └── LBBiomesInstanceTracker.h /.gitattributes: -------------------------------------------------------------------------------- 1 | *.png[[:space:]]filter=lfs[[:space:]]diff=lfs[[:space:]]merge=lfs[[:space:]]-text filter=lfs diff=lfs merge=lfs -text 2 | *.mp3[[:space:]]filter=lfs[[:space:]]diff=lfs[[:space:]]merge=lfs[[:space:]]-text filter=lfs diff=lfs merge=lfs -text 3 | *.wav[[:space:]]filter=lfs[[:space:]]diff=lfs[[:space:]]merge=lfs[[:space:]]-text filter=lfs diff=lfs merge=lfs -text 4 | *.xcf[[:space:]]filter=lfs[[:space:]]diff=lfs[[:space:]]merge=lfs[[:space:]]-text filter=lfs diff=lfs merge=lfs -text 5 | \#[[:space:]]UE[[:space:]]file[[:space:]]types filter=lfs diff=lfs merge=lfs -text 6 | *.uasset[[:space:]]filter=lfs[[:space:]]diff=lfs[[:space:]]merge=lfs[[:space:]]-text filter=lfs diff=lfs merge=lfs -text 7 | *.umap[[:space:]]filter=lfs[[:space:]]diff=lfs[[:space:]]merge=lfs[[:space:]]-text filter=lfs diff=lfs merge=lfs -text 8 | *.fbx[[:space:]]filter=lfs[[:space:]]diff=lfs[[:space:]]merge=lfs[[:space:]]-text filter=lfs diff=lfs merge=lfs -text 9 | \#[[:space:]]Raw[[:space:]]Content[[:space:]]types filter=lfs diff=lfs merge=lfs -text 10 | *.3ds[[:space:]]filter=lfs[[:space:]]diff=lfs[[:space:]]merge=lfs[[:space:]]-text filter=lfs diff=lfs merge=lfs -text 11 | *.psd[[:space:]]filter=lfs[[:space:]]diff=lfs[[:space:]]merge=lfs[[:space:]]-text filter=lfs diff=lfs merge=lfs -text 12 | *.jpg[[:space:]]filter=lfs[[:space:]]diff=lfs[[:space:]]merge=lfs[[:space:]]-text filter=lfs diff=lfs merge=lfs -text 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.vs/ 2 | *_BuiltData.uasset 3 | Binaries 4 | DerivedDataCache 5 | Intermediate 6 | Saved 7 | .vscode 8 | .vs 9 | .idea 10 | *.VC.db 11 | *.opensdf 12 | *.opendb 13 | *.sdf 14 | *.sln 15 | *.suo 16 | *.xcodeproj 17 | *.xcworkspace 18 | /Backup/ 19 | /Backup1/ 20 | *Log*.htm 21 | /Build/ 22 | -------------------------------------------------------------------------------- /Config/DefaultPCGLayeredBiomes.ini: -------------------------------------------------------------------------------- 1 | [CoreRedirects] 2 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesInstanceUserData",NewName="/Script/PCGLayeredBiomes.LBBiomesInstanceUserData") 3 | +StructRedirects=(OldName="/Script/PCGLayeredBiomes.PCGSpawnInfo",NewName="/Script/PCGLayeredBiomes.LBPCGSpawnInfo") 4 | +StructRedirects=(OldName="/Script/PCGLayeredBiomes.PCGSpawnSet",NewName="/Script/PCGLayeredBiomes.LBPCGSpawnSet") 5 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.PCGSpawnPreset",NewName="/Script/PCGLayeredBiomes.LBPCGSpawnPreset") 6 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.ExplicitBiomeActor",NewName="/Script/PCGLayeredBiomes.LBExplicitBiomeActor") 7 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesTagPacker",NewName="/Script/PCGLayeredBiomes.LBBiomesTagPacker") 8 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesSpawnManager",NewName="/Script/PCGLayeredBiomes.LBBiomesSpawnManager") 9 | +StructRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesPersistentInstancesData",NewName="/Script/PCGLayeredBiomes.LBBiomesPersistentInstancesData") 10 | +StructRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesInstanceHandle",NewName="/Script/PCGLayeredBiomes.LBBiomesInstanceHandle") 11 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesPCGUtils",NewName="/Script/PCGLayeredBiomes.LBBiomesPCGUtils") 12 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesInstanceTracker",NewName="/Script/PCGLayeredBiomes.LBBiomesInstanceTracker") 13 | +StructRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesInstanceData",NewName="/Script/PCGLayeredBiomes.LBBiomesInstanceData") 14 | +StructRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesPartition",NewName="/Script/PCGLayeredBiomes.LBBiomesPartition") 15 | +StructRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesPersistentPartitionedInstances",NewName="/Script/PCGLayeredBiomes.LBBiomesPersistentPartitionedInstances") 16 | +StructRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesPersistentMainInstances",NewName="/Script/PCGLayeredBiomes.LBBiomesPersistentMainInstances") 17 | +StructRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesISMList",NewName="/Script/PCGLayeredBiomes.LBBiomesISMList") 18 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesInstanceController",NewName="/Script/PCGLayeredBiomes.LBBiomesInstanceController") 19 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.PCGMeshFromSpawnManagerSettings",NewName="/Script/PCGLayeredBiomes.LBPCGMeshFromSpawnManagerSettings") 20 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.PCGBiomesNoiseSettings",NewName="/Script/PCGLayeredBiomes.LBPCGBiomesNoiseSettings") 21 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.PCGExplicitBiomeFromSplines",NewName="/Script/PCGLayeredBiomes.LBPCGExplicitBiomeFromSplines") 22 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesSettings",NewName="/Script/PCGLayeredBiomes.LBBiomesSettings") 23 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.PCGExtractBiomeData",NewName="/Script/PCGLayeredBiomes.LBPCGExtractBiomeData") 24 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.PCGGetAttributesSettings",NewName="/Script/PCGLayeredBiomes.LBPCGGetAttributesSettings") 25 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.PCGGetAllAttributesFromSettings",NewName="/Script/PCGLayeredBiomes.LBPCGGetAllAttributesFromSettings") 26 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.PCGBiomesBaseFilter",NewName="/Script/PCGLayeredBiomes.LBPCGBiomesBaseFilter") 27 | +StructRedirects=(OldName="/Script/PCGLayeredBiomes.BiomeSettings",NewName="/Script/PCGLayeredBiomes.LBBiomeSettings") 28 | +StructRedirects=(OldName="/Script/PCGLayeredBiomes.BiomeSettings_Named",NewName="/Script/PCGLayeredBiomes.LBBiomeSettings_Named") 29 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.BiomesData",NewName="/Script/PCGLayeredBiomes.LBBiomesData") 30 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.GenericBiomeLayer",NewName="/Script/PCGLayeredBiomes.LBGenericBiomeLayer") 31 | +EnumRedirects=(OldName="/Script/PCGLayeredBiomes.EEdgeLayerMode",NewName="/Script/PCGLayeredBiomes.ELBEdgeLayerMode") 32 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.EdgeBiomeLayer",NewName="/Script/PCGLayeredBiomes.LBEdgeBiomeLayer") 33 | +EnumRedirects=(OldName="/Script/PCGLayeredBiomes.EBiomeLayerExclusion",NewName="/Script/PCGLayeredBiomes.ELBBiomeLayerExclusion") 34 | +EnumRedirects=(OldName="/Script/PCGLayeredBiomes.EBiomeLayerDebugMode",NewName="/Script/PCGLayeredBiomes.ELBBiomeLayerDebugMode") 35 | +ClassRedirects=(OldName="/Script/PCGLayeredBiomes.BaseBiomeLayer",NewName="/Script/PCGLayeredBiomes.LBBaseBiomeLayer") -------------------------------------------------------------------------------- /Config/FilterPlugin.ini: -------------------------------------------------------------------------------- 1 | [FilterPlugin] 2 | ; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and 3 | ; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively. 4 | ; 5 | ; Examples: 6 | ; /README.txt 7 | ; /Extras/... 8 | ; /Binaries/ThirdParty/*.dll 9 | -------------------------------------------------------------------------------- /Content/A_BiomesBlockingSpline.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/A_BiomesBlockingSpline.uasset -------------------------------------------------------------------------------- /Content/A_Biomes_BlockingSpline.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/A_Biomes_BlockingSpline.uasset -------------------------------------------------------------------------------- /Content/A_Biomes_ExplicitBiome.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/A_Biomes_ExplicitBiome.uasset -------------------------------------------------------------------------------- /Content/A_ExplicitBiome.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/A_ExplicitBiome.uasset -------------------------------------------------------------------------------- /Content/Details/B_Biomes_DetectBiome.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Details/B_Biomes_DetectBiome.uasset -------------------------------------------------------------------------------- /Content/Details/PCG_Biomes_DetectAndExecuteBiomes.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Details/PCG_Biomes_DetectAndExecuteBiomes.uasset -------------------------------------------------------------------------------- /Content/Details/PCG_Biomes_ExecuteAllLayers.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Details/PCG_Biomes_ExecuteAllLayers.uasset -------------------------------------------------------------------------------- /Content/Details/PCG_Biomes_ExecuteSingleLayer.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Details/PCG_Biomes_ExecuteSingleLayer.uasset -------------------------------------------------------------------------------- /Content/Filters/Filter_ByHeight.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Filters/Filter_ByHeight.uasset -------------------------------------------------------------------------------- /Content/Filters/Filter_ByLandscapeLayer.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Filters/Filter_ByLandscapeLayer.uasset -------------------------------------------------------------------------------- /Content/Layers/PCG_Layer_BiomeEdge.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Layers/PCG_Layer_BiomeEdge.uasset -------------------------------------------------------------------------------- /Content/Layers/PCG_Layer_Generic.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Layers/PCG_Layer_Generic.uasset -------------------------------------------------------------------------------- /Content/Layers/Spawners/PCG_Spawn_Default.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Layers/Spawners/PCG_Spawn_Default.uasset -------------------------------------------------------------------------------- /Content/Layers/Spawners/PCG_Spawn_Default_CullFar.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Layers/Spawners/PCG_Spawn_Default_CullFar.uasset -------------------------------------------------------------------------------- /Content/Layers/Spawners/PCG_Spawn_Default_CullNear.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Layers/Spawners/PCG_Spawn_Default_CullNear.uasset -------------------------------------------------------------------------------- /Content/Layers/Utils/PCG_Biome_GetExclusion.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Layers/Utils/PCG_Biome_GetExclusion.uasset -------------------------------------------------------------------------------- /Content/Layers/Utils/PCG_Biome_InExclusion_And_Debug.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Layers/Utils/PCG_Biome_InExclusion_And_Debug.uasset -------------------------------------------------------------------------------- /Content/Layers/Utils/PCG_SpawnMeshes.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/Layers/Utils/PCG_SpawnMeshes.uasset -------------------------------------------------------------------------------- /Content/PCG_BIomes_PreFilters.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/PCG_BIomes_PreFilters.uasset -------------------------------------------------------------------------------- /Content/PCG_Biomes_Main.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/PCG_Biomes_Main.uasset -------------------------------------------------------------------------------- /Content/PCG_World_Exclusion.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Content/PCG_World_Exclusion.uasset -------------------------------------------------------------------------------- /PCGLayeredBiomes.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "1.3", 5 | "FriendlyName": "PCG Layered Biomes", 6 | "Description": "PCG Layered Biomes is a plugin for Unreal Engine that allows you to create realistic and multilayered biomes using the PCG.", 7 | "Category": "Other", 8 | "CreatedBy": "LazyCatsDev", 9 | "CreatedByURL": "", 10 | "DocsURL": "https://pcg-layered-biomes.snazzydocs.com", 11 | "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/aa2d2e7e78e74b9da57f1297066597a0", 12 | "SupportURL": "mailto:lazycatsdev@gmail.com", 13 | "CanContainContent": true, 14 | "IsBetaVersion": false, 15 | "IsExperimentalVersion": false, 16 | "Installed": false, 17 | "Modules": [ 18 | { 19 | "Name": "PCGLayeredBiomes", 20 | "Type": "Runtime", 21 | "LoadingPhase": "PostConfigInit", 22 | "PlatformAllowList": [ "Win64", "Mac", "Linux", "IOS", "Android" ] 23 | } 24 | ], 25 | "Plugins": [ 26 | { 27 | "Name": "PCG", 28 | "Enabled": true 29 | } 30 | ] 31 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PCGLayeredBiomes 2 | 3 | PCG Layered Biomes is a plugin for Unreal Engine that enables the creation of realistic, multilayered biomes using PCG (Procedural Content Generation). The plugin includes only code and blueprints, no additional assets. 4 | 5 | > **Note**: This project is provided as-is and may not be actively developed or maintained due to limited time. Contributions and forks are welcome for anyone interested in further developing it. 6 | 7 | ## Key Features 8 | 9 | ### Core Idea 10 | The plugin divides the generation area into distinct biomes, each with separate logic and objects for unique biome generation. This setup allows for diverse biome environments with specific characteristics. 11 | 12 | ### Layered Generation 13 | Biome generation is handled layer by layer. Each layer is represented by a single PCG graph that references previously generated geometry, minimizing overlap and optimizing spatial coherence within each biome. 14 | 15 | ### Flexibility 16 | This approach enables the development of biomes with varying complexity without creating overly complex PCG graphs, providing a streamlined and efficient process for biome customization. 17 | 18 | ### PCG Knowledge Not Required 19 | No prior knowledge of PCG is necessary to utilize this plugin. A set of ready-made layers is included, allowing users to achieve substantial results right out of the box. 20 | 21 | ### Mesh-to-Actor Replacement with State Persistence (UE 5.4 ONLY) 22 | For Unreal Engine 5.4, the plugin supports the seamless replacement of meshes with actors, which is useful for dynamic interactions like tree chopping. This feature also includes support for saving and loading the game's last state, ensuring continuity in gameplay. 23 | 24 | - A sample project demonstrating this feature is available. 25 | - Learn more: [Watch the explanation](https://youtu.be/bSDhaORGlew) 26 | 27 | > **Note**: For an advanced and flexible alternative, consider using the built-in PCG Biomes Core solution available in UE 5.4. 28 | 29 | ## Additional Resources 30 | 31 | - **Documentation**: [PCG Layered Biomes Documentation](https://pcg-layered-biomes.snazzydocs.com) 32 | - **Brief Overview Video**: [Watch here](https://youtu.be/--WgVOKVePA) 33 | - **Tutorial**: [Watch the tutorial](https://youtu.be/w_Hq9T3iizU) 34 | 35 | ## Support 36 | For assistance, please contact: lazycatsdev@gmail.com 37 | -------------------------------------------------------------------------------- /Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lazycatsdev/PCGLayeredBiomes/a8de134bdb4bf5342432437a1e85fb6951f4babb/Resources/Icon128.png -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/PCGLayeredBiomes.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class PCGLayeredBiomes : ModuleRules 6 | { 7 | public PCGLayeredBiomes(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicIncludePaths.AddRange( 12 | new string[] { 13 | // ... add public include paths required here ... 14 | } 15 | ); 16 | 17 | 18 | PrivateIncludePaths.AddRange( 19 | new string[] { 20 | // ... add other private include paths required here ... 21 | } 22 | ); 23 | 24 | 25 | PublicDependencyModuleNames.AddRange( 26 | new string[] 27 | { 28 | "Core", 29 | "CoreUObject", 30 | "Engine", 31 | "PCG", 32 | "DeveloperSettings", 33 | // ... add other public dependencies that you statically link with here ... 34 | } 35 | ); 36 | 37 | 38 | PrivateDependencyModuleNames.AddRange( 39 | new string[] 40 | { 41 | // ... add private dependencies that you statically link with here ... 42 | } 43 | ); 44 | 45 | 46 | DynamicallyLoadedModuleNames.AddRange( 47 | new string[] 48 | { 49 | // ... add any modules that your module loads dynamically here ... 50 | } 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/Biomes/LBBiomesSettings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "Biomes/LBBiomesSettings.h" 26 | 27 | #include "LBBiomesPCGUtils.h" 28 | #include "Biomes/LBPCGBiomesBaseFilter.h" 29 | #include "Serialization/ArchiveCrc32.h" 30 | 31 | bool ULBBiomesData::DetectBiome(const FPCGPoint& Point, const UPCGMetadata* Metadata, FName& OutBiome, int& OutPriority) const 32 | { 33 | static const FName PriorityName = "BiomePriority"; 34 | static const FName BiomeName = "Biome"; 35 | 36 | OutPriority = ULBBiomesPCGUtils::GetInteger32Attribute(Point, Metadata, PriorityName); 37 | OutBiome = ULBBiomesPCGUtils::GetNameAttribute(Point, Metadata, BiomeName); 38 | 39 | for (const auto& Biome: Biomes) 40 | { 41 | bool AllMatched = true; 42 | for (const auto& Filter: Biome.Filters) 43 | { 44 | if (!Filter || !Filter->Filter(Point, Metadata)) 45 | { 46 | AllMatched = false; 47 | break; 48 | } 49 | } 50 | if (AllMatched) 51 | { 52 | // First match is the best one, but we should take to account value from point 53 | if (Biome.Priority < OutPriority) 54 | { 55 | OutBiome = Biome.Name; 56 | OutPriority = Biome.Priority; 57 | } 58 | break; 59 | } 60 | } 61 | return !OutBiome.IsNone(); 62 | } 63 | 64 | 65 | FLBBiomeSettings_Named::FLBBiomeSettings_Named(FName InName, FLBBiomeSettings InSettings) 66 | : FLBBiomeSettings(InSettings) 67 | , Name(InName) 68 | { 69 | } 70 | 71 | FPCGCrc ULBBiomesSettings::ComputeCrc() 72 | { 73 | FPCGCrc Result(Biomes.Num()); 74 | for (auto& Item : Biomes) 75 | { 76 | FArchiveCrc32 Ar; 77 | Ar << Item.Key; 78 | Ar << Item.Value; 79 | Result.Combine(Ar.GetCrc()); 80 | } 81 | return Result; 82 | } 83 | 84 | ULBBiomesData* ULBBiomesSettings::Prepare() const 85 | { 86 | auto* Result = NewObject(); 87 | 88 | Result->Biomes.Reserve(Biomes.Num()); 89 | 90 | for (const auto& [Name, Biome]: Biomes) 91 | { 92 | Result->Biomes.Emplace(Name, Biome); 93 | } 94 | 95 | Result->Biomes.StableSort([](const auto& A, const auto& B) { return A.Priority < B.Priority; } ); 96 | 97 | return Result; 98 | } 99 | 100 | const FLBBiomeSettings* ULBBiomesSettings::FindSettings(FName Name) const 101 | { 102 | return Biomes.Find(Name); 103 | } 104 | 105 | #if WITH_EDITOR 106 | static FLinearColor GetNextColor() 107 | { 108 | constexpr int NumPredefinedColors = 30; 109 | constexpr FLinearColor PredefinedColors[NumPredefinedColors] = { 110 | FLinearColor(0.247059, 0.705882, 0.988235, 1.000000), 111 | FLinearColor(0.027451, 0.949020, 0.603922, 1.000000), 112 | FLinearColor(0.992157, 0.486275, 0.129412, 1.000000), 113 | FLinearColor(0.823529, 0.168627, 0.788235, 1.000000), 114 | FLinearColor(0.992157, 0.250980, 0.501961, 1.000000), 115 | FLinearColor(0.000000, 0.956863, 0.854902, 1.000000), 116 | FLinearColor(1.000000, 0.992157, 0.392157, 1.000000), 117 | FLinearColor(0.984314, 0.105882, 0.764706, 1.000000), 118 | FLinearColor(0.376471, 0.219608, 0.815686, 1.000000), 119 | FLinearColor(0.890196, 0.725490, 0.203922, 1.000000), 120 | FLinearColor(0.207843, 0.956863, 0.964706, 1.000000), 121 | FLinearColor(0.047059, 0.603922, 0.988235, 1.000000), 122 | FLinearColor(0.000000, 0.854902, 0.419608, 1.000000), 123 | FLinearColor(0.952941, 0.368627, 0.160784, 1.000000), 124 | FLinearColor(0.788235, 0.164706, 0.701961, 1.000000), 125 | FLinearColor(0.988235, 0.156863, 0.443137, 1.000000), 126 | FLinearColor(0.109804, 0.827451, 0.788235, 1.000000), 127 | FLinearColor(0.988235, 0.949020, 0.258824, 1.000000), 128 | FLinearColor(0.972549, 0.098039, 0.658824, 1.000000), 129 | FLinearColor(0.298039, 0.168627, 0.721569, 1.000000), 130 | FLinearColor(0.803922, 0.635294, 0.203922, 1.000000), 131 | FLinearColor(0.117647, 0.878431, 0.913725, 1.000000), 132 | FLinearColor(0.086275, 0.443137, 0.992157, 1.000000), 133 | FLinearColor(0.000000, 0.666667, 0.321569, 1.000000), 134 | FLinearColor(0.921569, 0.258824, 0.078431, 1.000000), 135 | FLinearColor(0.670588, 0.156863, 0.576471, 1.000000), 136 | FLinearColor(0.992157, 0.105882, 0.298039, 1.000000), 137 | FLinearColor(0.039216, 0.752941, 0.709804, 1.000000), 138 | FLinearColor(0.996078, 0.901961, 0.372549, 1.000000), 139 | FLinearColor(0.905882, 0.086275, 0.600000, 1.000000) 140 | }; 141 | static int ColorIndex = 0; 142 | if (ColorIndex < NumPredefinedColors) 143 | { 144 | return PredefinedColors[++ColorIndex]; 145 | } 146 | return FLinearColor::MakeRandomColor(); 147 | } 148 | 149 | void ULBBiomesSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) 150 | { 151 | Super::PostEditChangeProperty(PropertyChangedEvent); 152 | 153 | if(PropertyChangedEvent.GetPropertyName() == GET_MEMBER_NAME_CHECKED(ULBBiomesData, Biomes)) 154 | { 155 | for (auto& Pair : Biomes) 156 | { 157 | if (Pair.Value.DebugColor == FLinearColor::Transparent) 158 | { 159 | Pair.Value.DebugColor = GetNextColor(); 160 | } 161 | } 162 | } 163 | } 164 | #endif 165 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/Biomes/Layers/LBGenericBiomeLayer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "Biomes/Layers/LBGenericBiomeLayer.h" 26 | 27 | ULBGenericBiomeLayer::ULBGenericBiomeLayer() 28 | { 29 | Stream.GenerateNewSeed(); 30 | 31 | Seed = Stream.GetUnsignedInt(); 32 | NoiseSeed = Stream.FRandRange(0, 10000); 33 | } 34 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/Graph/LBPCGBiomesNoise.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "Graph/LBPCGBiomesNoise.h" 26 | #include "GameFramework/Actor.h" 27 | 28 | #include "PCGComponent.h" 29 | #include "PCGContext.h" 30 | #include "PCGPin.h" 31 | 32 | #include "Data/PCGPointData.h" 33 | #include "Data/PCGSpatialData.h" 34 | #include "Helpers/PCGAsync.h" 35 | #include "Helpers/PCGHelpers.h" 36 | #include "Helpers/PCGSettingsHelpers.h" 37 | #include "LBBiomesPCGUtils.h" 38 | 39 | #define LOCTEXT_NAMESPACE "PCGBiomesNoise" 40 | 41 | ULBPCGBiomesNoiseSettings::ULBPCGBiomesNoiseSettings() 42 | { 43 | ValueTarget.SetPointProperty(EPCGPointProperties::Density); 44 | } 45 | 46 | TArray ULBPCGBiomesNoiseSettings::InputPinProperties() const 47 | { 48 | return Super::DefaultPointInputPinProperties(); 49 | } 50 | 51 | TArray ULBPCGBiomesNoiseSettings::OutputPinProperties() const 52 | { 53 | return Super::DefaultPointOutputPinProperties(); 54 | } 55 | 56 | FPCGElementPtr ULBPCGBiomesNoiseSettings::CreateElement() const 57 | { 58 | return MakeShared(); 59 | } 60 | 61 | namespace PCGBiomesNoise 62 | { 63 | // the useful ranges here are very small so make input easier 64 | static const double MAGIC_SCALE_FACTOR = 0.0001; 65 | 66 | inline double Fract(double X) 67 | { 68 | return X - FMath::Floor(X); 69 | } 70 | 71 | inline FVector2D Floor(FVector2D X) 72 | { 73 | return FVector2D(FMath::Floor(X.X), FMath::Floor(X.Y)); 74 | } 75 | 76 | inline FInt32Point FloorInt(FVector2D X) 77 | { 78 | return FInt32Point(FMath::FloorToInt(X.X), FMath::FloorToInt(X.Y)); 79 | } 80 | 81 | inline FVector2D ToVec2D(FInt32Point V) 82 | { 83 | return FVector2D(double(V.X), double(V.Y)); 84 | } 85 | 86 | inline FVector2D Fract(FVector2D V) 87 | { 88 | return FVector2D(Fract(V.X), Fract(V.Y)); 89 | } 90 | 91 | inline double ValueHash(FVector2D Position) 92 | { 93 | Position = 50.0 * Fract(Position * 0.3183099 + FVector2D(0.71, 0.113)); 94 | return -1.0 + 2.0 * Fract(Position.X * Position.Y * (Position.X + Position.Y)); 95 | } 96 | 97 | inline double Noise2D(FVector2D Position) 98 | { 99 | const FVector2D FloorPosition = Floor(Position); 100 | const FVector2D Fraction = Position - FloorPosition; 101 | const FVector2D U = Fraction * Fraction * (FVector2D(3.0, 3.0) - 2.0 * Fraction); 102 | 103 | return FMath::Lerp( 104 | FMath::Lerp(ValueHash(FloorPosition), ValueHash(FloorPosition + FVector2D(1.0, 0.0)), U.X), 105 | FMath::Lerp(ValueHash(FloorPosition + FVector2D(0.0, 1.0)), ValueHash(FloorPosition + FVector2D(1.0, 1.0)), U.X), 106 | U.Y 107 | ); 108 | } 109 | 110 | inline FVector2D MultiplyMatrix2D(FVector2D Point, const FVector2D (&Mat2)[2]) 111 | { 112 | return Point.X * Mat2[0] + Point.Y * Mat2[1]; 113 | } 114 | 115 | // takes a cell id and produces a pseudo random vector offset 116 | inline FVector2D VoronoiHash2D(FInt32Point Cell) 117 | { 118 | const FVector2D P = ToVec2D(Cell); 119 | 120 | // this is some arbitrary large random scale+rotation+skew 121 | const FVector2D P2 = FVector2D( 122 | P.Dot(FVector2D(127.1, 311.7)), 123 | P.Dot(FVector2D(269.5, 183.3)) 124 | ); 125 | 126 | // further scale the results by a big number 127 | return FVector2D( 128 | Fract(FMath::Sin(P2.X) * 17.1717) - 0.5, 129 | Fract(FMath::Sin(P2.Y) * 17.1717) - 0.5 130 | ); 131 | } 132 | 133 | double CalcFractionalBrownian2D(FVector2D Position, int32 Iterations) 134 | { 135 | double Z = 0.5; 136 | double Result = 0.0; 137 | 138 | // just some fixed random rotation and scale numbers 139 | const FVector2D RotScale[] = {{1.910673, -0.5910404}, {0.5910404, 1.910673}}; 140 | 141 | for (int32 I = 0; I < Iterations; ++I) 142 | { 143 | Result += FMath::Abs(Noise2D(Position)) * Z; 144 | Z *= 0.5; 145 | Position = MultiplyMatrix2D(Position, RotScale); 146 | } 147 | 148 | return Result; 149 | } 150 | 151 | const FVector2D PerlinM[] = {{1.6, 1.2}, {-1.2, 1.6}}; 152 | 153 | double CalcPerlin2D(FVector2D Position, int32 Iterations) 154 | { 155 | double Value = 0.0; 156 | 157 | double Strength = 1.0; 158 | 159 | for (int32 N = 0; N < Iterations; ++N) 160 | { 161 | Strength *= 0.5; 162 | Value += Strength * Noise2D(Position); 163 | Position = MultiplyMatrix2D(Position, PerlinM); 164 | } 165 | 166 | return 0.5 + 0.5 * Value; 167 | } 168 | 169 | double ApplyContrast(double Value, double Contrast) 170 | { 171 | // early out for default 1.0 contrast, the math should be the same 172 | if (Contrast == 1.0) 173 | { 174 | return Value; 175 | } 176 | 177 | if (Contrast <= 0.0) 178 | { 179 | return 0.5; 180 | } 181 | 182 | Value = FMath::Clamp(Value, 0.0, 1.0); 183 | 184 | if (Value == 1.0) 185 | { 186 | return 1.0; 187 | } 188 | 189 | return 1.0 / (1.0 + FMath::Pow(Value / (1.0 - Value), -Contrast)); 190 | } 191 | 192 | FLocalCoordinates2D CalcLocalCoordinates2D(const FBox& ActorLocalBox, const FTransform& ActorTransformInverse, FVector2D Scale, const FVector& InPosition) 193 | { 194 | if (!ActorLocalBox.IsValid) 195 | { 196 | return {}; 197 | } 198 | 199 | const FVector2D LocalPosition = FVector2D(ActorTransformInverse.TransformPosition(InPosition)); 200 | 201 | const double LeftDist = LocalPosition.X-ActorLocalBox.Min.X; 202 | const double RightDist = LocalPosition.X-ActorLocalBox.Max.X; 203 | 204 | const double TopDist = LocalPosition.Y-ActorLocalBox.Min.Y; 205 | const double BottomDist = LocalPosition.Y-ActorLocalBox.Max.Y; 206 | 207 | FLocalCoordinates2D Result; 208 | 209 | Result.X0 = LeftDist * Scale.X; 210 | Result.X1 = RightDist * Scale.X; 211 | Result.Y0 = TopDist * Scale.Y; 212 | Result.Y1 = BottomDist * Scale.Y; 213 | 214 | Result.FracX = FMath::Clamp(LeftDist / (ActorLocalBox.Max.X - ActorLocalBox.Min.X), 0.0, 1.0); 215 | Result.FracY = FMath::Clamp(TopDist / (ActorLocalBox.Max.Y - ActorLocalBox.Min.Y), 0.0, 1.0); 216 | 217 | return Result; 218 | }; 219 | 220 | struct FSharedParams 221 | { 222 | FPCGContext* Context = nullptr; 223 | FTransform ActorTransformInverse; 224 | FBox ActorLocalBox; 225 | FTransform Transform; 226 | 227 | double Brightness; 228 | double Contrast; 229 | int32 Iterations; 230 | bool bTiling; 231 | }; 232 | 233 | struct FBufferParams 234 | { 235 | const UPCGPointData* InputPointData = nullptr; 236 | UPCGPointData* OutputPointData = nullptr; 237 | }; 238 | 239 | template 240 | void DoFractal2D(const FSharedParams& SharedParams, const FBufferParams& BufferParams, const ULBPCGBiomesNoiseSettings& Settings, FractalNoiseFunc&& FractalNoise) 241 | { 242 | const TArray& SrcPoints = BufferParams.InputPointData->GetPoints(); 243 | 244 | struct FProcessResults 245 | { 246 | TArray Points; 247 | TArray Values; 248 | }; 249 | 250 | FProcessResults Results; 251 | 252 | FPCGAsync::AsyncProcessingOneToOneEx( 253 | SharedParams.Context ? &SharedParams.Context->AsyncState : nullptr, 254 | SrcPoints.Num(), 255 | [&Results, Count = SrcPoints.Num()]() 256 | { 257 | // initialize 258 | Results.Points.SetNumUninitialized(Count); 259 | Results.Values.SetNumUninitialized(Count); 260 | }, 261 | [ 262 | &SharedParams, 263 | &BufferParams, 264 | &Results, 265 | &SrcPoints, 266 | &FractalNoise 267 | ](const int32 ReadIndex, const int32 WriteIndex) 268 | { 269 | const FPCGPoint& InPoint = SrcPoints[ReadIndex]; 270 | FPCGPoint& OutPoint = Results.Points[WriteIndex]; 271 | 272 | OutPoint = InPoint; 273 | 274 | const FVector PointPos = InPoint.Transform.GetTranslation(); 275 | 276 | double Value = 0.0; 277 | 278 | if (SharedParams.bTiling) 279 | { 280 | const FLocalCoordinates2D LocalCoords = CalcLocalCoordinates2D( 281 | SharedParams.ActorLocalBox, 282 | SharedParams.ActorTransformInverse, 283 | FVector2D(SharedParams.Transform.GetScale3D()), 284 | PointPos 285 | ); 286 | 287 | Value = FMath::BiLerp( 288 | FractalNoise(FVector2D(LocalCoords.X0, LocalCoords.Y0), SharedParams.Iterations), 289 | FractalNoise(FVector2D(LocalCoords.X1, LocalCoords.Y0), SharedParams.Iterations), 290 | FractalNoise(FVector2D(LocalCoords.X0, LocalCoords.Y1), SharedParams.Iterations), 291 | FractalNoise(FVector2D(LocalCoords.X1, LocalCoords.Y1), SharedParams.Iterations), 292 | LocalCoords.FracX, 293 | LocalCoords.FracY 294 | ); 295 | } 296 | else 297 | { 298 | Value = FractalNoise(FVector2D(SharedParams.Transform.TransformPosition(PointPos)), SharedParams.Iterations); 299 | } 300 | 301 | Value = ApplyContrast(SharedParams.Brightness + Value, SharedParams.Contrast); 302 | 303 | Results.Values[WriteIndex] = Value; 304 | }, 305 | /* bEnableTimeSlicing */ false 306 | ); 307 | 308 | // now apply these results 309 | BufferParams.OutputPointData->GetMutablePoints() = MoveTemp(Results.Points); 310 | 311 | ULBBiomesPCGUtils::SetAttributeHelper(BufferParams.OutputPointData, Settings.ValueTarget, Results.Values); 312 | } 313 | } 314 | 315 | bool FLBPCGBiomesNoise::ExecuteInternal(FPCGContext* Context) const 316 | { 317 | TRACE_CPUPROFILER_EVENT_SCOPE(FPCGNoise::Execute); 318 | 319 | const ULBPCGBiomesNoiseSettings* Settings = Context->GetInputSettings(); 320 | check(Settings); 321 | 322 | FRandomStream RandomSource(Context->GetSeed()); 323 | 324 | const FVector RandomOffset = Settings->RandomOffset * FVector(RandomSource.GetFraction(), RandomSource.GetFraction(), RandomSource.GetFraction()); 325 | 326 | PCGBiomesNoise::FSharedParams SharedParams; 327 | SharedParams.Context = Context; 328 | 329 | if (!Context->SourceComponent.IsValid()) 330 | { 331 | PCGE_LOG(Error, GraphAndLog, LOCTEXT("NoSourceComponent", "No Source Component.")); 332 | return true; 333 | } 334 | 335 | { 336 | AActor* Actor = Context->SourceComponent->GetOwner(); 337 | if (!Actor) 338 | { 339 | PCGE_LOG(Error, GraphAndLog, LOCTEXT("NoActor", "Source Component has no actor")); 340 | return true; 341 | } 342 | 343 | SharedParams.ActorLocalBox = PCGHelpers::GetActorLocalBounds(Actor); 344 | SharedParams.ActorLocalBox.Min *= Actor->GetTransform().GetScale3D(); 345 | SharedParams.ActorLocalBox.Max *= Actor->GetTransform().GetScale3D(); 346 | 347 | const FTransform ActorTransform = FTransform(Actor->GetTransform().Rotator(), Actor->GetTransform().GetTranslation(), FVector::One()); 348 | SharedParams.ActorTransformInverse = ActorTransform.Inverse(); 349 | } 350 | 351 | SharedParams.Transform = FTransform(FRotator::ZeroRotator, RandomOffset, FVector(PCGBiomesNoise::MAGIC_SCALE_FACTOR) * Settings->Scale); 352 | SharedParams.Brightness = Settings->Brightness; 353 | SharedParams.Contrast = Settings->Contrast; 354 | SharedParams.bTiling = Settings->bTiling; 355 | SharedParams.Iterations = FMath::Max(1, Settings->Iterations); // clamped in meta properties but things will crash if it's < 1 356 | 357 | TArray Inputs = Context->InputData.GetInputsByPin(PCGPinConstants::DefaultInputLabel); 358 | for (const FPCGTaggedData& Input : Inputs) 359 | { 360 | PCGBiomesNoise::FBufferParams BufferParams; 361 | 362 | BufferParams.InputPointData = Cast(Input.Data); 363 | 364 | if (!BufferParams.InputPointData) 365 | { 366 | PCGE_LOG(Error, GraphAndLog, LOCTEXT("InvalidInputData", "Invalid input data (only supports point data).")); 367 | continue; 368 | } 369 | 370 | BufferParams.OutputPointData = NewObject(); 371 | BufferParams.OutputPointData->InitializeFromData(BufferParams.InputPointData); 372 | Context->OutputData.TaggedData.Add_GetRef(Input).Data = BufferParams.OutputPointData; 373 | 374 | DoFractal2D(SharedParams, BufferParams, *Settings, &PCGBiomesNoise::CalcPerlin2D); 375 | } 376 | 377 | return true; 378 | } 379 | 380 | #undef LOCTEXT_NAMESPACE -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/Graph/LBPCGExplicitBiomeFromSplines.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "Graph/LBPCGExplicitBiomeFromSplines.h" 26 | 27 | #include "EngineUtils.h" 28 | #include "LBExplicitBiomeActor.h" 29 | #include "PCGComponent.h" 30 | #include "PCGModule.h" 31 | #include "Data/PCGSpatialData.h" 32 | #include "Elements/Metadata/PCGMetadataElementCommon.h" 33 | #include "Helpers/PCGDynamicTrackingHelpers.h" 34 | #include "Helpers/PCGHelpers.h" 35 | 36 | #define LOCTEXT_NAMESPACE "PCGExplicitBiomeFromSplines" 37 | 38 | ULBPCGExplicitBiomeFromSplines::ULBPCGExplicitBiomeFromSplines() 39 | { 40 | bDisplayModeSettings = false; 41 | Mode = EPCGGetDataFromActorMode::ParseActorComponents; 42 | } 43 | 44 | FPCGElementPtr ULBPCGExplicitBiomeFromSplines::CreateElement() const 45 | { 46 | return MakeShared(); 47 | } 48 | 49 | TArray ULBPCGExplicitBiomeFromSplines::OutputPinProperties() const 50 | { 51 | TArray PinProperties; 52 | PinProperties.Emplace(PCGPinConstants::DefaultOutputLabel, EPCGDataType::Spline); 53 | 54 | return PinProperties; 55 | } 56 | 57 | FPCGContext* FLBPCGExplicitBiomeFromSplines::Initialize(const FPCGDataCollection& InputData, TWeakObjectPtr SourceComponent, const UPCGNode* Node) 58 | { 59 | FPCGDataFromActorContext* Context = new FPCGDataFromActorContext(); 60 | Context->InputData = InputData; 61 | Context->SourceComponent = SourceComponent; 62 | Context->Node = Node; 63 | 64 | return Context; 65 | } 66 | 67 | bool FLBPCGExplicitBiomeFromSplines::ExecuteInternal(FPCGContext* InContext) const 68 | { 69 | TRACE_CPUPROFILER_EVENT_SCOPE(FPCGDataFromActorElement::Execute); 70 | 71 | check(InContext); 72 | FPCGDataFromActorContext* Context = static_cast(InContext); 73 | 74 | const UPCGDataFromActorSettings* Settings = Context->GetInputSettings(); 75 | check(Settings); 76 | 77 | if (!Context->bPerformedQuery) 78 | { 79 | TFunction BoundsCheck = [](const AActor*) -> bool { return true; }; 80 | const UPCGComponent* PCGComponent = Context->SourceComponent.IsValid() ? Context->SourceComponent.Get() : nullptr; 81 | const AActor* Self = PCGComponent ? PCGComponent->GetOwner() : nullptr; 82 | if (Self && Settings->ActorSelector.bMustOverlapSelf) 83 | { 84 | // Capture ActorBounds by value because it goes out of scope 85 | const FBox ActorBounds = PCGHelpers::GetActorBounds(Self); 86 | BoundsCheck = [ActorBounds, PCGComponent](const AActor* OtherActor) -> bool 87 | { 88 | const FBox OtherActorBounds = OtherActor ? PCGHelpers::GetGridBounds(OtherActor, PCGComponent) : FBox(EForceInit::ForceInit); 89 | return ActorBounds.Intersect(OtherActorBounds); 90 | }; 91 | } 92 | 93 | Context->FoundActors.Reset(); 94 | 95 | const auto* World = Context->SourceComponent->GetWorld(); 96 | for (TActorIterator It(World, ALBExplicitBiomeActor::StaticClass()); It; ++It) 97 | { 98 | AActor* Actor = *It; 99 | if (BoundsCheck(Actor)) 100 | { 101 | Context->FoundActors.Add(Actor); 102 | } 103 | } 104 | 105 | Context->bPerformedQuery = true; 106 | 107 | if (Context->FoundActors.IsEmpty()) 108 | { 109 | return true; 110 | } 111 | } 112 | 113 | if (Context->bPerformedQuery) 114 | { 115 | ProcessActors(Context, Settings, Context->FoundActors); 116 | 117 | // Register dynamic tracking 118 | #if WITH_EDITOR 119 | FPCGDynamicTrackingHelper::AddSingleDynamicTrackingKey(Context, FPCGSelectionKey(ALBExplicitBiomeActor::StaticClass()), /*bIsCulled=*/false); 120 | #endif // WITH_EDITOR 121 | } 122 | 123 | return true; 124 | } 125 | 126 | void FLBPCGExplicitBiomeFromSplines::ProcessActors(FPCGContext* Context, const UPCGDataFromActorSettings* Settings, const TArray& FoundActors) const 127 | { 128 | for (AActor* Actor : FoundActors) 129 | { 130 | ProcessActor(Context, Settings, Actor); 131 | } 132 | } 133 | 134 | void FLBPCGExplicitBiomeFromSplines::ProcessActor(FPCGContext* Context, const UPCGDataFromActorSettings* Settings, AActor* FoundActor) const 135 | { 136 | check(Context); 137 | check(Settings); 138 | 139 | if (!FoundActor || !IsValid(FoundActor)) 140 | { 141 | return; 142 | } 143 | 144 | TArray& Outputs = Context->OutputData.TaggedData; 145 | 146 | const auto Collection = UPCGComponent::CreateActorPCGDataCollection(FoundActor, Context->SourceComponent.Get(), Settings->GetDataFilter(), true); 147 | 148 | if (const auto* Actor = Cast(FoundActor)) 149 | { 150 | for (auto& Item: Collection.TaggedData) 151 | { 152 | if (const UPCGSpatialData* SpatialData = Cast(Item.Data)) 153 | { 154 | auto* Attribute = ClearOrCreateAttribute(SpatialData->Metadata, "Biome", Actor->Biome); 155 | if (!Attribute) 156 | { 157 | PCGE_LOG(Error, GraphAndLog, LOCTEXT("ErrorCreatingAttribute", "Error while creating attribute 'Biome'")); 158 | } 159 | } 160 | } 161 | } 162 | 163 | Outputs += Collection.TaggedData; 164 | } 165 | 166 | FPCGMetadataAttributeBase* FLBPCGExplicitBiomeFromSplines::ClearOrCreateAttribute(UPCGMetadata* Metadata, const FName OutputAttributeName, const FName Value) 167 | { 168 | check(Metadata); 169 | 170 | return PCGMetadataElementCommon::ClearOrCreateAttribute(Metadata, OutputAttributeName, Value); 171 | } 172 | 173 | #undef LOCTEXT_NAMESPACE 174 | 175 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/Graph/LBPCGExtractBiomeData.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "Graph/LBPCGExtractBiomeData.h" 26 | 27 | #include "LBBiomesPCGUtils.h" 28 | #include "LBBiomesSpawnManager.h" 29 | #include "PCGContext.h" 30 | #include "PCGParamData.h" 31 | #include "PCGPin.h" 32 | #include "Biomes/LBBiomesSettings.h" 33 | #include "Biomes/Layers/LBBaseBiomeLayer.h" 34 | 35 | #if WITH_EDITOR 36 | #include "Helpers/PCGDynamicTrackingHelpers.h" 37 | #endif 38 | 39 | #define LOCTEXT_NAMESPACE "PCGSetWeightedMeshFromSet" 40 | 41 | TArray ULBPCGExtractBiomeData::InputPinProperties() const 42 | { 43 | TArray Properties; 44 | Properties.Emplace(TEXT("Biome"), EPCGDataType::Param); 45 | return Properties; 46 | } 47 | 48 | TArray ULBPCGExtractBiomeData::OutputPinProperties() const 49 | { 50 | TArray PinProperties; 51 | 52 | PinProperties.Emplace("Layers", EPCGDataType::Param); 53 | PinProperties.Emplace("Biome Settings", EPCGDataType::Param, true, false); 54 | 55 | return PinProperties; 56 | } 57 | 58 | FPCGElementPtr ULBPCGExtractBiomeData::CreateElement() const 59 | { 60 | return MakeShared(); 61 | } 62 | 63 | bool FLBPCGExtractBiomeData::ExecuteInternal(FPCGContext* Context) const 64 | { 65 | TRACE_CPUPROFILER_EVENT_SCOPE(FPCGExecuteLayers::Execute); 66 | 67 | const auto* Settings = Context->GetInputSettings(); 68 | check(Settings); 69 | 70 | FName Biome; 71 | 72 | const auto& Params = Context->InputData.GetParamsByPin("Biome"); 73 | if (Params.IsEmpty()) 74 | { 75 | return true; 76 | } 77 | 78 | const auto& Param = Params.Last(); 79 | if (const auto* BiomeParam = Cast(Param.Data)) 80 | { 81 | auto* BiomeAttribute = static_cast*>(BiomeParam->ConstMetadata()->GetConstAttribute("Biome")); 82 | Biome = BiomeAttribute->GetValue(0); 83 | } 84 | else 85 | { 86 | PCGE_LOG(Error, GraphAndLog, LOCTEXT("InvalidInputData", "Biome pin is not Param (Attribute Set) pin!")); 87 | return true; 88 | } 89 | 90 | const auto* Manager = ULBBiomesSpawnManager::GetManager(Context->SourceComponent.Get()); 91 | if (!Manager) 92 | { 93 | PCGE_LOG(Error, GraphAndLog, LOCTEXT("NoActorsManager", "Source Actor has no ULBBiomesSpawnManager component")); 94 | return true; 95 | } 96 | 97 | if (auto* BiomeSettings = Manager->FindSettings(Biome)) 98 | { 99 | { 100 | TObjectPtr OutData = NewObject(); 101 | PCGMetadataEntryKey MetadataKey = OutData->Metadata->AddEntry(); 102 | for (TFieldIterator FieldIt(BiomeSettings->StaticStruct(), EFieldIterationFlags::IncludeSuper); FieldIt; ++FieldIt) 103 | { 104 | const FString FieldName = BiomeSettings->StaticStruct()->GetAuthoredNameForField(*FieldIt); 105 | const FName AttributeName(FieldName); 106 | 107 | OutData->Metadata->SetAttributeFromDataProperty(AttributeName, MetadataKey, BiomeSettings, *FieldIt, true); 108 | } 109 | 110 | Context->OutputData.TaggedData.Add({OutData, {}, "Biome Settings", false}); 111 | } 112 | 113 | for (const auto& Layer: BiomeSettings->Layers) 114 | { 115 | if (!Layer) 116 | { 117 | continue; 118 | } 119 | 120 | TObjectPtr OutData = NewObject(); 121 | PCGMetadataEntryKey MetadataKey = OutData->Metadata->AddEntry(); 122 | for (const FProperty* Property = Layer->GetClass()->PropertyLink; Property != nullptr; Property = Property->PropertyLinkNext) 123 | { 124 | OutData->Metadata->SetAttributeFromProperty(Property->GetFName(), MetadataKey, Layer.Get(), Property, true); 125 | } 126 | 127 | Context->OutputData.TaggedData.Add({OutData, {}, "Layers", false}); 128 | } 129 | } 130 | else 131 | { 132 | PCGE_LOG(Warning, GraphAndLog, LOCTEXT("InvalidBiome", "Settings doesn't have biome")); 133 | return true; 134 | } 135 | 136 | // Register dynamic tracking 137 | #if WITH_EDITOR 138 | FPCGDynamicTrackingHelper::AddSingleDynamicTrackingKey(Context, FPCGSelectionKey::CreateFromPath(Manager->GetBiomesSoftPath()), /*bIsCulled=*/false); 139 | #endif // WITH_EDITOR 140 | 141 | return true; 142 | } 143 | 144 | void FLBPCGExtractBiomeData::GetDependenciesCrc(const FPCGDataCollection& InInput, const UPCGSettings* InSettings, 145 | UPCGComponent* InComponent, FPCGCrc& OutCrc) const 146 | { 147 | FPCGCrc Crc; 148 | FPCGPointProcessingElementBase::GetDependenciesCrc(InInput, InSettings, InComponent, Crc); 149 | 150 | const auto* Manager = ULBBiomesSpawnManager::GetManager(InComponent); 151 | if (!Manager) 152 | { 153 | OutCrc = Crc; 154 | return; 155 | } 156 | 157 | Crc.Combine(Manager->GetBiomesCrc()); 158 | 159 | OutCrc = Crc; 160 | } 161 | 162 | #undef LOCTEXT_NAMESPACE 163 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/Graph/LBPCGGetAttributes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "Graph/LBPCGGetAttributes.h" 26 | 27 | #include "LBBiomesPCGUtils.h" 28 | #include "PCGContext.h" 29 | #include "PCGParamData.h" 30 | #include "PCGPin.h" 31 | 32 | #define LOCTEXT_NAMESPACE "PCGGetAttributesSettings" 33 | 34 | TArray ULBPCGGetAttributesSettings::InputPinProperties() const 35 | { 36 | TArray Properties; 37 | Properties.Emplace(TEXT("Params"), EPCGDataType::Param); 38 | return Properties; 39 | } 40 | 41 | TArray ULBPCGGetAttributesSettings::OutputPinProperties() const 42 | { 43 | TArray PinProperties; 44 | 45 | for (const auto& Attribute: Attributes) 46 | { 47 | PinProperties.Emplace(Attribute, EPCGDataType::Param, true, false); 48 | } 49 | 50 | return PinProperties; 51 | } 52 | 53 | FPCGElementPtr ULBPCGGetAttributesSettings::CreateElement() const 54 | { 55 | return MakeShared(); 56 | } 57 | 58 | bool FLBPCGGetAttributes::ExecuteInternal(FPCGContext* Context) const 59 | { 60 | const auto* Settings = Context->GetInputSettings(); 61 | check(Settings); 62 | 63 | const auto& InputParamsData = Context->InputData.GetParamsByPin("Params"); 64 | for (const auto& InputData: InputParamsData) 65 | { 66 | const auto& InputParams = Cast(InputData.Data); 67 | 68 | for (const auto& AttributeName: Settings->Attributes) 69 | { 70 | const auto* InMetadata = InputParams->ConstMetadata(); 71 | 72 | const auto* InAttribute = InMetadata->GetConstAttribute(AttributeName); 73 | if (!InAttribute) 74 | { 75 | return true; 76 | } 77 | 78 | TObjectPtr OutData = NewObject(); 79 | 80 | auto CreateAttribute = [this, Context, AttributeName, InAttribute, &OutData](auto DummyValue) -> bool 81 | { 82 | using AttributeType = decltype(DummyValue); 83 | 84 | const auto* TypedAttribute = static_cast*>(InAttribute); 85 | AttributeType Value = TypedAttribute->GetValue(0); 86 | 87 | FPCGMetadataAttribute* NewAttribute = static_cast*>( 88 | OutData->Metadata->CreateAttribute(AttributeName, Value, /*bAllowInterpolation=*/false, /*bOverrideParent=*/false)); 89 | 90 | if (!NewAttribute) 91 | { 92 | PCGE_LOG(Error, GraphAndLog, FText::Format(LOCTEXT("ErrorCreatingTargetAttribute", "Error while creating target attribute '{0}'"), FText::FromName(AttributeName))); 93 | return true; 94 | } 95 | 96 | NewAttribute->SetValue(OutData->Metadata->AddEntry(), Value); 97 | 98 | return true; 99 | }; 100 | 101 | if (PCGMetadataAttribute::CallbackWithRightType(InAttribute->GetTypeId(), MoveTemp(CreateAttribute))) 102 | { 103 | Context->OutputData.TaggedData.Add({OutData, {}, AttributeName, false}); 104 | } 105 | } 106 | } 107 | 108 | return true; 109 | } 110 | 111 | TArray ULBPCGGetAllAttributesFromSettings::InputPinProperties() const 112 | { 113 | TArray Properties; 114 | Properties.Emplace(TEXT("Params"), EPCGDataType::Param); 115 | return Properties; 116 | } 117 | 118 | TArray ULBPCGGetAllAttributesFromSettings::OutputPinProperties() const 119 | { 120 | TArray Properties; 121 | Properties.Emplace(TEXT("Params"), EPCGDataType::Param, true, false); 122 | Properties.Emplace(TEXT("Success"), EPCGDataType::Param, true, false); 123 | return Properties; 124 | } 125 | 126 | FPCGElementPtr ULBPCGGetAllAttributesFromSettings::CreateElement() const 127 | { 128 | return MakeShared(); 129 | } 130 | 131 | bool FLBPCGGetAllAttributesFrom::ExecuteInternal(FPCGContext* Context) const 132 | { 133 | const auto* Settings = Context->GetInputSettings(); 134 | check(Settings); 135 | 136 | const auto& InputParamsData = Context->InputData.GetParamsByPin("Params"); 137 | 138 | const bool IsSuccess = InputParamsData.IsValidIndex(Settings->DataIndex); 139 | const TObjectPtr SuccessData = NewObject(); 140 | ULBBiomesPCGUtils::CreateAndSetAttribute(NAME_None, SuccessData->Metadata, IsSuccess); 141 | Context->OutputData.TaggedData.Add({SuccessData, {}, "Success", false}); 142 | 143 | if (IsSuccess) 144 | { 145 | const auto& Params = InputParamsData[Settings->DataIndex]; 146 | Context->OutputData.TaggedData.Add({Params.Data, {}, "Params", false}); 147 | } 148 | 149 | return true; 150 | } 151 | 152 | #undef LOCTEXT_NAMESPACE 153 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/Graph/PCGSetWeightedMeshFromSet.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "Graph/LBPCGMeshFromSpawnManager.h" 26 | 27 | #include "Engine/StaticMesh.h" 28 | #include "LBBiomesPCGUtils.h" 29 | #include "PCGComponent.h" 30 | #include "PCGModule.h" 31 | #include "PCGPin.h" 32 | #include "LBPCGSpawnStructures.h" 33 | #include "LBBiomesSpawnManager.h" 34 | #include "LBRandomUtils.h" 35 | #include "Data/PCGPointData.h" 36 | #include "Helpers/PCGAsync.h" 37 | #include "Helpers/PCGDynamicTrackingHelpers.h" 38 | #include "Helpers/PCGHelpers.h" 39 | 40 | 41 | 42 | #define LOCTEXT_NAMESPACE "PCGFPCGMeshFromSpawnManager" 43 | 44 | ULBPCGMeshFromSpawnManagerSettings::ULBPCGMeshFromSpawnManagerSettings() 45 | { 46 | ValueTarget.SetAttributeName(TEXT("Mesh")); 47 | bUseSeed = true; 48 | } 49 | 50 | TArray ULBPCGMeshFromSpawnManagerSettings::InputPinProperties() const 51 | { 52 | return DefaultPointInputPinProperties(); 53 | } 54 | 55 | TArray ULBPCGMeshFromSpawnManagerSettings::OutputPinProperties() const 56 | { 57 | return DefaultPointOutputPinProperties(); 58 | } 59 | 60 | FPCGElementPtr ULBPCGMeshFromSpawnManagerSettings::CreateElement() const 61 | { 62 | return MakeShared(); 63 | } 64 | 65 | namespace PCGMeshSet 66 | { 67 | struct FSharedParams 68 | { 69 | FPCGContext* Context = nullptr; 70 | const TArray* Actors = nullptr; 71 | int TotalWeight = 0; 72 | int32 Seed = 0; 73 | }; 74 | 75 | struct FBufferParams 76 | { 77 | const UPCGPointData* InputPointData = nullptr; 78 | UPCGPointData* OutputPointData = nullptr; 79 | }; 80 | 81 | const FLBPCGSpawnInfo& SelectRandom(const FSharedParams& SharedParams, const FRandomStream& RandomSource) 82 | { 83 | if (SharedParams.TotalWeight <= 1) 84 | { 85 | return SharedParams.Actors->Last(); 86 | } 87 | 88 | const auto RandomWeight = RandomSource.RandRange(0, SharedParams.TotalWeight - 1); 89 | int CurWeight = 0; 90 | for (const auto& Item: *SharedParams.Actors) 91 | { 92 | CurWeight += Item.Weight; 93 | if (CurWeight > RandomWeight) 94 | { 95 | return Item; 96 | } 97 | } 98 | 99 | return SharedParams.Actors->Last(); 100 | } 101 | 102 | void ProcessPoints(const FSharedParams& SharedParams, const FBufferParams& BufferParams, const ULBPCGMeshFromSpawnManagerSettings& Settings) 103 | { 104 | const TArray& SrcPoints = BufferParams.InputPointData->GetPoints(); 105 | 106 | struct FProcessResults 107 | { 108 | TArray Points; 109 | TArray Values; 110 | TArray BoundsMin; 111 | TArray BoundsMax; 112 | }; 113 | 114 | FProcessResults Results; 115 | 116 | const bool ApplyBounds = Settings.ApplyMeshBounds; 117 | 118 | FPCGAsync::AsyncProcessingOneToOneEx( 119 | SharedParams.Context ? &SharedParams.Context->AsyncState : nullptr, 120 | SrcPoints.Num(), 121 | [&Results, Count = SrcPoints.Num(), ApplyBounds]() 122 | { 123 | // initialize 124 | Results.Points.SetNumUninitialized(Count); 125 | Results.Values.SetNum(Count); 126 | if (ApplyBounds) 127 | { 128 | Results.BoundsMin.SetNum(Count); 129 | Results.BoundsMax.SetNum(Count); 130 | } 131 | }, 132 | [ 133 | &SharedParams, 134 | &Results, 135 | &SrcPoints, 136 | ApplyBounds 137 | ](const int32 ReadIndex, const int32 WriteIndex) 138 | { 139 | const FPCGPoint& InPoint = SrcPoints[ReadIndex]; 140 | FPCGPoint& OutPoint = Results.Points[WriteIndex]; 141 | 142 | OutPoint = InPoint; 143 | FRandomStream RandomSource(PCGHelpers::ComputeSeed(SharedParams.Seed, InPoint.Seed)); 144 | 145 | const auto& Info = FLBRandomUtils::SelectRandom(*SharedParams.Actors, RandomSource, &SharedParams.TotalWeight); 146 | 147 | Results.Values[WriteIndex] = Info.Mesh.ToString(); 148 | 149 | if (ApplyBounds && Info.Mesh) 150 | { 151 | const auto Bounds = Info.Mesh->GetBounds(); 152 | Results.BoundsMin[WriteIndex] = Bounds.GetBox().Min; 153 | Results.BoundsMax[WriteIndex] = Bounds.GetBox().Max; 154 | } 155 | else if (ApplyBounds) 156 | { 157 | Results.BoundsMin[WriteIndex] = FVector::ZeroVector; 158 | Results.BoundsMax[WriteIndex] = FVector::ZeroVector; 159 | } 160 | }, 161 | /* bEnableTimeSlicing */ false 162 | ); 163 | 164 | // now apply these results 165 | BufferParams.OutputPointData->GetMutablePoints() = MoveTemp(Results.Points); 166 | 167 | ULBBiomesPCGUtils::SetAttributeHelper(BufferParams.OutputPointData, Settings.ValueTarget, Results.Values); 168 | 169 | if (ApplyBounds) 170 | { 171 | FPCGAttributePropertySelector BoundsMinSelector, BoundsMaxSelector; 172 | BoundsMinSelector.SetPointProperty(EPCGPointProperties::BoundsMin); 173 | BoundsMaxSelector.SetPointProperty(EPCGPointProperties::BoundsMax); 174 | 175 | ULBBiomesPCGUtils::SetAttributeHelper(BufferParams.OutputPointData, BoundsMinSelector, Results.BoundsMin); 176 | ULBBiomesPCGUtils::SetAttributeHelper(BufferParams.OutputPointData, BoundsMaxSelector, Results.BoundsMax); 177 | } 178 | } 179 | } 180 | 181 | bool FLBPCGMeshFromSpawnManager::ExecuteInternal(FPCGContext* Context) const 182 | { 183 | TRACE_CPUPROFILER_EVENT_SCOPE(FPCGNoise::Execute); 184 | 185 | const auto* Settings = Context->GetInputSettings(); 186 | check(Settings); 187 | 188 | PCGMeshSet::FSharedParams SharedParams; 189 | SharedParams.Context = Context; 190 | SharedParams.Seed = Context->GetSeed(); 191 | 192 | if (Settings->SetName.IsEmpty()) 193 | { 194 | return true; 195 | } 196 | 197 | const auto* Manager = ULBBiomesSpawnManager::GetManager(Context->SourceComponent.Get()); 198 | if (!Manager) 199 | { 200 | PCGE_LOG(Error, GraphAndLog, LOCTEXT("NoActorsManager", "Source Actor has no ULBBiomesSpawnManager component")); 201 | return true; 202 | } 203 | 204 | SharedParams.Actors = Manager->FindSet(Settings->SetName); 205 | if (!SharedParams.Actors) 206 | { 207 | PCGE_LOG(Error, GraphAndLog, LOCTEXT("NoSet", "Set not found in ULBBiomesSpawnManager component")); 208 | return true; 209 | } 210 | 211 | if (SharedParams.Actors->IsEmpty()) 212 | { 213 | return true; 214 | } 215 | 216 | // Calculate Total Weight 217 | SharedParams.TotalWeight = 0; 218 | for (const auto& Item: *SharedParams.Actors) 219 | { 220 | SharedParams.TotalWeight += Item.Weight; 221 | } 222 | 223 | if (SharedParams.TotalWeight == 0) 224 | { 225 | PCGE_LOG(Warning, GraphAndLog, LOCTEXT("WrongWeights", "All meshes in set has 0 weight - it's not supported")); 226 | return true; 227 | } 228 | 229 | TArray Inputs = Context->InputData.GetInputsByPin(PCGPinConstants::DefaultInputLabel); 230 | for (const FPCGTaggedData& Input : Inputs) 231 | { 232 | PCGMeshSet::FBufferParams BufferParams; 233 | 234 | BufferParams.InputPointData = Cast(Input.Data); 235 | 236 | if (!BufferParams.InputPointData) 237 | { 238 | PCGE_LOG(Error, GraphAndLog, LOCTEXT("InvalidInputData", "Invalid input data (only supports point data).")); 239 | continue; 240 | } 241 | 242 | BufferParams.OutputPointData = NewObject(); 243 | BufferParams.OutputPointData->InitializeFromData(BufferParams.InputPointData); 244 | Context->OutputData.TaggedData.Add_GetRef(Input).Data = BufferParams.OutputPointData; 245 | 246 | PCGMeshSet::ProcessPoints(SharedParams, BufferParams, *Settings); 247 | } 248 | 249 | // Register dynamic tracking 250 | #if WITH_EDITOR 251 | FPCGDynamicTrackingHelper::AddSingleDynamicTrackingKey(Context, 252 | FPCGSelectionKey::CreateFromPath(Manager->GetSpawnPresetSoftPath()), /*bIsCulled=*/false); 253 | #endif // WITH_EDITOR 254 | 255 | return true; 256 | } 257 | 258 | void FLBPCGMeshFromSpawnManager::GetDependenciesCrc(const FPCGDataCollection& InInput, const UPCGSettings* InSettings, 259 | UPCGComponent* InComponent, FPCGCrc& OutCrc) const 260 | { 261 | FPCGCrc Crc; 262 | FPCGPointProcessingElementBase::GetDependenciesCrc(InInput, InSettings, InComponent, Crc); 263 | 264 | const auto* Manager = ULBBiomesSpawnManager::GetManager(InComponent); 265 | if (!Manager) 266 | { 267 | OutCrc = Crc; 268 | return; 269 | } 270 | 271 | Crc.Combine(Manager->GetSpawnPresetCrc()); 272 | 273 | OutCrc = Crc; 274 | } 275 | 276 | 277 | #undef LOCTEXT_NAMESPACE 278 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/LBBiomesLog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | PCGLAYEREDBIOMES_API DECLARE_LOG_CATEGORY_EXTERN(LogBiomes, Log, All); 26 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/LBBiomesPCGUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "LBBiomesPCGUtils.h" 26 | 27 | #include "LBBiomesSpawnManager.h" 28 | #include "PCGComponent.h" 29 | #include "PCGSubsystem.h" 30 | #include "Components/InstancedStaticMeshComponent.h" 31 | #include "Runtime/LBBiomesInstanceController.h" 32 | #include "Runtime/LBBiomesInstanceTracker.h" 33 | 34 | template 35 | static bool GetAttribute(const FPCGPoint& Point, const UPCGMetadata* Metadata, FName AttributeName, AttributeType& Value) 36 | { 37 | const FPCGMetadataAttributeBase* AttributeBase = Metadata->GetConstAttribute(AttributeName); 38 | if (!AttributeBase) 39 | { 40 | return false; 41 | } 42 | 43 | if (PCG::Private::IsOfTypes(AttributeBase->GetTypeId())) 44 | { 45 | Value = static_cast*>(AttributeBase)->GetValueFromItemKey(Point.MetadataEntry); 46 | return true; 47 | } 48 | return false; 49 | } 50 | 51 | bool ULBBiomesPCGUtils::ExtractSpawnInfo(const UInstancedStaticMeshComponent* Component, const int32 InstanceId, FLBPCGSpawnInfo& Result) 52 | { 53 | if (const auto* Mgr = GetSpawnManager(Component)) 54 | { 55 | 56 | return Mgr->GetSpawnInfoFromInstance(Component, InstanceId, Result); 57 | } 58 | return false; 59 | } 60 | 61 | bool ULBBiomesPCGUtils::RemoveInstance(UInstancedStaticMeshComponent* Component, const int32 InstanceId, 62 | FLBBiomesInstanceHandle& InstanceHandle, FTransform& InstanceTransform) 63 | { 64 | check(Component); 65 | check(Component->IsValidInstance(InstanceId)); 66 | 67 | ULBBiomesInstanceController* Controller = ULBBiomesInstanceController::GetInstance(Component); 68 | if (!Controller) 69 | { 70 | InstanceHandle = {}; 71 | return false; 72 | } 73 | 74 | if (Component->GetInstanceTransform(InstanceId, InstanceTransform, true)) 75 | { 76 | FLBBiomesInstanceHandle Handle = Controller->RemoveInstance(Component, InstanceId); 77 | InstanceHandle = Handle; 78 | return Handle.IsValid(); 79 | } 80 | 81 | InstanceHandle = {}; 82 | return {}; 83 | } 84 | 85 | bool ULBBiomesPCGUtils::RestoreInstance(const FLBBiomesInstanceHandle& InstanceHandle) 86 | { 87 | const auto* WorldContext = UPCGSubsystem::GetSubsystemForCurrentWorld(); 88 | if (auto* Controller = ULBBiomesInstanceController::GetInstance(WorldContext)) 89 | { 90 | return Controller->RestoreInstance(InstanceHandle); 91 | } 92 | return false; 93 | } 94 | 95 | bool ULBBiomesPCGUtils::GetTransformByHandle(const FLBBiomesInstanceHandle& InstanceHandle, FTransform& InstanceTransform) 96 | { 97 | const auto* WorldContext = UPCGSubsystem::GetSubsystemForCurrentWorld(); 98 | if (auto* Controller = ULBBiomesInstanceController::GetInstance(WorldContext)) 99 | { 100 | return Controller->GetInstanceTransform(InstanceHandle, InstanceTransform); 101 | } 102 | return false; 103 | } 104 | 105 | ULBBiomesInstanceUserData* ULBBiomesPCGUtils::GetUserDataByHandle(const FLBBiomesInstanceHandle& InstanceHandle) 106 | { 107 | const auto* WorldContext = UPCGSubsystem::GetSubsystemForCurrentWorld(); 108 | if (auto* Controller = ULBBiomesInstanceController::GetInstance(WorldContext)) 109 | { 110 | return Controller->GetUserData(InstanceHandle); 111 | } 112 | return nullptr; 113 | } 114 | 115 | FLBBiomesPersistentInstancesData ULBBiomesPCGUtils::GetPersistentData() 116 | { 117 | const auto* WorldContext = UPCGSubsystem::GetSubsystemForCurrentWorld(); 118 | if (auto* Controller = ULBBiomesInstanceController::GetInstance(WorldContext)) 119 | { 120 | return Controller->GetPersistentData(); 121 | } 122 | return {}; 123 | } 124 | 125 | void ULBBiomesPCGUtils::SetPersistentData(const FLBBiomesPersistentInstancesData& Data) 126 | { 127 | const auto* WorldContext = UPCGSubsystem::GetSubsystemForCurrentWorld(); 128 | if (auto* Controller = ULBBiomesInstanceController::GetInstance(WorldContext)) 129 | { 130 | Controller->SetPersistentData(Data); 131 | } 132 | } 133 | 134 | ULBBiomesSpawnManager* ULBBiomesPCGUtils::GetSpawnManager(const UActorComponent* Component) 135 | { 136 | if (!Component) 137 | { 138 | return nullptr; 139 | } 140 | 141 | const auto* Owner = Component->GetOwner(); 142 | check(Owner); 143 | 144 | return GetSpawnManager(Owner); 145 | } 146 | 147 | ULBBiomesSpawnManager* ULBBiomesPCGUtils::GetSpawnManager(const AActor* Actor) 148 | { 149 | auto* PcgComponent = Actor->FindComponentByClass(); 150 | if (!PcgComponent) 151 | { 152 | return nullptr; 153 | } 154 | const auto* Original = PcgComponent->GetOriginalComponent(); 155 | return Original->GetOwner()->GetComponentByClass(); 156 | } 157 | 158 | int32 ULBBiomesPCGUtils::GetInteger32Attribute(const FPCGPoint& Point, const UPCGMetadata* Metadata, FName AttributeName) 159 | { 160 | int32 Value = 0; 161 | GetAttribute(Point, Metadata, AttributeName, Value); 162 | return Value; 163 | } 164 | 165 | FName ULBBiomesPCGUtils::GetNameAttribute(const FPCGPoint& Point, const UPCGMetadata* Metadata, FName AttributeName) 166 | { 167 | FName Value = {}; 168 | GetAttribute(Point, Metadata, AttributeName, Value); 169 | return Value; 170 | } 171 | 172 | ULBBiomesInstanceUserData* ULBBiomesPCGUtils::ExtractUserData(const UInstancedStaticMeshComponent* Component, const int32 InstanceId) 173 | { 174 | if (auto* Mgr = GetSpawnManager(Component)) 175 | { 176 | return Mgr->GetExtraDataFromInstance(Component, InstanceId); 177 | } 178 | return nullptr; 179 | } 180 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/LBBiomesSpawnManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "LBBiomesSpawnManager.h" 26 | 27 | #include "EngineUtils.h" 28 | #include "PCGComponent.h" 29 | #include "PCGSubsystem.h" 30 | #include "Biomes/LBBiomesSettings.h" 31 | #include "Components/InstancedStaticMeshComponent.h" 32 | #include "Grid/PCGPartitionActor.h" 33 | #include "Misc/MapErrors.h" 34 | #include "Misc/UObjectToken.h" 35 | #include "Runtime/LBBiomesInstanceTracker.h" 36 | #include "Logging/MessageLog.h" 37 | #include "Runtime/LBBiomesInstanceController.h" 38 | 39 | #define LOCTEXT_NAMESPACE "Biomes" 40 | 41 | ULBBiomesSpawnManager* ULBBiomesSpawnManager::GetManager(UPCGComponent* InComponent) 42 | { 43 | if (!InComponent) 44 | { 45 | return nullptr; 46 | } 47 | 48 | const AActor* Actor = InComponent->GetOriginalComponent()->GetOwner(); 49 | if (!Actor) 50 | { 51 | return nullptr; 52 | } 53 | 54 | return Actor->GetComponentByClass(); 55 | } 56 | 57 | ULBBiomesSpawnManager* ULBBiomesSpawnManager::GetManager(const AActor* Actor) 58 | { 59 | if (!Actor) 60 | { 61 | return nullptr; 62 | } 63 | 64 | if (auto* Result = Actor->GetComponentByClass()) 65 | { 66 | return Result; 67 | } 68 | 69 | if (auto* PcgComponent = Actor->GetComponentByClass()) 70 | { 71 | return GetManager(PcgComponent); 72 | } 73 | 74 | return nullptr; 75 | } 76 | 77 | void ULBBiomesSpawnManager::BeginPlay() 78 | { 79 | Super::BeginPlay(); 80 | 81 | if (auto* Controller = ULBBiomesInstanceController::GetInstance(this)) 82 | { 83 | Controller->RegisterManager(this); 84 | } 85 | } 86 | 87 | void ULBBiomesSpawnManager::EndPlay(const EEndPlayReason::Type EndPlayReason) 88 | { 89 | if (auto* Controller = ULBBiomesInstanceController::GetInstance(this)) 90 | { 91 | Controller->UnRegisterManager(this); 92 | } 93 | 94 | Super::EndPlay(EndPlayReason); 95 | } 96 | 97 | const TArray* ULBBiomesSpawnManager::FindSet(const FString& SetName) const 98 | { 99 | if (!Preset) 100 | { 101 | return nullptr; 102 | } 103 | 104 | for (const auto& Item: Preset->Sets) 105 | { 106 | if (Item.Name == SetName) 107 | { 108 | return &Item.Actors; 109 | } 110 | } 111 | return nullptr; 112 | } 113 | 114 | const FLBBiomeSettings* ULBBiomesSpawnManager::FindSettings(FName BiomeName) const 115 | { 116 | return Biomes ? Biomes->FindSettings(BiomeName) : nullptr; 117 | } 118 | 119 | FPCGCrc ULBBiomesSpawnManager::GetBiomesCrc() const 120 | { 121 | if (Biomes) 122 | { 123 | return Biomes->ComputeCrc(); 124 | } 125 | return {}; 126 | } 127 | 128 | FSoftObjectPath ULBBiomesSpawnManager::GetBiomesSoftPath() const 129 | { 130 | return FSoftObjectPath(Biomes); 131 | } 132 | 133 | FPCGCrc ULBBiomesSpawnManager::GetSpawnPresetCrc() const 134 | { 135 | if (Preset) 136 | { 137 | return Preset->ComputeCrc(); 138 | } 139 | return {}; 140 | } 141 | 142 | FSoftObjectPath ULBBiomesSpawnManager::GetSpawnPresetSoftPath() const 143 | { 144 | return FSoftObjectPath(Preset); 145 | } 146 | 147 | void ULBBiomesSpawnManager::PreSave(FObjectPreSaveContext SaveContext) 148 | { 149 | Super::PreSave(SaveContext); 150 | 151 | if (!SaveContext.IsProceduralSave()) 152 | { 153 | if (!HasAnyFlags(RF_ArchetypeObject) && !Guid.IsValid()) 154 | { 155 | Guid = FGuid::NewGuid(); 156 | } 157 | else if (HasAnyFlags(RF_ArchetypeObject) && Guid.IsValid()) 158 | { 159 | // Guid should be unique per instance, so ensure it's empty for templates 160 | Guid = {}; 161 | } 162 | } 163 | } 164 | 165 | #if WITH_EDITOR 166 | 167 | void ULBBiomesSpawnManager::PostLoad() 168 | { 169 | Super::PostLoad(); 170 | 171 | if (!HasAnyFlags(RF_ArchetypeObject)) 172 | { 173 | PrepareForRuntimeInteractions(); 174 | } 175 | } 176 | 177 | void ULBBiomesSpawnManager::PrepareForRuntimeInteractions() const 178 | { 179 | if (auto* PCGSubsystem = UPCGSubsystem::GetSubsystemForCurrentWorld()) 180 | { 181 | if (!PCGSubsystem->OnComponentGenerationCompleteOrCancelled.IsBoundToObject(this)) 182 | { 183 | PCGSubsystem->OnComponentGenerationCompleteOrCancelled.AddUObject(this, &ULBBiomesSpawnManager::OnGenerationDone); 184 | } 185 | } 186 | 187 | FixAllPCGActors(); 188 | } 189 | 190 | void ULBBiomesSpawnManager::FixAllPCGActors() const 191 | { 192 | // Track all partitioned actors 193 | for (TActorIterator ActorIt(GetWorld()); ActorIt; ++ActorIt) 194 | { 195 | auto* Actor = *ActorIt; 196 | if (!Actor->FindComponentByClass()) 197 | { 198 | Actor->Modify(); 199 | 200 | FName NewComponentName = "BiomesInstanceTracker"; 201 | 202 | // Construct the new component and attach as needed 203 | UActorComponent* NewInstanceComponent = NewObject(Actor, ULBBiomesInstanceTracker::StaticClass(), NewComponentName, RF_Transactional); 204 | 205 | Actor->AddInstanceComponent(NewInstanceComponent); 206 | NewInstanceComponent->OnComponentCreated(); 207 | NewInstanceComponent->RegisterComponent(); 208 | } 209 | } 210 | } 211 | 212 | void ULBBiomesSpawnManager::OnGenerationDone(UPCGSubsystem* Subsystem) const 213 | { 214 | FixAllPCGActors(); 215 | } 216 | 217 | void ULBBiomesSpawnManager::CheckForErrors() 218 | { 219 | Super::CheckForErrors(); 220 | 221 | if (Preset && Preset->HasUserData()) 222 | { 223 | auto* Owner = GetOwner(); 224 | 225 | for (TActorIterator ActorIt(GetWorld()); ActorIt; ++ActorIt) 226 | { 227 | auto* Actor = *ActorIt; 228 | if (!Actor->FindComponentByClass()) 229 | { 230 | FMessageLog("MapCheck").Warning() 231 | ->AddToken(FUObjectToken::Create(Owner)) 232 | ->AddToken(FTextToken::Create(LOCTEXT( 233 | "MapCheck_Message_ActorsNotReady", 234 | "Not all of PCG actors ready for runtime interaction" ))) 235 | ->AddToken(FActionToken::Create(LOCTEXT("MapCheck_Message_ActorsNotReady_Fix", "Fix actors"), 236 | LOCTEXT("MapCheck_Message_ActorsNotReady_Fix_Desc", "Modify PCG actors to be ready"), 237 | FOnActionTokenExecuted::CreateUObject(this, &ULBBiomesSpawnManager::PrepareForRuntimeInteractions) 238 | )); 239 | 240 | break; 241 | } 242 | } 243 | } 244 | } 245 | 246 | #endif 247 | 248 | const FLBPCGSpawnInfo* ULBBiomesSpawnManager::FindActorInfoByMesh(const TSoftObjectPtr& Mesh, FPackedTagsEntry& OutEntry) const 249 | { 250 | OutEntry.SetIndex = 0; 251 | 252 | for (const auto& [_, Actors]: Preset->Sets) 253 | { 254 | OutEntry.ActorIndex = 0; 255 | for (const auto& Item: Actors) 256 | { 257 | if (Item.Mesh == Mesh) 258 | { 259 | return &Item; 260 | } 261 | OutEntry.ActorIndex++; 262 | } 263 | OutEntry.SetIndex++; 264 | } 265 | return nullptr; 266 | } 267 | 268 | ULBBiomesInstanceUserData* ULBBiomesSpawnManager::GetExtraDataFromInstance(const UInstancedStaticMeshComponent* Component, 269 | const int32 InstanceId) const 270 | { 271 | const auto TagEntry = GetTagEntryFromInstance(Component, InstanceId); 272 | if (TagEntry.ActorIndex != INDEX_NONE && TagEntry.SetIndex != INDEX_NONE) 273 | { 274 | return Preset->Sets[TagEntry.SetIndex].Actors[TagEntry.ActorIndex].UserData; 275 | } 276 | return nullptr; 277 | } 278 | 279 | ULBBiomesInstanceUserData* ULBBiomesSpawnManager::GetExtraData(int32 SetIndex, int32 ActorIndex) const 280 | { 281 | if (ActorIndex != INDEX_NONE && SetIndex != INDEX_NONE) 282 | { 283 | return Preset->Sets[SetIndex].Actors[ActorIndex].UserData; 284 | } 285 | return nullptr; 286 | } 287 | 288 | bool ULBBiomesSpawnManager::GetSpawnInfoFromInstance( 289 | const UInstancedStaticMeshComponent* Component, 290 | const int32 InstanceId, 291 | FLBPCGSpawnInfo& Result) const 292 | { 293 | const auto TagEntry = GetTagEntryFromInstance(Component, InstanceId); 294 | if (TagEntry.ActorIndex != INDEX_NONE && TagEntry.SetIndex != INDEX_NONE) 295 | { 296 | Result = Preset->Sets[TagEntry.SetIndex].Actors[TagEntry.ActorIndex]; 297 | return true; 298 | } 299 | return false; 300 | } 301 | 302 | ULBBiomesSpawnManager::FPackedTagsEntry ULBBiomesSpawnManager::GetTagEntryFromInstance(const UInstancedStaticMeshComponent* Component, const int32 InstanceId) 303 | { 304 | if (Component->PerInstanceSMCustomData.IsEmpty()) 305 | { 306 | return {}; 307 | } 308 | 309 | const auto& Data = Component->PerInstanceSMCustomData; 310 | const auto Offset = Component->NumCustomDataFloats * InstanceId; 311 | if (Data.Num() >= Offset + Component->NumCustomDataFloats) 312 | { 313 | return *(FPackedTagsEntry*)&Data[Offset]; 314 | } 315 | 316 | return {}; 317 | } 318 | 319 | void ULBBiomesSpawnManager::SetTagEntryFromInstance(UInstancedStaticMeshComponent* Component, 320 | const int32 InstanceId, const FPackedTagsEntry& Data) 321 | { 322 | if (Component->PerInstanceSMCustomData.IsEmpty()) 323 | { 324 | return; 325 | } 326 | 327 | auto& CustomData = Component->PerInstanceSMCustomData; 328 | const auto Offset = Component->NumCustomDataFloats * InstanceId; 329 | if (CustomData.Num() >= Offset + Component->NumCustomDataFloats) 330 | { 331 | FMemory::Memcpy(&CustomData[Offset], &Data, sizeof(FPackedTagsEntry)); 332 | } 333 | } 334 | 335 | 336 | #undef LOCTEXT_NAMESPACE 337 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/LBBiomesTagPacker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "LBBiomesTagPacker.h" 26 | 27 | #include "LBBiomesSpawnManager.h" 28 | #include "PCGComponent.h" 29 | #include "Engine/StaticMesh.h" 30 | #include "PCGContext.h" 31 | #include "MeshSelectors/PCGMeshSelectorBase.h" 32 | 33 | void ULBBiomesTagPacker::PackInstances_Implementation(FPCGContext& Context, const UPCGSpatialData* InSpatialData, 34 | const FPCGMeshInstanceList& InstanceList, FPCGPackedCustomData& OutPackedCustomData) const 35 | { 36 | if (const auto* Actor = Context.SourceComponent->GetOriginalComponent()->GetOwner()) 37 | { 38 | if (const auto* Manager = Actor->GetComponentByClass()) 39 | { 40 | ULBBiomesSpawnManager::FPackedTagsEntry TagsEntry; 41 | if (auto* Info = Manager->FindActorInfoByMesh(InstanceList.Descriptor.StaticMesh, TagsEntry)) 42 | { 43 | if (!Info->UserData) 44 | { 45 | return; 46 | } 47 | 48 | TArray TypedData; 49 | TypedData.Init(TagsEntry, InstanceList.Instances.Num()); 50 | 51 | constexpr auto FloatsPerTag = sizeof(ULBBiomesSpawnManager::FPackedTagsEntry) / sizeof(float); 52 | OutPackedCustomData.NumCustomDataFloats = FloatsPerTag; 53 | 54 | const auto NumFloats = TypedData.Num() * FloatsPerTag; 55 | OutPackedCustomData.CustomData.SetNum(NumFloats); 56 | FMemory::Memcpy(&OutPackedCustomData.CustomData[0], &TypedData[0], NumFloats * sizeof(float)); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/LBExplicitBiomeActor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "LBExplicitBiomeActor.h" 26 | 27 | 28 | ALBExplicitBiomeActor::ALBExplicitBiomeActor() 29 | { 30 | PrimaryActorTick.bCanEverTick = false; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/LBPCGLayeredBiomes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "LBPCGLayeredBiomes.h" 24 | #include "LBBiomesLog.h" 25 | 26 | DEFINE_LOG_CATEGORY(LogBiomes); 27 | 28 | #define LOCTEXT_NAMESPACE "FPCGBiomesModule" 29 | 30 | void FLBPCGLayeredBiomesModule::StartupModule() 31 | { 32 | // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module 33 | } 34 | 35 | void FLBPCGLayeredBiomesModule::ShutdownModule() 36 | { 37 | // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 38 | // we call this function before unloading the module. 39 | } 40 | 41 | #undef LOCTEXT_NAMESPACE 42 | 43 | IMPLEMENT_MODULE(FLBPCGLayeredBiomesModule, PCGLayeredBiomes) -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/LBPCGSpawnStructures.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "LBPCGSpawnStructures.h" 26 | 27 | #include "PCGCrc.h" 28 | #include "Serialization/ArchiveCrc32.h" 29 | 30 | FPCGCrc FLBPCGSpawnInfo::ComputeCrc() const 31 | { 32 | FArchiveCrc32 Ar; 33 | Ar << *this; 34 | return FPCGCrc(Ar.GetCrc()); 35 | } 36 | 37 | FPCGCrc ULBPCGSpawnPreset::ComputeCrc() 38 | { 39 | FArchiveCrc32 Ar; 40 | for (auto& Item: Sets) 41 | { 42 | Ar << Item; 43 | } 44 | 45 | return FPCGCrc(Ar.GetCrc()); 46 | } 47 | 48 | bool ULBPCGSpawnPreset::HasUserData() const 49 | { 50 | for (const auto& Item: Sets) 51 | { 52 | for (const auto& Actor: Item.Actors) 53 | { 54 | if (Actor.UserData) 55 | { 56 | return true; 57 | } 58 | } 59 | } 60 | return false; 61 | } 62 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/LBRandomUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "LBRandomUtils.h" 26 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/LBRandomUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "Math/RandomStream.h" 28 | 29 | template 30 | struct TFLBWeightGetter 31 | { 32 | static constexpr int GetWeight(const T& Item) 33 | { 34 | if constexpr (std::is_pointer_v) 35 | { 36 | return Item->Weight; 37 | } 38 | else 39 | { 40 | return Item.Weight; 41 | } 42 | } 43 | }; 44 | 45 | class FLBRandomUtils 46 | { 47 | public: 48 | template 49 | static int SelectRandomIndex(const TArray& Items, const FRandomStream& RandomSource, const int* InTotalWeight = nullptr) 50 | { 51 | if (Items.IsEmpty()) 52 | { 53 | return INDEX_NONE; 54 | } 55 | 56 | int TotalWeight = 0; 57 | if (InTotalWeight) 58 | { 59 | // Use total weight from input 60 | TotalWeight = *InTotalWeight; 61 | } 62 | else 63 | { 64 | // Calculate total weight 65 | for (auto&& Item: Items) 66 | { 67 | TotalWeight += TFLBWeightGetter::GetWeight(Item); 68 | } 69 | } 70 | 71 | if (TotalWeight <= 1) 72 | { 73 | return Items.Num() - 1; 74 | } 75 | 76 | const auto RandomWeight = RandomSource.RandRange(0, TotalWeight - 1); 77 | int CurWeight = 0; 78 | for (int i = 0; i < Items.Num(); ++i) 79 | { 80 | CurWeight += TFLBWeightGetter::GetWeight(Items[i]); 81 | if (CurWeight > RandomWeight) 82 | { 83 | return i; 84 | } 85 | } 86 | 87 | return Items.Num() - 1; 88 | } 89 | 90 | template 91 | static const TItem& SelectRandom(const TArray& Items, const FRandomStream& RandomSource, const int* InTotalWeight = nullptr) 92 | { 93 | const auto Index = SelectRandomIndex(Items, RandomSource, InTotalWeight); 94 | check(Index != INDEX_NONE); 95 | return Items[Index]; 96 | } 97 | 98 | }; 99 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/Runtime/LBBiomesInstanceController.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include "Runtime/LBBiomesInstanceController.h" 26 | 27 | #include "LBBiomesLog.h" 28 | #include "LBBiomesPCGUtils.h" 29 | #include "PCGComponent.h" 30 | #include "PCGSubsystem.h" 31 | #include "Engine/World.h" 32 | #include "Components/InstancedStaticMeshComponent.h" 33 | #include "Grid/PCGPartitionActor.h" 34 | 35 | 36 | bool FLBBiomesInstanceData::operator==(const FLBBiomesInstanceHandle& Handle) const 37 | { 38 | return Id == Handle.InstanceId && ComponentName == Handle.ComponentName; 39 | } 40 | 41 | ULBBiomesInstanceController::ULBBiomesInstanceController() 42 | { 43 | } 44 | 45 | void ULBBiomesInstanceController::EnsureInstancesUnique(const FTransform& Transform, const int32 OriginalIndex, const FName ComponentName, const TArray& Instances) 46 | { 47 | auto* SameItem = Instances.FindByPredicate([OriginalIndex, ComponentName] (const FLBBiomesInstanceData& Item) 48 | { 49 | return Item.Id == OriginalIndex && Item.ComponentName == ComponentName; 50 | }); 51 | ensure(SameItem == nullptr); 52 | } 53 | 54 | UPCGComponent* ULBBiomesInstanceController::FindPcgComponent(const FGuid& Guid) 55 | { 56 | if (const auto* Component = PcgComponents.Find(Guid)) 57 | { 58 | return Component->Get(); 59 | } 60 | 61 | for (const auto& ManagerWeak: Managers) 62 | { 63 | if (const auto* Manager = ManagerWeak.Get(); Manager && Manager->Guid == Guid) 64 | { 65 | auto* Component = Manager->GetOwner()->FindComponentByClass(); 66 | PcgComponents.Add(Guid, Component); 67 | return Component; 68 | } 69 | } 70 | return nullptr; 71 | } 72 | 73 | FLBBiomesInstanceHandle ULBBiomesInstanceController::RemoveInstanceImpl(UInstancedStaticMeshComponent* Component, 74 | int32 InstanceId) 75 | { 76 | auto* Owner = Component->GetOwner(); 77 | check(Owner); 78 | 79 | auto* PcgComponent = Owner->FindComponentByClass(); 80 | if (!PcgComponent) 81 | { 82 | return {}; 83 | } 84 | 85 | // Return a handle for original (not partitioned) component 86 | FTransform Transform; 87 | if (!Component->GetInstanceTransform(InstanceId, Transform)) 88 | { 89 | return {}; 90 | } 91 | const auto OriginalIndex = GetOriginalIndex(Component, InstanceId); 92 | if (OriginalIndex == INDEX_NONE) 93 | { 94 | ensure(false); 95 | return {}; 96 | } 97 | 98 | const auto [SetIndex, ActorIndex] = ULBBiomesSpawnManager::GetTagEntryFromInstance(Component, InstanceId); 99 | const auto ComponentName = Component->GetFName(); 100 | 101 | if (!PcgComponent->IsLocalComponent()) 102 | { 103 | const auto MainIndex = GetMainIndex(PcgComponent); 104 | if (MainIndex == INDEX_NONE || !Mains.IsValidIndex(MainIndex)) 105 | { 106 | return {}; 107 | } 108 | auto& Instances = MainInstances.FindOrAdd(Mains[MainIndex]); 109 | EnsureInstancesUnique(Transform, OriginalIndex, ComponentName, Instances); 110 | 111 | auto& Data = Instances.AddDefaulted_GetRef(); 112 | Data.Id = OriginalIndex; 113 | Data.ComponentName = ComponentName; 114 | Data.Transform = Transform; 115 | 116 | // Store custom data from component 117 | Data.Custom_ActorIndex = ActorIndex; 118 | Data.Custom_SetIndex = SetIndex; 119 | 120 | FLBBiomesInstanceHandle Result; 121 | Result.InstanceId = Data.Id; 122 | Result.GroupId = -(MainIndex + 1); 123 | Result.ComponentName = ComponentName; 124 | return Result; 125 | } 126 | 127 | if (const auto* Actor = Cast(Owner)) 128 | { 129 | const auto ActorGridCoords = Actor->GetGridCoord(); 130 | const auto ActorGridSize = Actor->GetPCGGridSize(); 131 | 132 | // Ensure unique 133 | if (auto* Items = PartitionedInstances.Find({ActorGridCoords, ActorGridSize})) 134 | { 135 | EnsureInstancesUnique(Transform, OriginalIndex, ComponentName, *Items); 136 | } 137 | 138 | auto& Data = PartitionedInstances.FindOrAdd({ActorGridCoords, ActorGridSize}).AddDefaulted_GetRef(); 139 | Data.Id = OriginalIndex; 140 | Data.ComponentName = ComponentName; 141 | Data.Transform = Transform; 142 | 143 | // Store custom data from component 144 | Data.Custom_ActorIndex = ActorIndex; 145 | Data.Custom_SetIndex = SetIndex; 146 | 147 | FLBBiomesInstanceHandle Result; 148 | Result.InstanceId = Data.Id; 149 | Result.GroupId = GetPartitionIndex(ActorGridCoords, ActorGridSize) + 1; 150 | Result.ComponentName = ComponentName; 151 | return Result; 152 | } 153 | return {}; 154 | } 155 | 156 | void ULBBiomesInstanceController::OnInstanceIndexRelocated(UInstancedStaticMeshComponent* Component, 157 | TArrayView Data) 158 | { 159 | if (auto* Indices = TrackedComponents.Find(Component)) 160 | { 161 | checkSlow(Indices.Num() >= Component->GetNumInstances()); 162 | 163 | for (const auto& Item: Data) 164 | { 165 | if (Item.Type == FInstancedStaticMeshDelegates::EInstanceIndexUpdateType::Relocated) 166 | { 167 | Indices->Swap(Item.OldIndex, Item.Index); 168 | } 169 | } 170 | } 171 | } 172 | 173 | void ULBBiomesInstanceController::OnInstanceIndexUpdated(UInstancedStaticMeshComponent* Component, 174 | TArrayView Data) 175 | { 176 | for (const auto& Item: Data) 177 | { 178 | if (Item.Type == FInstancedStaticMeshDelegates::EInstanceIndexUpdateType::Relocated) 179 | { 180 | if (auto* System = GetInstance(Component)) 181 | { 182 | System->OnInstanceIndexRelocated(Component, Data); 183 | } 184 | return; 185 | } 186 | } 187 | } 188 | 189 | int16 ULBBiomesInstanceController::GetMainIndex(const UPCGComponent* Component) 190 | { 191 | ensure(!Component->IsLocalComponent() && !Component->IsPartitioned()); 192 | 193 | if (const auto* Manager = Component->GetOwner()->FindComponentByClass()) 194 | { 195 | const auto TargetGuid = Manager->Guid; 196 | ensure(TargetGuid.IsValid()); 197 | for (int16 i = 0; i < Mains.Num(); ++i) 198 | { 199 | if (Mains[i] == TargetGuid) 200 | { 201 | return i; 202 | } 203 | } 204 | 205 | return Mains.Add(TargetGuid); 206 | } 207 | ensureMsgf(false, TEXT("PCG component should have ULBBiomesSpawnManager")); 208 | return INDEX_NONE; 209 | } 210 | 211 | int16 ULBBiomesInstanceController::GetPartitionIndex(const FIntVector& ActorGridCoords, uint32 ActorGridSize) 212 | { 213 | for (int16 i = 0; i < Partitions.Num(); ++i) 214 | { 215 | const auto& Partition = Partitions[i]; 216 | if (Partition.GridSize == ActorGridSize && Partition.GridCoord == ActorGridCoords) 217 | { 218 | return i; 219 | } 220 | } 221 | 222 | return Partitions.Add(FLBBiomesPartition{ActorGridCoords, ActorGridSize}); 223 | } 224 | 225 | void ULBBiomesInstanceController::InitTrackedComponent(const UInstancedStaticMeshComponent* Component, TArray& Mapping) 226 | { 227 | Mapping.SetNumUninitialized(Component->GetNumInstances()); 228 | // Fill the array with initial indices 229 | for (int i = 0; i < Mapping.Num(); ++i) 230 | { 231 | Mapping[i] = i; 232 | } 233 | } 234 | 235 | int32 ULBBiomesInstanceController::GetOriginalIndex(UInstancedStaticMeshComponent* Component, int32 InstanceId) 236 | { 237 | auto& Mapping = TrackedComponents.FindOrAdd(Component); 238 | if (Mapping.IsEmpty()) 239 | { 240 | InitTrackedComponent(Component, Mapping); 241 | 242 | return InstanceId; 243 | } 244 | checkSlow(Mapping.Num() >= Component->GetNumInstances()); 245 | return Mapping[InstanceId]; 246 | } 247 | 248 | void ULBBiomesInstanceController::SetOriginalIndex(const UInstancedStaticMeshComponent* Component, int32 OriginalId, 249 | int32 InstanceId) 250 | { 251 | auto& Mapping = TrackedComponents.FindOrAdd(Component); 252 | if (Mapping.IsEmpty()) 253 | { 254 | InitTrackedComponent(Component, Mapping); 255 | } 256 | checkSlow(Mapping.Num() >= Component->GetNumInstances()); 257 | Mapping[InstanceId] = OriginalId; 258 | } 259 | 260 | void ULBBiomesInstanceController::Track(UInstancedStaticMeshComponent* Component) 261 | { 262 | auto& Mapping = TrackedComponents.FindOrAdd(Component); 263 | if (Mapping.IsEmpty()) 264 | { 265 | InitTrackedComponent(Component, Mapping); 266 | } 267 | } 268 | 269 | ULBBiomesInstanceController* ULBBiomesInstanceController::GetInstance(const UObject* WorldContext) 270 | { 271 | return WorldContext->GetWorld()->GetSubsystem(); 272 | } 273 | 274 | FLBBiomesInstanceHandle ULBBiomesInstanceController::RemoveInstance(UInstancedStaticMeshComponent* Component, 275 | int32 InstanceId) 276 | { 277 | if (!Component->IsValidInstance(InstanceId)) 278 | { 279 | return {}; 280 | } 281 | 282 | if (const auto Handle = RemoveInstanceImpl(Component, InstanceId)) 283 | { 284 | ensure(Component->RemoveInstance(InstanceId)); 285 | return Handle; 286 | } 287 | return {}; 288 | } 289 | 290 | bool ULBBiomesInstanceController::RestoreInstanceImpl(const FName& ComponentName, const FLBBiomesInstanceData& Data, AActor* Actor) 291 | { 292 | if (UInstancedStaticMeshComponent* Component = FindISM(Actor, ComponentName)) 293 | { 294 | const auto InstanceId = Component->AddInstance(Data.Transform); 295 | 296 | SetOriginalIndex(Component, Data.Id, InstanceId); 297 | 298 | ULBBiomesSpawnManager::SetTagEntryFromInstance(Component, InstanceId,{ 299 | .SetIndex = Data.Custom_SetIndex, 300 | .ActorIndex = Data.Custom_ActorIndex 301 | }); 302 | 303 | return true; 304 | } 305 | return false; 306 | } 307 | 308 | bool ULBBiomesInstanceController::RestoreInstance(const FLBBiomesInstanceHandle& InstanceHandle) 309 | { 310 | FResult Result = {}; 311 | if (FindDataByHandle(InstanceHandle, Result)) 312 | { 313 | if (Result.Actor) 314 | { 315 | const auto& Data = Result.GetData(); 316 | 317 | RestoreInstanceImpl(InstanceHandle.ComponentName, Data, Result.Actor); 318 | } 319 | 320 | Result.Instances->RemoveAtSwap(Result.Index, EAllowShrinking::No); 321 | return true; 322 | } 323 | return false; 324 | } 325 | 326 | bool ULBBiomesInstanceController::FindDataByHandle(const FLBBiomesInstanceHandle& Handle, FResult& Result) 327 | { 328 | if (!Handle) 329 | { 330 | return false; 331 | } 332 | 333 | const auto* PCG = UPCGSubsystem::GetSubsystemForCurrentWorld(); 334 | if (!PCG) 335 | { 336 | return false; 337 | } 338 | 339 | if (Handle.GroupId < 0) 340 | { 341 | const auto MainIndex = -(Handle.GroupId + 1); 342 | if (!Mains.IsValidIndex(MainIndex)) 343 | { 344 | return false; 345 | } 346 | auto& Instances = MainInstances.FindOrAdd(Mains[MainIndex]); 347 | const auto Index = Instances.IndexOfByKey(Handle); 348 | if (Index == INDEX_NONE) 349 | { 350 | return false; 351 | } 352 | 353 | if (UPCGComponent* Component = FindPcgComponent(Mains[MainIndex])) 354 | { 355 | Result.Actor = Component->GetOwner(); 356 | } 357 | Result.Index = Index; 358 | Result.Instances = &Instances; 359 | return true; 360 | } 361 | 362 | const auto PartitionIndex = Handle.GroupId - 1; 363 | if (!Partitions.IsValidIndex(PartitionIndex)) 364 | { 365 | return false; 366 | } 367 | const auto& Partition = Partitions[PartitionIndex]; 368 | 369 | if (auto* Instances = PartitionedInstances.Find(Partition)) 370 | { 371 | const auto Index = Instances->IndexOfByKey(Handle); 372 | if (Index == INDEX_NONE) 373 | { 374 | return false; 375 | } 376 | 377 | Result.Actor = PCG->GetRegisteredPCGPartitionActor(Partition.GridSize, Partition.GridCoord, false); 378 | Result.Index = Index; 379 | Result.Instances = Instances; 380 | return true; 381 | } 382 | return false; 383 | } 384 | 385 | bool ULBBiomesInstanceController::GetInstanceTransform(const FLBBiomesInstanceHandle& InstanceHandle, FTransform& InstanceTransform) 386 | { 387 | FResult Result = {}; 388 | if (FindDataByHandle(InstanceHandle, Result)) 389 | { 390 | InstanceTransform = Result.GetData().Transform; 391 | return true; 392 | } 393 | return false; 394 | } 395 | 396 | ULBBiomesInstanceUserData* ULBBiomesInstanceController::GetUserData(const FLBBiomesInstanceHandle& InstanceHandle) 397 | { 398 | FResult Result = {}; 399 | if (FindDataByHandle(InstanceHandle, Result)) 400 | { 401 | if (auto* Manager = ULBBiomesSpawnManager::GetManager(Result.Actor)) 402 | { 403 | const auto& Data = Result.GetData(); 404 | return Manager->GetExtraData(Data.Custom_SetIndex, Data.Custom_ActorIndex); 405 | } 406 | } 407 | return nullptr; 408 | } 409 | 410 | FLBBiomesPersistentInstancesData ULBBiomesInstanceController::GetPersistentData() const 411 | { 412 | TArray MainData; 413 | MainData.Reserve(MainInstances.Num()); 414 | for (const auto& [Guid, Instances]: MainInstances) 415 | { 416 | MainData.Add({.Guid = Guid, .Instances = Instances}); 417 | } 418 | 419 | TArray PartitionedData; 420 | PartitionedData.Reserve(PartitionedInstances.Num()); 421 | for (const auto& [Partition, Instances]: PartitionedInstances) 422 | { 423 | PartitionedData.Add({.Partition = Partition, .Instances = Instances}); 424 | } 425 | 426 | return { 427 | .Mains = Mains, 428 | .Partitions = Partitions, 429 | .MainInstances = MoveTemp(MainData), 430 | .PartitionedInstances = MoveTemp(PartitionedData) 431 | }; 432 | } 433 | 434 | void ULBBiomesInstanceController::SetPersistentData(const FLBBiomesPersistentInstancesData& Data) 435 | { 436 | const auto* PCG = UPCGSubsystem::GetSubsystemForCurrentWorld(); 437 | 438 | // Now I am using inefficient approach - restore the state of all partition actors and then remove all from new data. 439 | // So if these lists are equals, we waste a lot of resources doing nothing 440 | if (PCG) 441 | { 442 | if (!MainInstances.IsEmpty()) 443 | { 444 | for (const auto& [Guid, Instances]: MainInstances) 445 | { 446 | if (const auto* Component = FindPcgComponent(Guid)) 447 | { 448 | for (const auto& InstanceData: Instances) 449 | { 450 | RestoreInstanceImpl(InstanceData.ComponentName, InstanceData, Component->GetOwner()); 451 | } 452 | } 453 | } 454 | } 455 | 456 | if (!PartitionedInstances.IsEmpty()) 457 | { 458 | for (const auto& [Partition, Instances]: PartitionedInstances) 459 | { 460 | if (auto* Actor = PCG->GetRegisteredPCGPartitionActor(Partition.GridSize, Partition.GridCoord, false)) 461 | { 462 | for (const auto& InstanceData: Instances) 463 | { 464 | RestoreInstanceImpl(InstanceData.ComponentName, InstanceData, Actor); 465 | } 466 | } 467 | } 468 | } 469 | } 470 | 471 | // Copy new data 472 | Mains = Data.Mains; 473 | Partitions = Data.Partitions; 474 | 475 | MainInstances.Empty(Data.MainInstances.Num()); 476 | for (const auto& [Guid, Instances] : Data.MainInstances) 477 | { 478 | MainInstances.Add(Guid, Instances); 479 | } 480 | 481 | PartitionedInstances.Empty(Data.PartitionedInstances.Num()); 482 | for (const auto& [Partition, Instances] : Data.PartitionedInstances) 483 | { 484 | PartitionedInstances.Add(Partition, Instances); 485 | } 486 | 487 | // Remove all new instances 488 | if (PCG) 489 | { 490 | for (const auto& [Guid, Instances] : Data.MainInstances) 491 | { 492 | if (const auto* Component = FindPcgComponent(Guid)) 493 | { 494 | ApplyStateToActor(Component->GetOwner(), Instances, true); 495 | } 496 | } 497 | 498 | for (const auto& [Partition, Instances] : Data.PartitionedInstances) 499 | { 500 | if (auto* Actor = PCG->GetRegisteredPCGPartitionActor(Partition.GridSize, Partition.GridCoord, false)) 501 | { 502 | ApplyStateToActor(Actor, Instances, true); 503 | } 504 | } 505 | } 506 | } 507 | 508 | struct FInstancesCache 509 | { 510 | // Mesh can be destroyed, but Groups used only as a local storage and always cleared before access 511 | TMap> Groups; 512 | ULBBiomesInstanceController::FTrackedComponents GlobalToLocal; 513 | 514 | void Setup(const TArray& Instances) 515 | { 516 | // This is not true - the number of meshes will be less then Num() 517 | Groups.Empty(); 518 | 519 | for (const auto& Item : Instances) 520 | { 521 | Groups.FindOrAdd(Item.ComponentName).Add(Item.Id); 522 | } 523 | } 524 | 525 | void BuildGlobalToLocal(ULBBiomesInstanceController::FTrackedComponents& TrackedComponents) 526 | { 527 | GlobalToLocal.Empty(TrackedComponents.Num()); 528 | 529 | for (auto It = TrackedComponents.CreateIterator(); It; ++It) 530 | { 531 | // Clear dead items from TrackedComponents 532 | if (!It->Key.IsValid()) 533 | { 534 | It.RemoveCurrent(); 535 | continue; 536 | } 537 | 538 | auto& [Component, ToGlobal] = *It; 539 | 540 | // Create reverse mapping - from global to local 541 | auto& Mapping = GlobalToLocal.FindOrAdd(Component); 542 | const auto Count = ToGlobal.Num(); 543 | // Limit to current count of elements because ToGlobal might have more elements 544 | Mapping.SetNumUninitialized(Count, false); 545 | for (int i = 0; i < Count; ++i) 546 | { 547 | const auto GlobalId = ToGlobal[i]; 548 | Mapping[GlobalId] = i; 549 | } 550 | } 551 | } 552 | 553 | void ToLocal(UInstancedStaticMeshComponent* Component, TArray& Indices) 554 | { 555 | if (auto* Mapping = GlobalToLocal.Find(Component)) 556 | { 557 | for (auto& GlobalIndex: Indices) 558 | { 559 | GlobalIndex = (*Mapping)[GlobalIndex]; 560 | } 561 | } 562 | } 563 | }; 564 | 565 | bool ULBBiomesInstanceController::ApplyStateToActor(AActor* Actor, 566 | const FBiomesInstances& Instances, bool ConvertToLocal) 567 | { 568 | auto& ISMs = CachePartition(Actor); 569 | 570 | static FInstancesCache Cache; 571 | Cache.Setup(Instances); 572 | if (ConvertToLocal) 573 | { 574 | Cache.BuildGlobalToLocal(TrackedComponents); 575 | } 576 | 577 | bool Success = true; 578 | 579 | for (auto& [ComponentName, Indices]: Cache.Groups) 580 | { 581 | if (auto* Component = FindISM(ComponentName, &ISMs)) 582 | { 583 | if (ConvertToLocal) 584 | { 585 | Cache.ToLocal(Component, Indices); 586 | } 587 | Indices.Sort(TGreater()); 588 | 589 | Track(Component); 590 | 591 | Success &= Component->RemoveInstances(Indices, true); 592 | } 593 | } 594 | return Success; 595 | } 596 | 597 | void ULBBiomesInstanceController::OnPartitionLoaded(APCGPartitionActor* PartitionActor) 598 | { 599 | int NumInstances = 0; 600 | bool Success = true; 601 | if (const auto* Instances = GetInstancesFor(PartitionActor)) 602 | { 603 | NumInstances += Instances->Num(); 604 | Success = ApplyStateToActor(PartitionActor, *Instances, false); 605 | } 606 | 607 | if (!Success) 608 | { 609 | const auto Coords = PartitionActor->GetGridCoord(); 610 | UE_LOG(LogBiomes, Warning, TEXT("Failed to restore state of partition: %d, %d, %d. Tried to remove %d instances"), 611 | Coords.X, Coords.Y, Coords.Z, NumInstances); 612 | } 613 | } 614 | 615 | void ULBBiomesInstanceController::OnPartitionUnloaded(APCGPartitionActor* PartitionActor) 616 | { 617 | if (auto* Actor = Cast(PartitionActor)) 618 | { 619 | ISMMapping.Remove(Actor); 620 | } 621 | } 622 | 623 | void ULBBiomesInstanceController::Initialize(FSubsystemCollectionBase& Collection) 624 | { 625 | Super::Initialize(Collection); 626 | 627 | if (auto* World = GetWorld(); World && World->IsGameWorld()) 628 | { 629 | DelegateHandle = FInstancedStaticMeshDelegates::OnInstanceIndexUpdated.AddStatic(&ULBBiomesInstanceController::OnInstanceIndexUpdated); 630 | } 631 | } 632 | 633 | void ULBBiomesInstanceController::Deinitialize() 634 | { 635 | Super::Deinitialize(); 636 | 637 | if (auto* World = GetWorld(); World && World->IsGameWorld()) 638 | { 639 | FInstancedStaticMeshDelegates::OnInstanceIndexUpdated.Remove(DelegateHandle); 640 | } 641 | } 642 | 643 | void ULBBiomesInstanceController::RegisterManager(ULBBiomesSpawnManager* Manager) 644 | { 645 | Managers.AddUnique(Manager); 646 | } 647 | 648 | void ULBBiomesInstanceController::UnRegisterManager(ULBBiomesSpawnManager* Manager) 649 | { 650 | Managers.Remove(Manager); 651 | } 652 | 653 | UInstancedStaticMeshComponent* ULBBiomesInstanceController::FindISM(const FName& ComponentName, const TArray>* ISMs) 654 | { 655 | const auto* Item = ISMs->FindByPredicate([&ComponentName] (const UInstancedStaticMeshComponent* Component) 656 | { 657 | return ComponentName == Component->GetFName(); 658 | }); 659 | 660 | return Item ? *Item : nullptr; 661 | } 662 | 663 | ULBBiomesInstanceController::FBiomesInstances* ULBBiomesInstanceController::GetInstancesFor(const APCGPartitionActor* PartitionActor) 664 | { 665 | const auto Size = PartitionActor->GetPCGGridSize(); 666 | const auto Coords = PartitionActor->GetGridCoord(); 667 | 668 | const auto Partition = FLBBiomesPartition{ Coords, Size}; 669 | return PartitionedInstances.Find(Partition); 670 | } 671 | 672 | UInstancedStaticMeshComponent* ULBBiomesInstanceController::FindISM(AActor* Actor, const FName& ComponentName) 673 | { 674 | // Find Actor in cache 675 | if (auto* ISMs = ISMMapping.Find(Actor)) 676 | { 677 | return FindISM(ComponentName, &ISMs->Components); 678 | } 679 | 680 | // Get a list of all ISM from actor 681 | const auto& ISMs = CachePartition(Actor); 682 | auto* Result = FindISM(ComponentName, &ISMs); 683 | return Result; 684 | } 685 | 686 | const TArray>& ULBBiomesInstanceController::CachePartition( 687 | AActor* Actor) 688 | { 689 | // Get a list of all ISM from actor 690 | TArray> ISMs; 691 | Actor->GetComponents(ISMs); 692 | 693 | // Save it to cache 694 | return ISMMapping.Emplace(Actor, FLBBiomesISMList {MoveTemp(ISMs)}).Components; 695 | } 696 | 697 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Private/Runtime/LBBiomesInstanceTracker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include "Runtime/LBBiomesInstanceTracker.h" 24 | #include "Runtime/LBBiomesInstanceController.h" 25 | 26 | 27 | ULBBiomesInstanceTracker::ULBBiomesInstanceTracker() 28 | { 29 | PrimaryComponentTick.bCanEverTick = false; 30 | } 31 | 32 | void ULBBiomesInstanceTracker::SetHandle(const FLBBiomesInstanceHandle& Value) 33 | { 34 | Handle = Value; 35 | } 36 | 37 | void ULBBiomesInstanceTracker::BeginPlay() 38 | { 39 | Super::BeginPlay(); 40 | 41 | if (auto* Controller = ULBBiomesInstanceController::GetInstance(this)) 42 | { 43 | if (auto* PartitionActor = GetOwner()) 44 | { 45 | Controller->OnPartitionLoaded(PartitionActor); 46 | } 47 | } 48 | } 49 | 50 | void ULBBiomesInstanceTracker::EndPlay(const EEndPlayReason::Type EndPlayReason) 51 | { 52 | if (auto* Controller = ULBBiomesInstanceController::GetInstance(this)) 53 | { 54 | if (auto* PartitionActor = GetOwner()) 55 | { 56 | Controller->OnPartitionUnloaded(PartitionActor); 57 | } 58 | } 59 | 60 | Super::EndPlay(EndPlayReason); 61 | } 62 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/Biomes/LBBiomesSettings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "PCGCrc.h" 28 | #include "UObject/Object.h" 29 | #include "Engine/DataAsset.h" 30 | #include "LBBiomesSettings.generated.h" 31 | 32 | class ULBPCGBiomesBaseFilter; 33 | class UPCGMetadata; 34 | struct FPCGPoint; 35 | struct FBiomeFilter; 36 | class UPCGGraph; 37 | class ULBBaseBiomeLayer; 38 | 39 | /** 40 | * 41 | */ 42 | USTRUCT(BlueprintType) 43 | struct PCGLAYEREDBIOMES_API FLBBiomeSettings 44 | { 45 | GENERATED_BODY() 46 | 47 | /** 48 | * Disabled biomes doesn't generate any content 49 | */ 50 | UPROPERTY(EditDefaultsOnly, AdvancedDisplay, Category=Biomes) 51 | bool Enabled = true; 52 | 53 | UPROPERTY(EditDefaultsOnly, AdvancedDisplay, Category=Biomes, meta=(InlineEditConditionToggle)) 54 | bool Debug = false; 55 | /** 56 | * Draw mask of the biome with specified color 57 | */ 58 | UPROPERTY(EditDefaultsOnly, AdvancedDisplay, Category=Biomes, AdvancedDisplay, meta=(EditCondition=Debug)) 59 | FLinearColor DebugColor = FLinearColor::Transparent; 60 | 61 | /** 62 | * Sets priority of the biome. If landscape point can passed filters for several biomes, 63 | * biome with lower priority take precedence. 64 | */ 65 | UPROPERTY(EditDefaultsOnly, Category=Biomes) 66 | int32 Priority = 5000; 67 | 68 | /** 69 | * All filters should pass (return `true`) for a point to include the point to the biome. 70 | */ 71 | UPROPERTY(EditDefaultsOnly, Instanced, Category=Biomes) 72 | TArray> Filters; 73 | 74 | /** 75 | * Content generation layers. 76 | * Executed in specified order. 77 | */ 78 | UPROPERTY(EditDefaultsOnly, Instanced, Category=Biomes, meta=(TitleProperty = "SpawnSet")) 79 | TArray> Layers; 80 | }; 81 | 82 | USTRUCT() 83 | struct PCGLAYEREDBIOMES_API FLBBiomeSettings_Named : public FLBBiomeSettings 84 | { 85 | GENERATED_BODY() 86 | 87 | FLBBiomeSettings_Named() = default; 88 | FLBBiomeSettings_Named(FName InName, FLBBiomeSettings InSettings); 89 | 90 | UPROPERTY(EditDefaultsOnly, Category=Biomes) 91 | FName Name; 92 | }; 93 | 94 | UCLASS(BlueprintType, Transient, ClassGroup=(Biomes)) 95 | class PCGLAYEREDBIOMES_API ULBBiomesData : public UObject 96 | { 97 | GENERATED_BODY() 98 | 99 | friend class ULBBiomesSettings; 100 | 101 | public: 102 | UFUNCTION(BlueprintCallable, Category=Biomes) 103 | bool DetectBiome(const FPCGPoint& Point, const UPCGMetadata* Metadata, FName& OutBiome, int& OutPriority) const; 104 | 105 | protected: 106 | UPROPERTY(Transient) 107 | TArray Biomes; 108 | }; 109 | 110 | /** 111 | * 112 | */ 113 | UCLASS(BlueprintType, ClassGroup=(Biomes)) 114 | class PCGLAYEREDBIOMES_API ULBBiomesSettings : public UPrimaryDataAsset 115 | { 116 | GENERATED_BODY() 117 | 118 | public: 119 | FPCGCrc ComputeCrc(); 120 | 121 | UFUNCTION(BlueprintCallable, Category=Biomes) 122 | ULBBiomesData* Prepare() const; 123 | 124 | const FLBBiomeSettings* FindSettings(FName Name) const; 125 | 126 | #if WITH_EDITOR 127 | virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; 128 | #endif 129 | 130 | UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Biomes) 131 | TMap Biomes; 132 | }; 133 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/Biomes/LBPCGBiomesBaseFilter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "UObject/Object.h" 28 | #include "LBPCGBiomesBaseFilter.generated.h" 29 | 30 | /** 31 | * 32 | */ 33 | UCLASS(Abstract, Const, DefaultToInstanced, EditInlineNew, Blueprintable, CollapseCategories) 34 | class PCGLAYEREDBIOMES_API ULBPCGBiomesBaseFilter : public UObject 35 | { 36 | GENERATED_BODY() 37 | 38 | public: 39 | 40 | /** 41 | * Should return true for a point if this point belongs to the biome. 42 | * @param Point Point data from PCG. Contains default points data and all the data from landscape. 43 | * @param Metadata Reference to metadata where all values of attributes are stored. 44 | * @return True if a point belongs to the biome and false otherwise. 45 | */ 46 | UFUNCTION(BlueprintImplementableEvent, Category=Biomes) 47 | bool Filter(const FPCGPoint& Point, const UPCGMetadata* Metadata) const; 48 | }; 49 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/Biomes/Layers/LBBaseBiomeLayer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "Elements/PCGBoundsModifier.h" 28 | #include "UObject/Object.h" 29 | #include "LBBaseBiomeLayer.generated.h" 30 | 31 | class UPCGGraph; 32 | class UPCGGraphInterface; 33 | 34 | UENUM() 35 | enum class ELBBiomeLayerExclusion : uint8 36 | { 37 | /** 38 | * Output bounds will be calculated from mesh bounds 39 | */ 40 | MeshBounds, 41 | 42 | /** 43 | * Extents of points (1x1m) will be used as a bounds 44 | */ 45 | Points, 46 | 47 | /** 48 | * Ignore bounds of the layer and allow to overlap other layers with it 49 | */ 50 | DontExclude, 51 | }; 52 | 53 | UENUM() 54 | enum class ELBBiomeLayerDebugMode 55 | { 56 | /** 57 | * Show transformed points 58 | * (before overlapping with avoid regions) 59 | */ 60 | Points, 61 | 62 | /** 63 | * Show transformed points with mesh bounds applied 64 | * (before overlapping with avoid regions) 65 | */ 66 | MeshBounds, 67 | 68 | /** 69 | * Show input avoid regions 70 | */ 71 | AvoidRegions, 72 | 73 | /** 74 | * Show exclusion regions which will be used to check with avoid regions 75 | */ 76 | InExclusion, 77 | 78 | /** 79 | * Show outgoing exclusion regions of spawned objects 80 | */ 81 | OutExclusion, 82 | 83 | /** 84 | * Can be used in graph to show other debugging information 85 | */ 86 | Custom1, 87 | /** 88 | * Can be used in graph to show other debugging information 89 | */ 90 | Custom2, 91 | }; 92 | 93 | /** 94 | * 95 | */ 96 | UCLASS(Abstract, Const, DefaultToInstanced, EditInlineNew, Blueprintable, AutoExpandCategories=(Default), PrioritizeCategories=(Default)) 97 | class PCGLAYEREDBIOMES_API ULBBaseBiomeLayer : public UObject 98 | { 99 | GENERATED_BODY() 100 | 101 | public: 102 | /** 103 | * Disabled layers doesn't generate content 104 | */ 105 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Default", meta=(DisplayPriority=-3)) 106 | bool Enabled = true; 107 | 108 | /** 109 | * Could be used in Layer PCG Graph to draw some debug information 110 | */ 111 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Default", meta=(InlineEditConditionToggle)) 112 | bool DebugEnabled = false; 113 | 114 | /** 115 | * Could be used in Layer PCG Graph to draw some debug information 116 | */ 117 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Default", meta=(DisplayPriority=-2, EditCondition=DebugEnabled)) 118 | ELBBiomeLayerDebugMode Debug = ELBBiomeLayerDebugMode::Points; 119 | 120 | /** 121 | * Main PCG Graph of the layer. Must be specified to generate anything. 122 | */ 123 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Default", AdvancedDisplay) 124 | TObjectPtr Graph; 125 | 126 | /** 127 | * Name of the spawn set in SpawnPreset. 128 | */ 129 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Default", meta=(DisplayPriority=-1)) 130 | FName SpawnSet; 131 | }; 132 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/Biomes/Layers/LBEdgeBiomeLayer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "LBGenericBiomeLayer.h" 28 | #include "LBEdgeBiomeLayer.generated.h" 29 | 30 | UENUM() 31 | enum class ELBEdgeLayerMode : uint8 32 | { 33 | Inner, 34 | Outer, 35 | }; 36 | 37 | /** 38 | * 39 | */ 40 | UCLASS(AutoExpandCategories=(Edge)) 41 | class PCGLAYEREDBIOMES_API ULBEdgeBiomeLayer : public ULBGenericBiomeLayer 42 | { 43 | GENERATED_BODY() 44 | 45 | public: 46 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Edge") 47 | ELBEdgeLayerMode Mode = ELBEdgeLayerMode::Inner; 48 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Edge") 49 | float EdgeDistance = 200; 50 | }; 51 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/Biomes/Layers/LBGenericBiomeLayer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "LBBaseBiomeLayer.h" 28 | #include "LBGenericBiomeLayer.generated.h" 29 | 30 | 31 | /** 32 | * 33 | */ 34 | UCLASS() 35 | class PCGLAYEREDBIOMES_API ULBGenericBiomeLayer : public ULBBaseBiomeLayer 36 | { 37 | GENERATED_BODY() 38 | 39 | public: 40 | ULBGenericBiomeLayer(); 41 | 42 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Exclusion") 43 | ELBBiomeLayerExclusion InExclusion = ELBBiomeLayerExclusion::Points; 44 | 45 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Exclusion", meta=(EditCondition="InExclusion==ELBBiomeLayerExclusion::MeshBounds")) 46 | EPCGBoundsModifierMode InExclusionBoundsMode = EPCGBoundsModifierMode::Scale; 47 | 48 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Exclusion", meta=(EditCondition="InExclusion==ELBBiomeLayerExclusion::MeshBounds")) 49 | FVector InExclusionBoundsValue = FVector::OneVector; 50 | 51 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Exclusion") 52 | ELBBiomeLayerExclusion OutExclusion = ELBBiomeLayerExclusion::MeshBounds; 53 | 54 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Exclusion", meta=(EditCondition="OutExclusion==ELBBiomeLayerExclusion::MeshBounds")) 55 | EPCGBoundsModifierMode OutExclusionBoundsMode = EPCGBoundsModifierMode::Scale; 56 | 57 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Exclusion", meta=(EditCondition="OutExclusion==ELBBiomeLayerExclusion::MeshBounds")) 58 | FVector OutExclusionBoundsValue = FVector::OneVector * 0.5f; 59 | 60 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn") 61 | double Density = 0.5; 62 | 63 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn") 64 | int Seed = 0; 65 | 66 | /** 67 | * Enable filtering of points based on random noise. 68 | * To visualize noise use Custom1 debug mode for the layer 69 | */ 70 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn") 71 | bool UseNoise = true; 72 | 73 | /** 74 | * Scale of noise. 75 | * Lower values - lower frequency 76 | */ 77 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn", meta=(EditCondition="UseNoise", EditConditionHides="UseNoise")) 78 | double NoiseScale = 8; 79 | 80 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn", meta=(EditCondition="UseNoise", EditConditionHides="UseNoise")) 81 | double NoiseFilterLow = 0.0f; 82 | 83 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn", meta=(EditCondition="UseNoise", EditConditionHides="UseNoise")) 84 | double NoiseFilterHigh = 0.5f; 85 | 86 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn", meta=(EditCondition="UseNoise", EditConditionHides="UseNoise")) 87 | double NoiseSeed = 10000.0f; 88 | 89 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn", meta=(InlineEditConditionToggle)) 90 | bool NoSlopesEnabled = false; 91 | 92 | /** 93 | * Disable spawning on slopes with a slope greater than specified value 94 | */ 95 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn", meta=(EditCondition="NoSlopesEnabled")) 96 | float NoSlopesValue = 0.25f; 97 | 98 | /** 99 | * Force points to be strictly vertical 100 | * Otherwise points match landscape normal 101 | */ 102 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn") 103 | bool AbsoluteRotation = false; 104 | 105 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn") 106 | double OffsetZ = 0; 107 | 108 | /** 109 | * Horizontal distance to randomly shift points 110 | * Value 100 means randomize position in 1m radius around initial position 111 | */ 112 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn") 113 | float TransformRange = 0; 114 | 115 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn") 116 | float ScaleMin = 0.8f; 117 | 118 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="Spawn") 119 | float ScaleMax = 1.2f; 120 | 121 | /** 122 | * PCG Graph to spawn meshes. Can be omitted. 123 | * Typically, it should contain only a StaticMeshSpawner graph node with specific mesh template. 124 | */ 125 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Spawn", AdvancedDisplay) 126 | TObjectPtr SpawnerGraph; 127 | 128 | protected: 129 | FRandomStream Stream; 130 | }; 131 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/Graph/LBPCGBiomesNoise.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "PCGSettings.h" 28 | #include "Elements/PCGPointProcessingElementBase.h" 29 | #include "Metadata/PCGAttributePropertySelector.h" 30 | 31 | #include "LBPCGBiomesNoise.generated.h" 32 | 33 | namespace PCGBiomesNoise 34 | { 35 | struct FLocalCoordinates2D 36 | { 37 | // coordinates to sample for the repeating edges (not 0 to 1, is scaled according to the settings scale) 38 | double X0; 39 | double Y0; 40 | double X1; 41 | double Y1; 42 | 43 | // how much to interpolate between the corners 44 | double FracX; 45 | double FracY; 46 | }; 47 | 48 | PCGLAYEREDBIOMES_API FLocalCoordinates2D CalcLocalCoordinates2D(const FBox& ActorLocalBox, const FTransform& ActorTransformInverse, FVector2D Scale, const FVector& Position); 49 | PCGLAYEREDBIOMES_API double CalcEdgeBlendAmount2D(const FLocalCoordinates2D& LocalCoords, double EdgeBlendDistance); 50 | } 51 | 52 | UCLASS(BlueprintType) 53 | class PCGLAYEREDBIOMES_API ULBPCGBiomesNoiseSettings : public UPCGSettings 54 | { 55 | GENERATED_BODY() 56 | 57 | public: 58 | ULBPCGBiomesNoiseSettings(); 59 | 60 | //~Begin UPCGSettings interface 61 | #if WITH_EDITOR 62 | virtual FName GetDefaultNodeName() const override { return FName(TEXT("BiomesNoise")); } 63 | virtual FText GetDefaultNodeTitle() const override { return NSLOCTEXT("PCGNoiseSettings", "NodeTitle", "Biomes Noise"); } 64 | virtual EPCGSettingsType GetType() const override { return EPCGSettingsType::Spatial; } 65 | #endif 66 | 67 | protected: 68 | virtual TArray InputPinProperties() const override; 69 | virtual TArray OutputPinProperties() const override; 70 | 71 | virtual FPCGElementPtr CreateElement() const override; 72 | //~End UPCGSettings interface 73 | 74 | public: 75 | 76 | // this is how many times the fractal method recurses. A higher number will mean more detail 77 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta = (ClampMin = "1", ClampMax = "100", EditConditionHides, PCG_Overridable)) 78 | int32 Iterations = 4; 79 | 80 | // if true, will generate results that tile along the bounding box size of the 81 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta = (PCG_Overridable)) 82 | bool bTiling = false; 83 | 84 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta = (PCG_Overridable)) 85 | float Brightness = 0.0; 86 | 87 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta = (PCG_Overridable)) 88 | float Contrast = 1.0; 89 | 90 | // The output attribute name to write, if not 'None' 91 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings) 92 | FPCGAttributePropertyOutputNoSourceSelector ValueTarget; 93 | 94 | // Adds a random amount of offset up to this amount 95 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta = (PCG_Overridable)) 96 | FVector RandomOffset = FVector(100000.0); 97 | 98 | // this will apply a transform to the points before calculating noise 99 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta = (EditCondition = "!bTiling", EditConditionHides, PCG_Overridable)) 100 | float Scale = 1.0f; 101 | }; 102 | 103 | class PCGLAYEREDBIOMES_API FLBPCGBiomesNoise : public FPCGPointProcessingElementBase 104 | { 105 | protected: 106 | virtual bool ExecuteInternal(FPCGContext* Context) const override; 107 | }; 108 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/Graph/LBPCGExplicitBiomeFromSplines.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "Elements/PCGDataFromActor.h" 28 | #include "LBPCGExplicitBiomeFromSplines.generated.h" 29 | 30 | class FPCGMetadataAttributeBase; 31 | 32 | /** 33 | * 34 | */ 35 | UCLASS(BlueprintType) 36 | class PCGLAYEREDBIOMES_API ULBPCGExplicitBiomeFromSplines : public UPCGDataFromActorSettings 37 | { 38 | GENERATED_BODY() 39 | 40 | ULBPCGExplicitBiomeFromSplines(); 41 | 42 | virtual FPCGElementPtr CreateElement() const override; 43 | 44 | //~Begin UPCGSettings interface 45 | #if WITH_EDITOR 46 | virtual FName GetDefaultNodeName() const override { return FName(TEXT("ExplicitBiomeFromSplines")); } 47 | virtual FText GetDefaultNodeTitle() const override { return NSLOCTEXT("PCGExplicitBiomeFromSplines", "NodeTitle", "Get Biome from Splines"); } 48 | virtual bool CanDynamicallyTrackKeys() const override { return true; } 49 | #endif 50 | 51 | protected: 52 | virtual TArray OutputPinProperties() const override; 53 | //~End UPCGSettings 54 | 55 | public: 56 | //~Begin UPCGDataFromActorSettings interface 57 | virtual EPCGDataType GetDataFilter() const override { return EPCGDataType::PolyLine; } 58 | //~End UPCGDataFromActorSettings 59 | 60 | }; 61 | 62 | class PCGLAYEREDBIOMES_API FLBPCGExplicitBiomeFromSplines : public IPCGElement 63 | { 64 | public: 65 | virtual FPCGContext* Initialize(const FPCGDataCollection& InputData, TWeakObjectPtr SourceComponent, const UPCGNode* Node) override; 66 | virtual bool CanExecuteOnlyOnMainThread(FPCGContext* Context) const override { return true; } 67 | virtual bool IsCacheable(const UPCGSettings* InSettings) const override { return false; } 68 | 69 | protected: 70 | virtual bool ExecuteInternal(FPCGContext* InContext) const; 71 | 72 | virtual void ProcessActors(FPCGContext* Context, const UPCGDataFromActorSettings* Settings, const TArray& FoundActors) const; 73 | virtual void ProcessActor(FPCGContext* Context, const UPCGDataFromActorSettings* Settings, AActor* FoundActor) const; 74 | 75 | /* Create (or clear) an attribute named by OutputAttributeName and depending on the selected type. Value can be overridden by params. Default value will be set to the specified value. */ 76 | static FPCGMetadataAttributeBase* ClearOrCreateAttribute(UPCGMetadata* Metadata, const FName OutputAttributeName, const FName Value); 77 | }; 78 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/Graph/LBPCGExtractBiomeData.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "PCGSettings.h" 28 | #include "Elements/PCGPointProcessingElementBase.h" 29 | #include "LBPCGExtractBiomeData.generated.h" 30 | 31 | class ULBBiomesSettings; 32 | 33 | /** 34 | * 35 | */ 36 | UCLASS(BlueprintType) 37 | class PCGLAYEREDBIOMES_API ULBPCGExtractBiomeData : public UPCGSettings 38 | { 39 | GENERATED_BODY() 40 | public: 41 | //~Begin UPCGSettings interface 42 | #if WITH_EDITOR 43 | virtual FName GetDefaultNodeName() const override { return FName(TEXT("ExtractBiomeData")); } 44 | virtual FText GetDefaultNodeTitle() const override { return NSLOCTEXT("ULBPCGExtractBiomeData", "NodeTitle", "Extract Biome Data"); } 45 | virtual EPCGSettingsType GetType() const override { return EPCGSettingsType::InputOutput; } 46 | virtual bool CanDynamicallyTrackKeys() const override { return true; } 47 | #endif 48 | 49 | protected: 50 | 51 | virtual TArray InputPinProperties() const override; 52 | virtual TArray OutputPinProperties() const override; 53 | 54 | virtual FPCGElementPtr CreateElement() const override; 55 | //~End UPCGSettings interface 56 | }; 57 | 58 | class PCGLAYEREDBIOMES_API FLBPCGExtractBiomeData final : public FPCGPointProcessingElementBase 59 | { 60 | protected: 61 | virtual bool ExecuteInternal(FPCGContext* Context) const override; 62 | virtual bool CanExecuteOnlyOnMainThread(FPCGContext* Context) const override { return true; } 63 | virtual void GetDependenciesCrc(const FPCGDataCollection& InInput, const UPCGSettings* InSettings, UPCGComponent* InComponent, FPCGCrc& OutCrc) const override; 64 | virtual bool ShouldComputeFullOutputDataCrc(FPCGContext* Context) const override { return true; } 65 | virtual bool IsCacheable(const UPCGSettings* InSettings) const override { return true; } 66 | }; 67 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/Graph/LBPCGGetAttributes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "PCGSettings.h" 28 | #include "Elements/PCGPointProcessingElementBase.h" 29 | #include "LBPCGGetAttributes.generated.h" 30 | 31 | /** 32 | * 33 | */ 34 | UCLASS(BlueprintType, ClassGroup = (Biomes)) 35 | class PCGLAYEREDBIOMES_API ULBPCGGetAttributesSettings : public UPCGSettings 36 | { 37 | GENERATED_BODY() 38 | 39 | //~Begin UPCGSettings interface 40 | #if WITH_EDITOR 41 | virtual FName GetDefaultNodeName() const override { return FName(TEXT("Get Attributes")); } 42 | virtual FText GetDefaultNodeTitle() const override { return NSLOCTEXT("ULBPCGGetAttributesSettings", "NodeTitle", "Get Attributes"); } 43 | virtual FText GetNodeTooltipText() const override { return NSLOCTEXT("ULBPCGGetAttributesSettings", "NodeTooltip", "Get specified attributes as output pins"); } 44 | virtual EPCGSettingsType GetType() const override { return EPCGSettingsType::Metadata; } 45 | #endif 46 | 47 | protected: 48 | virtual TArray InputPinProperties() const override; 49 | virtual TArray OutputPinProperties() const override; 50 | 51 | virtual FPCGElementPtr CreateElement() const override; 52 | //~End UPCGSettings interface 53 | 54 | public: 55 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Biomes) 56 | TArray Attributes; 57 | }; 58 | 59 | class PCGLAYEREDBIOMES_API FLBPCGGetAttributes final : public FPCGPointProcessingElementBase 60 | { 61 | protected: 62 | virtual bool ExecuteInternal(FPCGContext* Context) const override; 63 | }; 64 | 65 | /** 66 | * 67 | */ 68 | UCLASS(BlueprintType, ClassGroup = (Biomes)) 69 | class PCGLAYEREDBIOMES_API ULBPCGGetAllAttributesFromSettings : public UPCGSettings 70 | { 71 | GENERATED_BODY() 72 | 73 | //~Begin UPCGSettings interface 74 | #if WITH_EDITOR 75 | virtual FName GetDefaultNodeName() const override { return FName(TEXT("GetAllAttributesFrom")); } 76 | virtual FText GetDefaultNodeTitle() const override { return NSLOCTEXT("ULBPCGGetAllAttributesFromSettings", "NodeTitle", "Get All Attributes From"); } 77 | virtual EPCGSettingsType GetType() const override { return EPCGSettingsType::Metadata; } 78 | #endif 79 | 80 | protected: 81 | virtual TArray InputPinProperties() const override; 82 | virtual TArray OutputPinProperties() const override; 83 | 84 | virtual FPCGElementPtr CreateElement() const override; 85 | //~End UPCGSettings interface 86 | 87 | public: 88 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Biomes, meta=(PCG_Overridable)) 89 | int DataIndex = 0; 90 | }; 91 | 92 | class PCGLAYEREDBIOMES_API FLBPCGGetAllAttributesFrom final : public FPCGPointProcessingElementBase 93 | { 94 | protected: 95 | virtual bool ExecuteInternal(FPCGContext* Context) const override; 96 | }; 97 | 98 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/Graph/LBPCGMeshFromSpawnManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "Elements/PCGExecuteBlueprint.h" 28 | #include "Elements/PCGPointProcessingElementBase.h" 29 | #include "LBPCGMeshFromSpawnManager.generated.h" 30 | 31 | 32 | /** 33 | * Various fractal noises that can be used to filter points 34 | */ 35 | UCLASS(BlueprintType, ClassGroup = (Biomes)) 36 | class PCGLAYEREDBIOMES_API ULBPCGMeshFromSpawnManagerSettings : public UPCGSettings 37 | { 38 | GENERATED_BODY() 39 | 40 | public: 41 | ULBPCGMeshFromSpawnManagerSettings(); 42 | 43 | //~Begin UPCGSettings interface 44 | #if WITH_EDITOR 45 | virtual FName GetDefaultNodeName() const override { return FName(TEXT("MeshFromSpawnManager")); } 46 | virtual FText GetDefaultNodeTitle() const override { return NSLOCTEXT("PCGMeshFromSpawnManagerSettings", "NodeTitle", "Mesh From SpawnManager"); } 47 | virtual EPCGSettingsType GetType() const override { return EPCGSettingsType::Spatial; } 48 | virtual bool CanDynamicallyTrackKeys() const override { return true; } 49 | #endif 50 | 51 | protected: 52 | virtual TArray InputPinProperties() const override; 53 | virtual TArray OutputPinProperties() const override; 54 | 55 | virtual FPCGElementPtr CreateElement() const override; 56 | //~End UPCGSettings interface 57 | 58 | public: 59 | 60 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta = (PCG_Overridable)) 61 | FString SetName; 62 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta = (PCG_Overridable)) 63 | bool ApplyMeshBounds = false; 64 | 65 | // The output attribute name to write, if not 'None' 66 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings) 67 | FPCGAttributePropertyOutputNoSourceSelector ValueTarget; 68 | }; 69 | 70 | class PCGLAYEREDBIOMES_API FLBPCGMeshFromSpawnManager : public FPCGPointProcessingElementBase 71 | { 72 | protected: 73 | virtual bool ExecuteInternal(FPCGContext* Context) const override; 74 | virtual bool CanExecuteOnlyOnMainThread(FPCGContext* Context) const override { return true; } 75 | virtual void GetDependenciesCrc(const FPCGDataCollection& InInput, const UPCGSettings* InSettings, UPCGComponent* InComponent, FPCGCrc& OutCrc) const override; 76 | virtual bool ShouldComputeFullOutputDataCrc(FPCGContext* Context) const override { return true; } 77 | virtual bool IsCacheable(const UPCGSettings* InSettings) const override { return true; } 78 | }; 79 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/LBBiomesPCGUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "LBBiomesSpawnManager.h" 28 | #include "Data/PCGSpatialData.h" 29 | #include "Kismet/BlueprintFunctionLibrary.h" 30 | #include "Metadata/PCGAttributePropertySelector.h" 31 | #include "Metadata/Accessors/IPCGAttributeAccessor.h" 32 | #include "Metadata/Accessors/PCGAttributeAccessorKeys.h" 33 | #include "Metadata/Accessors/PCGAttributeAccessorHelpers.h" 34 | #include "LBBiomesPCGUtils.generated.h" 35 | 36 | struct FLBBiomesPersistentInstancesData; 37 | 38 | /** 39 | * Handle which identify mesh instance across all PCG Components in the world. 40 | * Can be stored in any place and used after game restart. 41 | * Invalidates if the world rebuilt with different seed or any changes to config or graphs were made. 42 | */ 43 | USTRUCT(BlueprintType, Category=Biomes) 44 | struct FLBBiomesInstanceHandle 45 | { 46 | GENERATED_BODY() 47 | 48 | FLBBiomesInstanceHandle() = default; 49 | 50 | explicit operator bool () const { return IsValid(); } 51 | 52 | bool IsValid() const { return InstanceId != INDEX_NONE && ComponentName != NAME_None; } 53 | 54 | public: 55 | /** 56 | * ID of a group. 57 | * Zero value is invalid. 58 | * Negative values are indices (-1) of non-partitioned PCG components. 59 | * Positive values are indices (+1) of APCGPartitionActor. 60 | */ 61 | UPROPERTY() 62 | int16 GroupId = 0; 63 | 64 | /** 65 | * ID of the mesh. 66 | */ 67 | UPROPERTY() 68 | FName ComponentName = NAME_None; 69 | 70 | /** 71 | * ID of the instance. 72 | * Actually it's original index of instance in ISM. 73 | */ 74 | UPROPERTY() 75 | int32 InstanceId = INDEX_NONE; 76 | }; 77 | 78 | /** 79 | * 80 | */ 81 | UCLASS() 82 | class PCGLAYEREDBIOMES_API ULBBiomesPCGUtils : public UBlueprintFunctionLibrary 83 | { 84 | GENERATED_BODY() 85 | 86 | public: 87 | UFUNCTION(BlueprintCallable, Category=Biomes) 88 | static ULBBiomesInstanceUserData* ExtractUserData( 89 | const UInstancedStaticMeshComponent* Component, 90 | const int32 InstanceId); 91 | 92 | UFUNCTION(BlueprintCallable, Category=Biomes) 93 | static bool ExtractSpawnInfo( 94 | const UInstancedStaticMeshComponent* Component, 95 | const int32 InstanceId, FLBPCGSpawnInfo& Result); 96 | 97 | UFUNCTION(BlueprintCallable, Category=Biomes, meta=(ExpandBoolAsExecs = "ReturnValue")) 98 | static bool RemoveInstance(UInstancedStaticMeshComponent* Component, const int32 InstanceId, 99 | FLBBiomesInstanceHandle& InstanceHandle, FTransform& InstanceTransform); 100 | 101 | UFUNCTION(BlueprintCallable, Category=Biomes) 102 | static bool RestoreInstance(const FLBBiomesInstanceHandle& InstanceHandle); 103 | 104 | UFUNCTION(BlueprintCallable, Category=Biomes, meta=(ExpandBoolAsExecs = "ReturnValue")) 105 | static bool GetTransformByHandle(const FLBBiomesInstanceHandle& InstanceHandle, FTransform& InstanceTransform); 106 | 107 | UFUNCTION(BlueprintCallable, Category=Biomes) 108 | static ULBBiomesInstanceUserData* GetUserDataByHandle(const FLBBiomesInstanceHandle& InstanceHandle); 109 | 110 | /** 111 | * Return structure which contains all information about removed instances in the world. 112 | * Can be stored anywhere and restored later with SetPersistentData 113 | */ 114 | UFUNCTION(BlueprintCallable, Category=Biomes) 115 | static FLBBiomesPersistentInstancesData GetPersistentData(); 116 | 117 | /** 118 | * Restore information about all removed instances in the world. 119 | * @param Data Which was returned by GetPersistentData. 120 | */ 121 | UFUNCTION(BlueprintCallable, Category=Biomes) 122 | static void SetPersistentData(const FLBBiomesPersistentInstancesData& Data); 123 | 124 | static ULBBiomesSpawnManager* GetSpawnManager(const UActorComponent* Component); 125 | static ULBBiomesSpawnManager* GetSpawnManager(const AActor* Actor); 126 | 127 | static int32 GetInteger32Attribute(const FPCGPoint& Point, const UPCGMetadata* Metadata, FName AttributeName); 128 | static FName GetNameAttribute(const FPCGPoint& Point, const UPCGMetadata* Metadata, FName AttributeName); 129 | 130 | template 131 | static bool CreateAndSetAttribute(FName AttributeName, UPCGMetadata* Metadata, AttributeType Value) 132 | { 133 | FPCGMetadataAttribute* NewAttribute = static_cast*>( 134 | Metadata->CreateAttribute(AttributeName, Value, /*bAllowInterpolation=*/false, /*bOverrideParent=*/false)); 135 | 136 | if (!NewAttribute) 137 | { 138 | return false; 139 | } 140 | 141 | NewAttribute->SetValue(Metadata->AddEntry(), Value); 142 | return true; 143 | } 144 | 145 | template 146 | static void SetAttributeHelper(UPCGSpatialData* Data, const FPCGAttributePropertySelector& PropertySelector, const TArrayView Values) 147 | { 148 | if (PropertySelector.GetSelection() == EPCGAttributePropertySelection::Attribute) 149 | { 150 | // Discard None attributes 151 | const FName AttributeName = PropertySelector.GetAttributeName(); 152 | if (AttributeName == NAME_None) 153 | { 154 | return; 155 | } 156 | constexpr bool Interpolate = std::is_arithmetic_v; 157 | Data->Metadata->FindOrCreateAttribute(AttributeName, {}, Interpolate); 158 | } 159 | 160 | TUniquePtr Accessor = PCGAttributeAccessorHelpers::CreateAccessor(Data, PropertySelector); 161 | if (!Accessor) 162 | { 163 | return; 164 | } 165 | 166 | TUniquePtr Keys = PCGAttributeAccessorHelpers::CreateKeys(Data, PropertySelector); 167 | if (!Keys) 168 | { 169 | return; 170 | } 171 | 172 | Accessor->SetRange(Values, 0, *Keys); 173 | } 174 | }; 175 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/LBBiomesSpawnManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "LBPCGSpawnStructures.h" 28 | #include "Components/ActorComponent.h" 29 | #include "Components/InstancedStaticMeshComponent.h" 30 | #include "LBBiomesSpawnManager.generated.h" 31 | 32 | 33 | class ULBBiomesInstanceController; 34 | struct FLBBiomeSettings; 35 | class UPCGComponent; 36 | class ULBBiomesSettings; 37 | 38 | UCLASS(Blueprintable, ClassGroup=(Biomes), meta=(BlueprintSpawnableComponent)) 39 | class PCGLAYEREDBIOMES_API ULBBiomesSpawnManager : public UActorComponent 40 | { 41 | GENERATED_BODY() 42 | 43 | friend class ULBBiomesInstanceController; 44 | 45 | public: 46 | static ULBBiomesSpawnManager* GetManager(UPCGComponent* InComponent); 47 | static ULBBiomesSpawnManager* GetManager(const AActor* Actor); 48 | 49 | virtual void BeginPlay() override; 50 | virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; 51 | 52 | const TArray* FindSet(const FString& SetName) const; 53 | const FLBBiomeSettings* FindSettings(FName BiomeName) const; 54 | 55 | FPCGCrc GetBiomesCrc() const; 56 | FSoftObjectPath GetBiomesSoftPath() const; 57 | 58 | FPCGCrc GetSpawnPresetCrc() const; 59 | FSoftObjectPath GetSpawnPresetSoftPath() const; 60 | 61 | virtual void PreSave(FObjectPreSaveContext SaveContext) override; 62 | 63 | #if WITH_EDITOR 64 | virtual void PostLoad() override; 65 | 66 | UFUNCTION(CallInEditor, Category="Interaction") 67 | void PrepareForRuntimeInteractions() const; 68 | 69 | void FixAllPCGActors() const; 70 | void OnGenerationDone(class UPCGSubsystem* Subsystem) const; 71 | 72 | virtual void CheckForErrors() override; 73 | 74 | #endif 75 | 76 | ULBBiomesInstanceUserData* GetExtraDataFromInstance(const UInstancedStaticMeshComponent* Component, 77 | const int32 InstanceId) const; 78 | ULBBiomesInstanceUserData* GetExtraData(int32 SetIndex, int32 ActorIndex) const; 79 | bool GetSpawnInfoFromInstance(const UInstancedStaticMeshComponent* Component, 80 | const int32 InstanceId, FLBPCGSpawnInfo& Result) const; 81 | 82 | public: 83 | struct FPackedTagsEntry 84 | { 85 | int32 SetIndex = INDEX_NONE; 86 | int32 ActorIndex = INDEX_NONE; 87 | }; 88 | 89 | const FLBPCGSpawnInfo* FindActorInfoByMesh(const TSoftObjectPtr& Mesh, FPackedTagsEntry& OutEntry) const; 90 | 91 | private: 92 | static FPackedTagsEntry GetTagEntryFromInstance(const UInstancedStaticMeshComponent* Component, const int32 InstanceId); 93 | static void SetTagEntryFromInstance(UInstancedStaticMeshComponent* Component, const int32 InstanceId, const FPackedTagsEntry& Data); 94 | 95 | protected: 96 | UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Biomes, AdvancedDisplay, meta=(EditCondition="false")) 97 | FGuid Guid; 98 | 99 | UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Biomes) 100 | TObjectPtr Preset; 101 | 102 | UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Biomes) 103 | TObjectPtr Biomes; 104 | 105 | struct FInstancedActor 106 | { 107 | FSoftObjectPath StaticMesh; 108 | int32 InstanceId = INDEX_NONE; 109 | }; 110 | TMap, FInstancedActor> DisabledInstances; 111 | }; 112 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/LBBiomesTagPacker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "InstanceDataPackers/PCGInstanceDataPackerBase.h" 28 | #include "LBBiomesTagPacker.generated.h" 29 | 30 | /** 31 | * 32 | */ 33 | UCLASS(BlueprintType, ClassGroup = (Procedural), Category="Biomes") 34 | class PCGLAYEREDBIOMES_API ULBBiomesTagPacker : public UPCGInstanceDataPackerBase 35 | { 36 | GENERATED_BODY() 37 | 38 | public: 39 | virtual void PackInstances_Implementation(UPARAM(ref) FPCGContext& Context, const UPCGSpatialData* InSpatialData, UPARAM(ref) const FPCGMeshInstanceList& InstanceList, FPCGPackedCustomData& OutPackedCustomData) const override; 40 | }; 41 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/LBExplicitBiomeActor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "GameFramework/Actor.h" 28 | #include "LBExplicitBiomeActor.generated.h" 29 | 30 | UCLASS(Abstract, Blueprintable) 31 | class PCGLAYEREDBIOMES_API ALBExplicitBiomeActor : public AActor 32 | { 33 | GENERATED_BODY() 34 | 35 | public: 36 | ALBExplicitBiomeActor(); 37 | 38 | public: 39 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Biomes) 40 | FName Biome; 41 | }; 42 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/LBPCGLayeredBiomes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "CoreMinimal.h" 26 | #include "Modules/ModuleManager.h" 27 | 28 | class FLBPCGLayeredBiomesModule : public IModuleInterface 29 | { 30 | public: 31 | 32 | /** IModuleInterface implementation */ 33 | virtual void StartupModule() override; 34 | virtual void ShutdownModule() override; 35 | }; 36 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/LBPCGSpawnStructures.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "Engine/DataAsset.h" 28 | #include "Components/StaticMeshComponent.h" 29 | #include "LBPCGSpawnStructures.generated.h" 30 | 31 | struct FPCGCrc; 32 | 33 | UCLASS(Abstract, Const, Blueprintable, DefaultToInstanced, EditInlineNew, CollapseCategories, ClassGroup=(Biomes)) 34 | class ULBBiomesInstanceUserData : public UObject 35 | { 36 | GENERATED_BODY() 37 | }; 38 | 39 | /** 40 | * 41 | */ 42 | USTRUCT(BlueprintType, Category=Biomes) 43 | struct PCGLAYEREDBIOMES_API FLBPCGSpawnInfo 44 | { 45 | GENERATED_BODY() 46 | 47 | FPCGCrc ComputeCrc() const; 48 | 49 | UPROPERTY(BlueprintReadOnly, EditAnywhere, Category=Biomes) 50 | TSoftObjectPtr Mesh; 51 | 52 | /** 53 | * Any additional information for that InstancedMesh 54 | */ 55 | UPROPERTY(BlueprintReadOnly, EditAnywhere, Instanced, Category=Biomes) 56 | TObjectPtr UserData; 57 | 58 | UPROPERTY(BlueprintReadOnly, EditAnywhere, Category=Biomes, meta=(ClampMin=1, UIMin=1)) 59 | int Weight = 1; 60 | }; 61 | 62 | USTRUCT(BlueprintType, Category=Biomes) 63 | struct PCGLAYEREDBIOMES_API FLBPCGSpawnSet 64 | { 65 | GENERATED_BODY() 66 | 67 | UPROPERTY(EditAnywhere, Category=Biomes) 68 | FString Name; 69 | 70 | UPROPERTY(EditAnywhere, Category=Biomes) 71 | TArray Actors; 72 | }; 73 | 74 | UCLASS(ClassGroup=(Biomes)) 75 | class PCGLAYEREDBIOMES_API ULBPCGSpawnPreset : public UPrimaryDataAsset 76 | { 77 | GENERATED_BODY() 78 | 79 | public: 80 | FPCGCrc ComputeCrc(); 81 | bool HasUserData() const; 82 | 83 | UPROPERTY(EditAnywhere, Category=Biomes, meta=(TitleProperty="Name")) 84 | TArray Sets; 85 | }; 86 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/Runtime/LBBiomesInstanceController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | 24 | #pragma once 25 | 26 | #include "CoreMinimal.h" 27 | #include "LBBiomesSpawnManager.h" 28 | #include "InstancedStaticMeshDelegates.h" 29 | #include "LBPCGSpawnStructures.h" 30 | #include "UObject/Object.h" 31 | #include "Engine/StaticMesh.h" 32 | #include "Subsystems/WorldSubsystem.h" 33 | #include "Grid/PCGPartitionActor.h" 34 | #include "LBBiomesInstanceController.generated.h" 35 | 36 | struct FLBBiomesInstanceHandle; 37 | 38 | USTRUCT(BlueprintType, Category=Biomes) 39 | struct PCGLAYEREDBIOMES_API FLBBiomesInstanceData 40 | { 41 | GENERATED_BODY() 42 | 43 | explicit operator bool () const { return Id != INDEX_NONE && ComponentName != NAME_None; } 44 | bool operator==(const FLBBiomesInstanceHandle& InstanceId) const; 45 | 46 | public: 47 | UPROPERTY() 48 | int32 Id = INDEX_NONE; 49 | UPROPERTY() 50 | FTransform Transform; 51 | UPROPERTY() 52 | FName ComponentName = NAME_None; 53 | 54 | UPROPERTY() 55 | int32 Custom_SetIndex = INDEX_NONE; 56 | UPROPERTY() 57 | int32 Custom_ActorIndex = INDEX_NONE; 58 | }; 59 | 60 | 61 | 62 | USTRUCT(BlueprintType) 63 | struct PCGLAYEREDBIOMES_API FLBBiomesPartition 64 | { 65 | GENERATED_BODY() 66 | 67 | bool operator==(const FLBBiomesPartition& Other) const 68 | { 69 | return (GridCoord == Other.GridCoord) && (GridSize == Other.GridSize); 70 | } 71 | 72 | friend uint32 GetTypeHash(const FLBBiomesPartition& Key) 73 | { 74 | return HashCombine(GetTypeHash(Key.GridCoord), GetTypeHash(Key.GridSize)); 75 | } 76 | 77 | UPROPERTY() 78 | FIntVector GridCoord = FIntVector::ZeroValue; 79 | UPROPERTY() 80 | uint32 GridSize = 0; 81 | }; 82 | 83 | 84 | USTRUCT(BlueprintType) 85 | struct PCGLAYEREDBIOMES_API FLBBiomesPersistentPartitionedInstances 86 | { 87 | GENERATED_BODY() 88 | 89 | UPROPERTY() 90 | FLBBiomesPartition Partition; 91 | 92 | UPROPERTY() 93 | TArray Instances; 94 | }; 95 | 96 | USTRUCT(BlueprintType) 97 | struct PCGLAYEREDBIOMES_API FLBBiomesPersistentMainInstances 98 | { 99 | GENERATED_BODY() 100 | 101 | UPROPERTY() 102 | FGuid Guid; 103 | 104 | UPROPERTY() 105 | TArray Instances; 106 | }; 107 | 108 | USTRUCT(BlueprintType) 109 | struct PCGLAYEREDBIOMES_API FLBBiomesPersistentInstancesData 110 | { 111 | GENERATED_BODY() 112 | 113 | UPROPERTY() 114 | TArray Mains; 115 | UPROPERTY() 116 | TArray Partitions; 117 | 118 | UPROPERTY() 119 | TArray MainInstances; 120 | UPROPERTY() 121 | TArray PartitionedInstances; 122 | }; 123 | 124 | USTRUCT() 125 | struct FLBBiomesISMList 126 | { 127 | GENERATED_BODY() 128 | 129 | UPROPERTY(Transient) 130 | TArray> Components; 131 | }; 132 | 133 | /** 134 | * 135 | */ 136 | UCLASS() 137 | class PCGLAYEREDBIOMES_API ULBBiomesInstanceController : public UWorldSubsystem 138 | { 139 | GENERATED_BODY() 140 | 141 | public: 142 | ULBBiomesInstanceController(); 143 | 144 | using FBiomesInstances = TArray; 145 | using FTrackedComponents = TMap, TArray>; 146 | 147 | static ULBBiomesInstanceController* GetInstance(const UObject* WorldContext); 148 | 149 | FLBBiomesInstanceHandle RemoveInstance(UInstancedStaticMeshComponent* Component, int32 InstanceId); 150 | bool RestoreInstance(const FLBBiomesInstanceHandle& InstanceHandle); 151 | 152 | bool GetInstanceTransform(const FLBBiomesInstanceHandle& InstanceHandle, FTransform& InstanceTransform); 153 | ULBBiomesInstanceUserData* GetUserData(const FLBBiomesInstanceHandle& InstanceHandle); 154 | 155 | /** 156 | * Return structure which contains all information about removed instances in the world. 157 | * Can be stored anywhere and restored later with SetPersistentData 158 | */ 159 | UFUNCTION(BlueprintCallable, Category=Biomes) 160 | FLBBiomesPersistentInstancesData GetPersistentData() const; 161 | 162 | /** 163 | * Restore information about all removed instances in the world. 164 | * @param Data Which was returned by GetPersistentData. 165 | */ 166 | UFUNCTION(BlueprintCallable, Category=Biomes) 167 | void SetPersistentData(const FLBBiomesPersistentInstancesData& Data); 168 | 169 | void OnPartitionLoaded(APCGPartitionActor* PartitionActor); 170 | void OnPartitionUnloaded(APCGPartitionActor* PartitionActor); 171 | 172 | virtual void Initialize(FSubsystemCollectionBase& Collection) override; 173 | virtual void Deinitialize() override; 174 | 175 | void RegisterManager(ULBBiomesSpawnManager* Manager); 176 | void UnRegisterManager(ULBBiomesSpawnManager* Manager); 177 | 178 | protected: 179 | struct FResult 180 | { 181 | FBiomesInstances* Instances = nullptr; 182 | int32 Index = INDEX_NONE; 183 | AActor* Actor = nullptr; 184 | 185 | const FLBBiomesInstanceData& GetData() const { return (*Instances)[Index]; } 186 | }; 187 | 188 | bool FindDataByHandle(const FLBBiomesInstanceHandle& Handle, FResult& Result); 189 | 190 | FLBBiomesInstanceHandle RemoveInstanceImpl(UInstancedStaticMeshComponent* Component, int32 InstanceId); 191 | bool RestoreInstanceImpl(const FName& ComponentName, const FLBBiomesInstanceData& Data, AActor* Actor); 192 | 193 | static void EnsureInstancesUnique(const FTransform& Transform, const int32 OriginalIndex, const FName ComponentName, const TArray& Instances); 194 | 195 | UPCGComponent* FindPcgComponent(const FGuid& Guid); 196 | 197 | const TArray>& CachePartition(AActor* Actor); 198 | UInstancedStaticMeshComponent* FindISM(AActor* Actor, const FName& ComponentName); 199 | static UInstancedStaticMeshComponent* FindISM(const FName& ComponentName, const TArray>* ISMs); 200 | 201 | FBiomesInstances* GetInstancesFor(const APCGPartitionActor* PartitionActor); 202 | 203 | int16 GetMainIndex(const UPCGComponent* Component); 204 | int16 GetPartitionIndex(const FIntVector& ActorGridCoords, uint32 ActorGridSize); 205 | 206 | int32 GetOriginalIndex(UInstancedStaticMeshComponent* Component, int32 InstanceId); 207 | void SetOriginalIndex(const UInstancedStaticMeshComponent* Component, int32 OriginalId, int32 InstanceId); 208 | void Track(UInstancedStaticMeshComponent* Component); 209 | static void InitTrackedComponent(const UInstancedStaticMeshComponent* Component, TArray& Mapping); 210 | 211 | bool ApplyStateToActor(AActor* Actor, const FBiomesInstances& Instances, bool ConvertToLocal); 212 | 213 | void OnInstanceIndexRelocated(UInstancedStaticMeshComponent* Component, TArrayView Data); 214 | static void OnInstanceIndexUpdated(UInstancedStaticMeshComponent* Component, TArrayView Data); 215 | 216 | protected: 217 | TMap MainInstances; 218 | TMap PartitionedInstances; 219 | 220 | // Persistent array of non-partitioned PCG components. 221 | // Indices of it are used in handles, so they should never be changed 222 | TArray Mains; 223 | // Persistent array of partitions. Indices of it are used in handles, so they should never be changed 224 | TArray Partitions; 225 | 226 | UPROPERTY(Transient) 227 | TMap, FLBBiomesISMList> ISMMapping; 228 | UPROPERTY(Transient) 229 | TMap> PcgComponents; 230 | UPROPERTY(Transient) 231 | TArray> Managers; 232 | 233 | FTrackedComponents TrackedComponents; 234 | FDelegateHandle DelegateHandle; 235 | }; 236 | 237 | -------------------------------------------------------------------------------- /Source/PCGLayeredBiomes/Public/Runtime/LBBiomesInstanceTracker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 LazyCatsDev 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "CoreMinimal.h" 26 | #include "LBBiomesPCGUtils.h" 27 | #include "Components/ActorComponent.h" 28 | #include "LBBiomesInstanceTracker.generated.h" 29 | 30 | 31 | UCLASS(ClassGroup=(Biomes), meta=(BlueprintSpawnableComponent)) 32 | class PCGLAYEREDBIOMES_API ULBBiomesInstanceTracker : public UActorComponent 33 | { 34 | GENERATED_BODY() 35 | 36 | public: 37 | ULBBiomesInstanceTracker(); 38 | 39 | void SetHandle(const FLBBiomesInstanceHandle& Value); 40 | 41 | protected: 42 | virtual void BeginPlay() override; 43 | virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; 44 | 45 | protected: 46 | UPROPERTY(BlueprintReadWrite, meta=(ExposeOnSpawn), Category=Biomes) 47 | FLBBiomesInstanceHandle Handle; 48 | }; 49 | --------------------------------------------------------------------------------