One map is generated procedurally with landscape heightmap on it

This commit is contained in:
aollero 2022-02-04 10:55:08 +01:00 committed by bernat
parent 416510bc89
commit 41d93b4a65
8 changed files with 127 additions and 22 deletions

View File

@ -25,7 +25,7 @@ public class CarlaTools : ModuleRules
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"Core"
// ... add other public dependencies that you statically link with here ...
}
);
@ -40,7 +40,9 @@ public class CarlaTools : ModuleRules
"SlateCore",
"UnrealEd",
"Blutility",
"UMG"
"UMG",
"EditorScriptingUtilities",
"Landscape"
// ... add private dependencies that you statically link with here ...
}
);

View File

@ -8,20 +8,99 @@
#include "MapGeneratorWidget.h"
#define DEBUG_MSG(x, ...) if(GEngine){GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, FString::Printf(TEXT(x), __VA_ARGS__));}
#include "AssetRegistryModule.h"
#include "EditorLevelLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "Landscape.h"
#include "LandscapeProxy.h"
#include "Runtime/Engine/Classes/Engine/ObjectLibrary.h"
#define DEBUG_MSG(x, ...) if(GEngine){GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Blue, FString::Printf(TEXT(x), __VA_ARGS__));}
#define DEBUG_MSG_RED(x, ...) if(GEngine){GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, FString::Printf(TEXT(x), __VA_ARGS__));}
// UMapGeneratorWidget::UMapGeneratorWidget()
// {
// }
// UMapGeneratorWidget::~UMapGeneratorWidget()
// {}
void UMapGeneratorWidget::HelloWorld()
FString UMapGeneratorWidget::GenerateMapFiles(const FString& destinationPath, const FString& mapName)
{
DEBUG_MSG("RT Changed")
DEBUG_MSG("Generating new map...");
FString errorMsg = "";
FAssetData worldAssetData;
// 1. Creating Levels
bool bLoaded = LoadWorld(worldAssetData);
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, bLoaded ? "Loaded CORRECT" : "NOT loaded");
// 2. Applying heightmap
UWorld* world = CastChecked<UWorld>(worldAssetData.GetAsset());
ALandscape* landscape = (ALandscape*) UGameplayStatics::GetActorOfClass(world, ALandscape::StaticClass());
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Green, landscape!=nullptr ? "L TRUE" : "L FALSE");
AssignLandscapeHeightMap(landscape);
// 3. Saving world
bool bSaved = SaveWorld(worldAssetData, destinationPath, mapName);
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Green, bSaved ? "Saved CORRECT" : "NOT saved");
return errorMsg;
}
bool UMapGeneratorWidget::LoadWorld(FAssetData& WorldAssetData)
{
TArray<FAssetData> AssetDatas;
UObjectLibrary *MapObjectLibrary;
const FString BaseMap = TEXT("/CarlaTools/MapGenerator/BaseMap");
// Loading Map from folder using object library
MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(), false, GIsEditor);
MapObjectLibrary->AddToRoot();
MapObjectLibrary->LoadAssetDataFromPath(*BaseMap);
MapObjectLibrary->LoadAssetsFromAssetData();
MapObjectLibrary->GetAssetDataList(AssetDatas);
if (AssetDatas.Num() > 0)
{
// Extract first asset found in folder path (i.e. the BaseMap)
WorldAssetData = AssetDatas.Pop();
return true;
}
else
return false;
}
bool UMapGeneratorWidget::SaveWorld(FAssetData& WorldToBeSaved, const FString& DestinationPath, const FString& WorldName)
{
UWorld* world;
UObjectRedirector *BaseMapRedirector = Cast<UObjectRedirector>(WorldToBeSaved.GetAsset());
if(BaseMapRedirector != nullptr)
world = CastChecked<UWorld>(BaseMapRedirector->DestinationObject);
else
world = CastChecked<UWorld>(WorldToBeSaved.GetAsset());
// Create package
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Preparing package");
UPackage *package = WorldToBeSaved.GetPackage();
package->SetFolderName("TestFolder001");
package->FullyLoad();
package->MarkPackageDirty();
FAssetRegistryModule::AssetCreated(world);
// Rename new World
world->Rename(*WorldName, world->GetOuter());
const FString PackagePath = DestinationPath + "/" + WorldName;
FAssetRegistryModule::AssetRenamed(world, *PackagePath);
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, world->GetMapName());
world->MarkPackageDirty();
world->GetOuter()->MarkPackageDirty();
// Saving package
const FString PackageFileName = FPackageName::LongPackageNameToFilename(PackagePath, FPackageName::GetMapPackageExtension());
if(FPaths::FileExists(*PackageFileName))
{
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Package already Exists");
return false;
}
return UPackage::SavePackage(package, world, EObjectFlags::RF_Public | EObjectFlags::RF_Standalone,
*PackageFileName, GError, nullptr, true, true, SAVE_NoError);
}
// #endif

View File

@ -7,28 +7,52 @@
// #if WITH_EDITOR
// #pragma once
#pragma once
#include "CoreMinimal.h"
#include "EditorUtilityWidget.h"
//#include "Editor/Blutility/Classes/EditorUtilityWidget.h"
#include "Engine/TextureRenderTarget2D.h"
#include "UnrealString.h"
#include "MapGeneratorWidget.generated.h"
// /**
// *
// */
/// Class UMapGeneratorWidget extends the functionality of UEditorUtilityWidget
/// to be able to generate and manage maps and largemaps tiles for procedural
/// map generation
UCLASS(BlueprintType)
//UCLASS()
class CARLATOOLS_API UMapGeneratorWidget : public UEditorUtilityWidget
{
GENERATED_BODY()
public:
// UMapGeneratorWidget();
// ~UMapGeneratorWidget();
/// This function invokes a blueprint event defined in widget blueprint
/// event graph, which sets a heightmap to the @a landscape using
/// ALandscapeProxy::LandscapeImportHeightMapFromRenderTarget(...)
/// function, which is not exposed to be used in C++ code, only blueprints
UFUNCTION(BlueprintImplementableEvent)
void AssignLandscapeHeightMap(ALandscape* landscape);
UFUNCTION(BlueprintCallable)
void HelloWorld();
//private:
// UPROPERTY()
// UObjectLibrary *MapObjectLibrary;
public:
/// Function called by Widget Blueprint which generates all tiles of map
/// @a mapName, and saves them in @a destinationPath
/// Returns a void string is success and an error message if the process failed
UFUNCTION(Category="Map Generator",BlueprintCallable)
FString GenerateMapFiles(const FString& destinationPath, const FString& mapName);
private:
/// Loads the base template UWorld object and is return in @a WorldAssetData
/// The funtions return true is success, otherwise false
UFUNCTION()
bool LoadWorld(FAssetData& WorldAssetData);
/// Saves a world contained in @a WorldToBeSaved, in the path defined in @a DestinationPath
/// named as @a WorldName, as a package .umap
UFUNCTION()
bool SaveWorld(FAssetData& WorldToBeSaved, const FString& DestinationPath, const FString& WorldName);
};
// #endif