Merging //UE4/Dev-Main to Dev-Networking (//UE4/Dev-Networking)

#rb none
#rnx

[CL 4344260 by Ryan Gerleve in Dev-Networking branch]
This commit is contained in:
Ryan Gerleve
2018-09-05 10:17:10 -04:00
parent ed97627519
commit f20cd46b96
1916 changed files with 189490 additions and 4127 deletions
File diff suppressed because it is too large Load Diff
+2
View File
@@ -106,6 +106,8 @@ EditorBrushMaterialName=/Engine/EngineMaterials/EditorBrushMaterial.EditorBrushM
DefaultPhysMaterialName=/Engine/EngineMaterials/DefaultPhysicalMaterial.DefaultPhysicalMaterial
DefaultDeferredDecalMaterialName=/Engine/EngineMaterials/DefaultDeferredDecalMaterial.DefaultDeferredDecalMaterial
DefaultPostProcessMaterialName=/Engine/EngineMaterials/DefaultPostProcessMaterial.DefaultPostProcessMaterial
TimecodeProviderClassName=None
DefaultTimecodeProviderClassName=/Script/Engine.SystemTimeTimecodeProvider
TextureStreamingBoundsMaterialName=/Engine/EditorMaterials/Utilities/TextureStreamingBounds_MATInst.TextureStreamingBounds_MATInst
ArrowMaterialName=/Engine/EditorMaterials/GizmoMaterial.GizmoMaterial
bAllowHostMigration=false
File diff suppressed because it is too large Load Diff
@@ -95,3 +95,16 @@ void ULiveLinkComponent::GetSubjectDataAtWorldTime(const FName SubjectName, cons
}
}
}
void ULiveLinkComponent::GetSubjectDataAtSceneTime(const FName SubjectName, const FTimecode& SceneTime, bool& bSuccess, FSubjectFrameHandle& SubjectFrameHandle)
{
bSuccess = false;
if (HasLiveLinkClient())
{
if (const FLiveLinkSubjectFrame* SubjectFrame = LiveLinkClient->GetSubjectDataAtSceneTime(SubjectName, SceneTime))
{
SubjectFrameHandle.SetCachedFrame(MakeShared<FCachedSubjectFrame>(SubjectFrame));
bSuccess = true;
}
}
}
@@ -0,0 +1,117 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "LiveLinkTimeSynchronizationSource.h"
#include "LiveLinkClient.h"
#include "Features/IModularFeatures.h"
#include "Math/NumericLimits.h"
ULiveLinkTimeSynchronizationSource::ULiveLinkTimeSynchronizationSource()
{
if (!HasAnyFlags(RF_ArchetypeObject | RF_ClassDefaultObject))
{
IModularFeatures& ModularFeatures = IModularFeatures::Get();
ModularFeatures.OnModularFeatureRegistered().AddUObject(this, &ThisClass::OnModularFeatureRegistered);
ModularFeatures.OnModularFeatureUnregistered().AddUObject(this, &ThisClass::OnModularFeatureUnregistered);
if (ModularFeatures.IsModularFeatureAvailable(ILiveLinkClient::ModularFeatureName))
{
LiveLinkClient = &ModularFeatures.GetModularFeature<FLiveLinkClient>(ILiveLinkClient::ModularFeatureName);
}
}
}
FFrameTime ULiveLinkTimeSynchronizationSource::GetNewestSampleTime() const
{
UpdateCachedState();
return CachedData.NewestSampleTime + FrameOffset;
}
FFrameTime ULiveLinkTimeSynchronizationSource::GetOldestSampleTime() const
{
UpdateCachedState();
return CachedData.OldestSampleTime + FrameOffset;
}
FFrameRate ULiveLinkTimeSynchronizationSource::GetFrameRate() const
{
UpdateCachedState();
return CachedData.Settings.FrameRate;
}
bool ULiveLinkTimeSynchronizationSource::IsReady() const
{
UpdateCachedState();
return LiveLinkClient && CachedData.bIsValid && (ESyncState::NotSynced == State || LastUpdateGuid == CachedData.SkeletonGuid);
}
bool ULiveLinkTimeSynchronizationSource::Open(const FTimeSynchronizationOpenData& OpenData)
{
UE_LOG(LogLiveLink, Log, TEXT("ULiveLinkTimeSynchronizationSource::Open %s"), *SubjectName.ToString());
if (ensure(LiveLinkClient != nullptr) && IsReady())
{
State = ESyncState::Opened;
LastUpdateGuid = CachedData.SkeletonGuid;
LiveLinkClient->OnStartSynchronization(SubjectName, OpenData, FrameOffset);
return true;
}
else
{
State = ESyncState::NotSynced;
return false;
}
}
void ULiveLinkTimeSynchronizationSource::Start(const FTimeSynchronizationStartData& StartData)
{
UE_LOG(LogLiveLink, Log, TEXT("ULiveLinkTimeSynchronizationSource::Start %s"), *SubjectName.ToString());
if (ensure(LiveLinkClient != nullptr))
{
State = ESyncState::Synced;
LiveLinkClient->OnSynchronizationEstablished(SubjectName, StartData);
}
else
{
State = ESyncState::NotSynced;
}
}
void ULiveLinkTimeSynchronizationSource::Close()
{
UE_LOG(LogLiveLink, Log, TEXT("ULiveLinkTimeSynchronizationSource::Close %s"), *SubjectName.ToString());
if (ensure(LiveLinkClient != nullptr))
{
LiveLinkClient->OnStopSynchronization(SubjectName);
}
State = ESyncState::NotSynced;
}
FString ULiveLinkTimeSynchronizationSource::GetDisplayName() const
{
return SubjectName.ToString();
}
void ULiveLinkTimeSynchronizationSource::OnModularFeatureRegistered(const FName& FeatureName, class IModularFeature* Feature)
{
if (FeatureName == ILiveLinkClient::ModularFeatureName)
{
LiveLinkClient = static_cast<FLiveLinkClient*>(Feature);
}
}
void ULiveLinkTimeSynchronizationSource::OnModularFeatureUnregistered(const FName& FeatureName, class IModularFeature* Feature)
{
if (FeatureName == ILiveLinkClient::ModularFeatureName && (LiveLinkClient != nullptr) && ensure(Feature == LiveLinkClient))
{
LiveLinkClient = nullptr;
}
}
void ULiveLinkTimeSynchronizationSource::UpdateCachedState() const
{
if (LastUpdateFrame != GFrameCounter && LiveLinkClient != nullptr)
{
LastUpdateFrame = GFrameCounter;
CachedData = LiveLinkClient->GetTimeSyncData(SubjectName);
}
}
@@ -0,0 +1,55 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "TimeSynchronizationSource.h"
#include "LiveLinkClient.h"
#include "Misc/Guid.h"
#include "LiveLinkTimeSynchronizationSource.generated.h"
UCLASS(EditInlineNew)
class ULiveLinkTimeSynchronizationSource : public UTimeSynchronizationSource
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, Category="LiveLink")
FName SubjectName;
FLiveLinkClient* LiveLinkClient;
enum class ESyncState
{
NotSynced,
Opened,
Synced
};
mutable ESyncState State = ESyncState::NotSynced;
mutable int64 LastUpdateFrame;
mutable FLiveLinkSubjectTimeSyncData CachedData;
mutable FGuid LastUpdateGuid;
public:
ULiveLinkTimeSynchronizationSource();
//~ Begin TimeSynchronizationSource API
virtual FFrameTime GetNewestSampleTime() const override;
virtual FFrameTime GetOldestSampleTime() const override;
virtual FFrameRate GetFrameRate() const override;
virtual bool IsReady() const override;
virtual bool Open(const FTimeSynchronizationOpenData& OpenData) override;
virtual void Start(const FTimeSynchronizationStartData& StartData) override;
virtual void Close() override;
virtual FString GetDisplayName() const override;
//~ End TimeSynchronizationSource API
private:
void OnModularFeatureRegistered(const FName& FeatureName, class IModularFeature* Feature);
void OnModularFeatureUnregistered(const FName& FeatureName, class IModularFeature* Feature);
void UpdateCachedState() const;
};
@@ -17,15 +17,22 @@
// Live Link Log Category
DECLARE_LOG_CATEGORY_EXTERN(LogLiveLink, Log, All);
struct FLiveLinkSubjectTimeSyncData
{
bool bIsValid = false;
FGuid SkeletonGuid;
FFrameTime OldestSampleTime;
FFrameTime NewestSampleTime;
FLiveLinkTimeSynchronizationSettings Settings;
};
struct FLiveLinkSubject
{
// Key for storing curve data (Names)
FLiveLinkCurveKey CurveKeyData;
FLiveLinkCurveKey CurveKeyData;
// Subject data frames that we have received (transforms and curve values)
TArray<FLiveLinkFrame> Frames;
TArray<FLiveLinkFrame> Frames;
// Time difference between current system time and TimeCode times
double SubjectTimeOffset;
@@ -40,42 +47,110 @@ struct FLiveLinkSubject
// Guid to track the last live link source that modified us
FGuid LastModifier;
// Connection settings specified by user
FLiveLinkInterpolationSettings CachedInterpolationSettings;
FLiveLinkSubject(const FLiveLinkRefSkeleton& InRefSkeleton)
: RefSkeleton(InRefSkeleton)
FLiveLinkSubject(const FLiveLinkRefSkeleton& InRefSkeleton, FName InName)
: Name(InName)
, RefSkeleton(InRefSkeleton)
, RefSkeletonGuid(FGuid::NewGuid())
{}
FLiveLinkSubject()
{}
// Add a frame of data from a FLiveLinkFrameData
void AddFrame(const FLiveLinkFrameData& FrameData, FGuid FrameSource, bool bSaveFrame);
// Populate OutFrame with a frame based off of the supplied time and our own offsets
void GetFrameAtWorldTime(const double InSeconds, FLiveLinkSubjectFrame& OutFrame);
// Populate OutFrame with a frame based off of the supplied scene time.
void GetFrameAtSceneTime(const FQualifiedFrameTime& InSceneTime, FLiveLinkSubjectFrame& OutFrame);
// Get this subjects ref skeleton
const FLiveLinkRefSkeleton& GetRefSkeleton() const { return RefSkeleton; }
// Handling setting a new ref skeleton
void SetRefSkeleton(const FLiveLinkRefSkeleton& InRefSkeleton) { RefSkeleton = InRefSkeleton; RefSkeletonGuid = FGuid::NewGuid(); }
// Free all subject data frames.
void ClearFrames();
void CacheSourceSettings(const ULiveLinkSourceSettings* DataToCache);
FName GetName() const { return Name; }
ELiveLinkSourceMode GetMode() const { return CachedSettings.SourceMode; }
FLiveLinkSubjectTimeSyncData GetTimeSyncData();
void OnStartSynchronization(const struct FTimeSynchronizationOpenData& OpenData, const int32 FrameOffset);
void OnSynchronizationEstablished(const struct FTimeSynchronizationStartData& StartData);
void OnStopSynchronization();
private:
// Copy a frame from the buffer to a FLiveLinkSubjectFrame
static void CopyFrameData(const FLiveLinkFrame& InFrame, FLiveLinkSubjectFrame& OutFrame);
// Blend two frames from the buffer and copy the result to a FLiveLinkSubjectFrame
static void CopyFrameDataBlended(const FLiveLinkFrame& PreFrame, const FLiveLinkFrame& PostFrame, float BlendWeight, FLiveLinkSubjectFrame& OutFrame);
void ResetFrame(FLiveLinkSubjectFrame& OutFrame) const;;
int32 AddFrame_Default(const FLiveLinkWorldTime& FrameTime, bool bSaveFrame);
int32 AddFrame_Interpolated(const FLiveLinkWorldTime& FrameTime, bool bSaveFrame);
int32 AddFrame_TimeSynchronized(const FFrameTime& FrameTime, bool bSaveFrame);
template<bool bWithRollover>
int32 AddFrame_TimeSynchronized(const FFrameTime& FrameTime, bool bSaveFrame);
void GetFrameAtWorldTime_Default(const double InSeconds, FLiveLinkSubjectFrame& OutFrame);
void GetFrameAtWorldTime_Interpolated(const double InSeconds, FLiveLinkSubjectFrame& OutFrame);
template<bool bWithRollover>
void GetFrameAtSceneTime_TimeSynchronized(const FFrameTime& FrameTime, FLiveLinkSubjectFrame& OutFrame);
template<bool bForInsert, bool bWithRollover>
int32 FindFrameIndex_TimeSynchronized(const FFrameTime& FrameTime);
FName Name;
struct FLiveLinkCachedSettings
{
ELiveLinkSourceMode SourceMode = ELiveLinkSourceMode::Default;
TOptional<FLiveLinkInterpolationSettings> InterpolationSettings;
TOptional<FLiveLinkTimeSynchronizationSettings> TimeSynchronizationSettings;
};
// Connection settings specified by user
// May only store settings relevant to the current mode (ELiveLinkSourceMode).
FLiveLinkCachedSettings CachedSettings;
// Ref Skeleton for transforms
FLiveLinkRefSkeleton RefSkeleton;
// Allow us to track changes to the ref skeleton
FGuid RefSkeletonGuid;
// Copy a frame from the buffer to a FLiveLinkSubjectFrame
void CopyFrameData(const FLiveLinkFrame& InFrame, FLiveLinkSubjectFrame& OutFrame);
struct FLiveLinkTimeSynchronizationData
{
// Whether or not synchronization has been established.
bool bHasEstablishedSync = false;
// The frame in our buffer where a rollover was detected. Only applicable for time synchronized sources.
int32 RolloverFrame = INDEX_NONE;
// Frame offset that will be used for this source.
int32 Offset = 0;
// Frame Time value modulus. When this value is not set, we assume no rollover occurs.
TOptional<FFrameTime> RolloverModulus;
// Frame rate used as the base for synchronization.
FFrameRate SyncFrameRate;
// Frame time that synchronization was established (relative to SynchronizationFrameRate).
FFrameTime SyncStartTime;
};
TOptional<FLiveLinkTimeSynchronizationData> TimeSyncData;
// Blend two frames from the buffer and copy the result to a FLiveLinkSubjectFrame
void CopyFrameDataBlended(const FLiveLinkFrame& PreFrame, const FLiveLinkFrame& PostFrame, float BlendWeight, FLiveLinkSubjectFrame& OutFrame);
};
// Structure that identifies an individual subject
@@ -149,6 +224,7 @@ public:
virtual const FLiveLinkSubjectFrame* GetSubjectData(FName SubjectName) override;
const FLiveLinkSubjectFrame* GetSubjectDataAtWorldTime(FName SubjectName, double WorldTime) override;
const FLiveLinkSubjectFrame* GetSubjectDataAtSceneTime(FName SubjectName, const FTimecode& SceneTime) override;
const TArray<FGuid>& GetSourceEntries() const { return SourceGuids; }
const TArray<FLiveLinkFrame>* GetSubjectRawFrames(FName SubjectName) override;
@@ -161,6 +237,10 @@ public:
// Get a list of currently active subjects
TArray<FLiveLinkSubjectKey> GetSubjects();
FLiveLinkSubjectTimeSyncData GetTimeSyncData(FName SubjectName);
FGuid GetCurrentSubjectOwner(FName SubjectName) const;
// Populates an array with in-use subject names
virtual void GetSubjectNames(TArray<FName>& SubjectNames) override;
@@ -196,8 +276,19 @@ public:
FDelegateHandle RegisterSubjectsChangedHandle(const FSimpleMulticastDelegate::FDelegate& SubjectsChanged);
void UnregisterSubjectsChangedHandle(FDelegateHandle Handle);
/** Called when time synchronization is starting for a subject. */
void OnStartSynchronization(FName SubjectName, const struct FTimeSynchronizationOpenData& OpenData, const int32 FrameOffset);
/** Called when time synchronization has been established for a subject. */
void OnSynchronizationEstablished(FName SubjectName, const struct FTimeSynchronizationStartData& StartData);
/** Called when time synchronization has been stopped for a subject. */
void OnStopSynchronization(FName SubjectName);
private:
void RemoveSource(int32 SourceIndex);
// Setup the source for virtual subjects
void AddVirtualSubjectSource();
@@ -48,6 +48,10 @@ public:
UFUNCTION(BlueprintCallable, Category = "LiveLink")
void GetSubjectDataAtWorldTime(const FName SubjectName, const float WorldTime, bool& bSuccess, FSubjectFrameHandle& SubjectFrameHandle);
// Returns a handle to the frame of data in LiveLink for a given subject at the specified time along with a boolean for whether a frame was found.
// Returns a handle to an empty frame if no frame of data is found.
UFUNCTION(BlueprintCallable, Category = "LiveLink")
void GetSubjectDataAtSceneTime(const FName SubjectName, const FTimecode& SceneTime, bool& bSuccess, FSubjectFrameHandle& SubjectFrameHandle);
private:
bool HasLiveLinkClient();
@@ -16,7 +16,7 @@ UMovieSceneComposurePostMoveSettingsTrack::UMovieSceneComposurePostMoveSettingsT
UMovieSceneSection* UMovieSceneComposurePostMoveSettingsTrack::CreateNewSection()
{
return NewObject<UMovieSceneSection>(this, UMovieSceneComposurePostMoveSettingsSection::StaticClass(), NAME_None, RF_Transactional);
return NewObject<UMovieSceneComposurePostMoveSettingsSection>(this, NAME_None, RF_Transactional);
}
@@ -21,12 +21,5 @@
"Type" : "Editor",
"LoadingPhase" : "Default"
}
],
"Plugins" :
[
{
"Name" : "PythonScriptPlugin",
"Enabled" : true
}
]
}
@@ -21,18 +21,14 @@ namespace UnrealBuildTool.Rules
"AssetTools",
"EditorStyle",
"MainFrame",
"MeshDescription",
"MeshDescriptionOperations",
"RawMesh",
"Slate",
"SlateCore",
"MeshDescription",
"UnrealEd",
}
);
PrivateIncludePathModuleNames.AddRange(
new string[] {
"PythonScriptPlugin",
}
);
}
}
}
@@ -12,6 +12,7 @@
#include "Editor/UnrealEdEngine.h"
#include "EngineUtils.h"
#include "Engine/Brush.h"
#include "Engine/MapBuildDataRegistry.h"
#include "Engine/Selection.h"
#include "Engine/StaticMesh.h"
#include "Engine/StaticMeshActor.h"
@@ -23,7 +24,8 @@
#include "Kismet2/ComponentEditorUtils.h"
#include "Layers/ILayers.h"
#include "LevelEditorViewport.h"
#include "Engine/MapBuildDataRegistry.h"
#include "Materials/Material.h"
#include "Materials/MaterialInterface.h"
#include "MeshMergeModule.h"
#include "ScopedTransaction.h"
#include "UnrealEdGlobals.h"
@@ -914,11 +916,6 @@ namespace InternalEditorLevelLibrary
ActorsToTest.RemoveAtSwap(Index);
}
}
if (ActorsToTest.Num() < 2)
{
OutFailureReason = TEXT("A merge operation requires at least 2 Actors.");
return false;
}
// All actors need to come from the same World
UWorld* CurrentWorld = ActorsToTest[0]->GetWorld();
@@ -983,12 +980,6 @@ namespace InternalEditorLevelLibrary
}
}
if (OutValidActor.Num() < 2)
{
OutFailureReason = TEXT("A merge operation requires at least 2 valid Actors.");
return false;
}
OutAverageLocation = PivotLocation / OutValidActor.Num();
return true;
@@ -1034,7 +1025,13 @@ AActor* UEditorLevelLibrary::JoinStaticMeshActors(const TArray<AStaticMeshActor*
FString FailureReason;
if (!InternalEditorLevelLibrary::FindValidActorAndComponents(ActorsToMerge, AllActors, AllComponents, PivotLocation, FailureReason))
{
UE_LOG(LogEditorScripting, Error, TEXT("JoinStaticMeshSctors failed. %s"), *FailureReason);
UE_LOG(LogEditorScripting, Error, TEXT("JoinStaticMeshActors failed. %s"), *FailureReason);
return nullptr;
}
if (AllActors.Num() < 2)
{
UE_LOG(LogEditorScripting, Error, TEXT("JoinStaticMeshActors failed. A merge operation requires at least 2 valid Actors."));
return nullptr;
}
@@ -1044,7 +1041,7 @@ AActor* UEditorLevelLibrary::JoinStaticMeshActors(const TArray<AStaticMeshActor*
AActor* NewActor = AllActors[0]->GetWorld()->SpawnActor<AActor>(PivotLocation, FRotator::ZeroRotator, Params);
if (!NewActor)
{
UE_LOG(LogEditorScripting, Error, TEXT("JoinStaticMeshSctors failed. Internal error while creating the join actor."));
UE_LOG(LogEditorScripting, Error, TEXT("JoinStaticMeshActors failed. Internal error while creating the join actor."));
return nullptr;
}
@@ -1129,7 +1126,7 @@ bool UEditorLevelLibrary::MergeStaticMeshActors(const TArray<AStaticMeshActor*>&
FVector MergedActorLocation;
TArray<UObject*> CreatedAssets;
const float ScreenAreaSize = TNumericLimits<float>::Max();
MeshUtilities.MergeComponentsToStaticMesh(AllComponents, AllActors[0]->GetWorld(), MergeOptions.MeshMergingSettings, nullptr, nullptr, MergeOptions.BasePackageName, CreatedAssets, MergedActorLocation, ScreenAreaSize, true);
MeshUtilities.MergeComponentsToStaticMesh(AllComponents, AllActors[0]->GetWorld(), MergeOptions.MeshMergingSettings, nullptr, nullptr, PackageName, CreatedAssets, MergedActorLocation, ScreenAreaSize, true);
UStaticMesh* MergedMesh = nullptr;
if (!CreatedAssets.FindItemByClass(&MergedMesh))
@@ -1184,4 +1181,103 @@ bool UEditorLevelLibrary::MergeStaticMeshActors(const TArray<AStaticMeshActor*>&
return true;
}
bool UEditorLevelLibrary::CreateProxyMeshActor(const TArray<class AStaticMeshActor*>& ActorsToMerge, const FEditorScriptingCreateProxyMeshActorOptions& MergeOptions, class AStaticMeshActor*& OutMergedActor)
{
// See FMeshProxyTool::RunMerge (Engine\Source\Editor\MergeActors\Private\MeshProxyTool\MeshProxyTool.cpp)
TGuardValue<bool> UnattendedScriptGuard(GIsRunningUnattendedScript, true);
OutMergedActor = nullptr;
if (!EditorScriptingUtils::CheckIfInEditorAndPIE())
{
return false;
}
// Cleanup actors
TArray<AStaticMeshActor*> StaticMeshActors;
TArray<UPrimitiveComponent*> AllComponents_UNUSED;
FVector PivotLocation;
FString FailureReason;
if (!InternalEditorLevelLibrary::FindValidActorAndComponents(ActorsToMerge, StaticMeshActors, AllComponents_UNUSED, PivotLocation, FailureReason))
{
UE_LOG(LogEditorScripting, Error, TEXT("MergeStaticMeshActors failed. %s"), *FailureReason);
return false;
}
TArray<AActor*> AllActors(StaticMeshActors);
const IMeshMergeUtilities& MeshUtilities = FModuleManager::Get().LoadModuleChecked<IMeshMergeModule>("MeshMergeUtilities").GetUtilities();
FCreateProxyDelegate ProxyDelegate;
TArray<UObject*> CreatedAssets;
ProxyDelegate.BindLambda([&CreatedAssets](const FGuid Guid, TArray<UObject*>& InAssetsToSync){CreatedAssets.Append(InAssetsToSync);});
MeshUtilities.CreateProxyMesh(
AllActors, // List of Actors to merge
MergeOptions.MeshProxySettings, // Merge settings
nullptr, // Base Material used for final proxy material. Note: nullptr for default impl: /Engine/EngineMaterials/BaseFlattenMaterial.BaseFlattenMaterial
nullptr, // Package for generated assets. Note: if nullptr, BasePackageName is used
MergeOptions.BasePackageName, // Will be used for naming generated assets, in case InOuter is not specified ProxyBasePackageName will be used as long package name for creating new packages
FGuid::NewGuid(), // Identify a job, First argument of the ProxyDelegate
ProxyDelegate // Called back on asset creation
);
UStaticMesh* MergedMesh = nullptr;
if (!CreatedAssets.FindItemByClass(&MergedMesh))
{
UE_LOG(LogEditorScripting, Error, TEXT("CreateProxyMeshActor failed. No mesh created."));
return false;
}
// Update the asset registry that a new static mesh and material has been created
FAssetRegistryModule& AssetRegistry = FModuleManager::Get().LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
for (UObject* Asset : CreatedAssets)
{
AssetRegistry.AssetCreated(Asset);
GEditor->BroadcastObjectReimported(Asset);
}
// Also notify the content browser that the new assets exists
FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>("ContentBrowser");
ContentBrowserModule.Get().SyncBrowserToAssets(CreatedAssets, true);
// Place new mesh in the world
UWorld* ActorWorld = AllActors[0]->GetWorld();
ULevel* ActorLevel = AllActors[0]->GetLevel();
if (MergeOptions.bSpawnMergedActor)
{
FActorSpawnParameters Params;
Params.OverrideLevel = ActorLevel;
OutMergedActor = ActorWorld->SpawnActor<AStaticMeshActor>(FVector::ZeroVector, FRotator::ZeroRotator, Params);
if (!OutMergedActor)
{
UE_LOG(LogEditorScripting, Error, TEXT("CreateProxyMeshActor failed. Internal error while creating the merged actor."));
return false;
}
OutMergedActor->GetStaticMeshComponent()->SetStaticMesh(MergedMesh);
OutMergedActor->SetActorLabel(MergeOptions.NewActorLabel);
ActorWorld->UpdateCullDistanceVolumes(OutMergedActor, OutMergedActor->GetStaticMeshComponent());
}
// Remove source actors
if (MergeOptions.bDestroySourceActors)
{
for (AActor* Actor : AllActors)
{
GEditor->Layers->DisassociateActorFromLayers(Actor);
ActorWorld->EditorDestroyActor(Actor, true);
}
}
//Select newly created actor
if (OutMergedActor)
{
GEditor->SelectNone(false, true, false);
GEditor->SelectActor(OutMergedActor, true, false); // don't notify but manually call NoteSelectionChange ?
GEditor->NoteSelectionChange();
}
return true;
}
#undef LOCTEXT_NAMESPACE
@@ -1,7 +1,6 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "EditorPythonExecuter.h"
#include "IPythonScriptPlugin.h"
#include "AssetRegistryModule.h"
#include "Editor.h"
@@ -164,7 +163,12 @@ namespace InternalEditorPythonRunner
if (!AssetRegistryModule.Get().IsLoadingAssets())
{
bIsRunning = true;
IPythonScriptPlugin::Get()->ExecPythonCommand(*FileName);
// Try and run the command
if (!GEngine->Exec(GWorld, *FString::Printf(TEXT("PY \"%s\""), *FileName), *GLog))
{
UE_LOG(LogEditorPythonExecuter, Error, TEXT("-ExecutePythonScript cannot be used without a valid Python Script Plugin. Ensure the plugin is enabled and wasn't compiled with Python support stubbed out."));
}
}
}
else
@@ -212,16 +216,8 @@ void FEditorPythonExecuter::OnStartupModule()
}
else
{
IPythonScriptPlugin* PythonScriptPlugin = IPythonScriptPlugin::Get();
if (PythonScriptPlugin && PythonScriptPlugin->IsPythonAvailable())
{
InternalEditorPythonRunner::Executer = new InternalEditorPythonRunner::FExecuterTickable(MoveTemp(FileValue));
InternalEditorPythonRunner::SExecutingDialog::OpenDialog();
}
else
{
UE_LOG(LogEditorPythonExecuter, Error, TEXT("-ExecutePythonScript cannot be used without a valid Python Script Plugin. Ensure the plugin is enabled and wasn't compiled with Python support stubbed out."));
}
InternalEditorPythonRunner::Executer = new InternalEditorPythonRunner::FExecuterTickable(MoveTemp(FileValue));
InternalEditorPythonRunner::SExecutingDialog::OpenDialog();
}
}
}
@@ -42,14 +42,15 @@ namespace EditorScriptingUtils
}
// Test for invalid characters
bool IsAValidPath(const FString& Path, FString& OutFailureReason)
bool IsAValidPath(const FString& Path, const TCHAR* InvalidChar, FString& OutFailureReason)
{
// Like !FName::IsValidGroupName(Path)), but with INVALID_OBJECTPATH_CHARACTERS and no conversion to from FName
const int32 StrLen = FCString::Strlen(INVALID_OBJECTPATH_CHARACTERS);
// Like !FName::IsValidGroupName(Path)), but with another list and no conversion to from FName
// InvalidChar may be INVALID_OBJECTPATH_CHARACTERS or INVALID_LONGPACKAGE_CHARACTERS or ...
const int32 StrLen = FCString::Strlen(InvalidChar);
for (int32 Index = 0; Index < StrLen; ++Index)
{
int32 FoundIndex = 0;
if (Path.FindChar(INVALID_OBJECTPATH_CHARACTERS[Index], FoundIndex))
if (Path.FindChar(InvalidChar[Index], FoundIndex))
{
OutFailureReason = FString::Printf(TEXT("Can't convert the path %s because it contains invalid characters."), *Path);
return false;
@@ -185,34 +186,35 @@ namespace EditorScriptingUtils
TextPath.ReplaceInline(TEXT("\\"), TEXT("/"), ESearchCase::CaseSensitive);
FPaths::RemoveDuplicateSlashes(TextPath);
// Test for invalid characters
if (!IsAValidPath(TextPath, OutFailureReason))
{
return FString();
}
// Get asset full name, i.e."PackageName.ObjectName:InnerAssetName.2ndInnerAssetName" from "/Game/Folder/PackageName.ObjectName:InnerAssetName.2ndInnerAssetName"
FString AssetFullName = FPackageName::GetShortName(TextPath);
// Remove possible ':' character from asset full name
FString AssetFullName;
{
int32 IndexOfSemiColumn;
if (AssetFullName.FindChar(TEXT(':'), IndexOfSemiColumn))
// Get everything after the last slash
int32 IndexOfLastSlash = INDEX_NONE;
TextPath.FindLastChar('/', IndexOfLastSlash);
FString Folders = TextPath.Left(IndexOfLastSlash);
// Test for invalid characters
if (!IsAValidPath(Folders, INVALID_LONGPACKAGE_CHARACTERS, OutFailureReason))
{
AssetFullName = AssetFullName.Left(IndexOfSemiColumn);
return FString();
}
AssetFullName = TextPath.Mid(IndexOfLastSlash + 1);
}
// Get the object name
FString ObjectName = FPackageName::ObjectPathToObjectName(AssetFullName);
FString ObjectName = FPackageName::ObjectPathToPackageName(AssetFullName);
if (ObjectName.IsEmpty())
{
ObjectName = FPackageName::ObjectPathToPackageName(AssetFullName);
if (ObjectName.IsEmpty())
{
OutFailureReason = FString::Printf(TEXT("Can't convert the path '%s' because it doesn't contain an asset name."), *AnyAssetPath);
return FString();
}
OutFailureReason = FString::Printf(TEXT("Can't convert the path '%s' because it doesn't contain an asset name."), *AnyAssetPath);
return FString();
}
// Test for invalid characters
if (!IsAValidPath(ObjectName, INVALID_OBJECTNAME_CHARACTERS, OutFailureReason))
{
return FString();
}
// Confirm that we have a valid Root Package and get the valid PackagePath /Game/MyFolder/MyAsset
@@ -234,7 +236,7 @@ namespace EditorScriptingUtils
return FString();
}
FString ObjectPath = FString::Printf(TEXT("%s.%s"), *PackagePath, *ObjectName);
FString ObjectPath = FString::Printf(TEXT("%s.%s"), *PackagePath, *ObjectName); // #todo-ueent should be asset name, not object name (as ObjectName == PackageName)
if (FPackageName::IsScriptPackage(ObjectPath))
{
@@ -281,13 +283,6 @@ namespace EditorScriptingUtils
TextPath.ReplaceInline(TEXT("\\"), TEXT("/"), ESearchCase::CaseSensitive);
FPaths::RemoveDuplicateSlashes(TextPath);
// Test for invalid characters
if (!IsAValidPath(TextPath, OutFailureReason))
{
return FString();
}
//ObjectName = FPackageName::ObjectPathToObjectName(ObjectName);
{
// Remove .
int32 ObjectDelimiterIdx;
@@ -303,6 +298,12 @@ namespace EditorScriptingUtils
}
}
// Test for invalid characters
if (!IsAValidPath(TextPath, INVALID_LONGPACKAGE_CHARACTERS, OutFailureReason))
{
return FString();
}
// Confirm that we have a valid Root Package and get the valid PackagePath /Game/MyFolder
FString PackagePath;
if (!FPackageName::TryConvertFilenameToLongPackageName(TextPath, PackagePath, &OutFailureReason))
@@ -26,7 +26,7 @@ namespace EditorScriptingUtils
/*
* Check if the Path is a valid ContentBrowser Path
*/
bool IsAValidPath(const FString& Path, FString& OutFailureReason);
bool IsAValidPath(const FString& Path, const TCHAR* InvalidChar, FString& OutFailureReason);
/*
* Check if the AssetPath can be used to create a new asset
@@ -24,16 +24,18 @@
#include "Layers/ILayers.h"
#include "LevelEditorViewport.h"
#include "Engine/MapBuildDataRegistry.h"
#include "MeshAttributes.h"
#include "MeshAttributeArray.h"
#include "MeshDescription.h"
#include "MeshDescriptionOperations.h"
#include "MeshMergeModule.h"
#include "PhysicsEngine/BodySetup.h"
#include "RawMesh.h"
#include "ScopedTransaction.h"
#include "Toolkits/AssetEditorManager.h"
#include "UnrealEdGlobals.h"
#include "UnrealEd/Private/GeomFitUtils.h"
#include "UnrealEd/Private/ConvexDecompTool.h"
#include "MeshDescription.h"
#include "MeshAttributes.h"
#include "MeshAttributeArray.h"
#define LOCTEXT_NAMESPACE "EditorStaticMeshLibrary"
@@ -114,6 +116,37 @@ namespace InternalEditorMeshLibrary
return true;
}
bool IsUVChannelValid(UStaticMesh* StaticMesh, int32 LODIndex, int32 UVChannelIndex)
{
if (StaticMesh == nullptr)
{
UE_LOG(LogEditorScripting, Error, TEXT("The StaticMesh is null."));
return false;
}
if (LODIndex >= StaticMesh->GetNumLODs() || LODIndex < 0)
{
UE_LOG(LogEditorScripting, Error, TEXT("The StaticMesh doesn't have LOD %d."), LODIndex);
return false;
}
FMeshDescription* MeshDescription = StaticMesh->GetOriginalMeshDescription(LODIndex);
if (!MeshDescription)
{
UE_LOG(LogEditorScripting, Error, TEXT("No mesh description for LOD %d."), LODIndex);
return false;
}
int32 NumUVChannels = StaticMesh->GetNumUVChannels(LODIndex);
if (UVChannelIndex < 0 || UVChannelIndex >= NumUVChannels)
{
UE_LOG(LogEditorScripting, Error, TEXT("The given UV channel index %d is out of bounds."), UVChannelIndex);
return false;
}
return true;
}
}
int32 UEditorStaticMeshLibrary::SetLods(UStaticMesh* StaticMesh, const FEditorScriptingMeshReductionOptions& ReductionOptions)
@@ -196,6 +229,68 @@ int32 UEditorStaticMeshLibrary::SetLods(UStaticMesh* StaticMesh, const FEditorSc
return LODIndex;
}
int32 UEditorStaticMeshLibrary::SetLodFromStaticMesh(UStaticMesh* DestinationStaticMesh, int32 DestinationLodIndex, UStaticMesh* SourceStaticMesh, int32 SourceLodIndex)
{
TGuardValue<bool> UnattendedScriptGuard( GIsRunningUnattendedScript, true );
if ( !EditorScriptingUtils::CheckIfInEditorAndPIE( ))
{
return -1;
}
if ( DestinationStaticMesh == nullptr )
{
UE_LOG(LogEditorScripting, Error, TEXT("SetLodFromStaticMesh: The DestinationStaticMesh is null."));
return -1;
}
if ( SourceStaticMesh == nullptr )
{
UE_LOG(LogEditorScripting, Error, TEXT("SetLodFromStaticMesh: The SourceStaticMesh is null."));
return -1;
}
if ( !SourceStaticMesh->SourceModels.IsValidIndex( SourceLodIndex ) )
{
UE_LOG(LogEditorScripting, Error, TEXT("SetLodFromStaticMesh: SourceLodIndex is invalid."));
return -1;
}
// Close the mesh editor to prevent crashing. Reopen it after the mesh has been built.
FAssetEditorManager& AssetEditorManager = FAssetEditorManager::Get();
bool bStaticMeshIsEdited = false;
if ( AssetEditorManager.FindEditorForAsset( DestinationStaticMesh, false ) )
{
AssetEditorManager.CloseAllEditorsForAsset( DestinationStaticMesh );
bStaticMeshIsEdited = true;
}
DestinationStaticMesh->Modify();
if ( DestinationStaticMesh->SourceModels.Num() < DestinationLodIndex + 1 )
{
// Add one LOD
DestinationStaticMesh->AddSourceModel();
DestinationLodIndex = DestinationStaticMesh->SourceModels.Num() - 1;
}
FRawMesh SourceRawMesh;
SourceStaticMesh->SourceModels[ SourceLodIndex ].LoadRawMesh( SourceRawMesh );
DestinationStaticMesh->SourceModels[ DestinationLodIndex ].SaveRawMesh( SourceRawMesh );
DestinationStaticMesh->PostEditChange();
// Reopen MeshEditor on this mesh if the MeshEditor was previously opened in it
if ( bStaticMeshIsEdited )
{
AssetEditorManager.OpenEditorForAsset( DestinationStaticMesh );
}
return DestinationLodIndex;
}
int32 UEditorStaticMeshLibrary::GetLodCount(UStaticMesh* StaticMesh)
{
TGuardValue<bool> UnattendedScriptGuard(GIsRunningUnattendedScript, true);
@@ -935,5 +1030,70 @@ bool UEditorStaticMeshLibrary::RemoveUVChannel(UStaticMesh* StaticMesh, int32 LO
return StaticMesh->RemoveUVChannel(LODIndex, UVChannelIndex);
}
#undef LOCTEXT_NAMESPACE
bool UEditorStaticMeshLibrary::GeneratePlanarUVChannel(UStaticMesh* StaticMesh, int32 LODIndex, int32 UVChannelIndex, const FUVMapSettings& UVSettings)
{
TGuardValue<bool> UnattendedScriptGuard(GIsRunningUnattendedScript, true);
if (!EditorScriptingUtils::CheckIfInEditorAndPIE())
{
return false;
}
if (!InternalEditorMeshLibrary::IsUVChannelValid(StaticMesh, LODIndex, UVChannelIndex))
{
return false;
}
FMeshDescription* MeshDescription = StaticMesh->GetOriginalMeshDescription(LODIndex);
TArray<FVector2D> TexCoords;
FMeshDescriptionOperations::GeneratePlanarUV(*MeshDescription, UVSettings, TexCoords);
return StaticMesh->SetUVChannel(LODIndex, UVChannelIndex, TexCoords);
}
bool UEditorStaticMeshLibrary::GenerateCylindricalUVChannel(UStaticMesh* StaticMesh, int32 LODIndex, int32 UVChannelIndex, const FUVMapSettings& UVSettings)
{
TGuardValue<bool> UnattendedScriptGuard(GIsRunningUnattendedScript, true);
if (!EditorScriptingUtils::CheckIfInEditorAndPIE())
{
return false;
}
if (!InternalEditorMeshLibrary::IsUVChannelValid(StaticMesh, LODIndex, UVChannelIndex))
{
return false;
}
FMeshDescription* MeshDescription = StaticMesh->GetOriginalMeshDescription(LODIndex);
TArray<FVector2D> TexCoords;
FMeshDescriptionOperations::GenerateCylindricalUV(*MeshDescription, UVSettings, TexCoords);
return StaticMesh->SetUVChannel(LODIndex, UVChannelIndex, TexCoords);
}
bool UEditorStaticMeshLibrary::GenerateBoxUVChannel(UStaticMesh* StaticMesh, int32 LODIndex, int32 UVChannelIndex, const FUVMapSettings& UVSettings)
{
TGuardValue<bool> UnattendedScriptGuard(GIsRunningUnattendedScript, true);
if (!EditorScriptingUtils::CheckIfInEditorAndPIE())
{
return false;
}
if (!InternalEditorMeshLibrary::IsUVChannelValid(StaticMesh, LODIndex, UVChannelIndex))
{
return false;
}
FMeshDescription* MeshDescription = StaticMesh->GetOriginalMeshDescription(LODIndex);
TArray<FVector2D> TexCoords;
FMeshDescriptionOperations::GenerateBoxUV(*MeshDescription, UVSettings, TexCoords);
return StaticMesh->SetUVChannel(LODIndex, UVChannelIndex, TexCoords);
}
#undef LOCTEXT_NAMESPACE
@@ -12,7 +12,7 @@
USTRUCT(BlueprintType)
struct FEditorScriptingJoinStaticMeshActorsOptions
{
GENERATED_USTRUCT_BODY()
GENERATED_BODY()
FEditorScriptingJoinStaticMeshActorsOptions()
: bDestroySourceActors(true)
@@ -35,7 +35,7 @@ struct FEditorScriptingJoinStaticMeshActorsOptions
USTRUCT(BlueprintType)
struct FEditorScriptingMergeStaticMeshActorsOptions : public FEditorScriptingJoinStaticMeshActorsOptions
{
GENERATED_USTRUCT_BODY()
GENERATED_BODY()
FEditorScriptingMergeStaticMeshActorsOptions()
: bSpawnMergedActor(true)
@@ -53,6 +53,27 @@ struct FEditorScriptingMergeStaticMeshActorsOptions : public FEditorScriptingJoi
FMeshMergingSettings MeshMergingSettings;
};
USTRUCT(BlueprintType)
struct FEditorScriptingCreateProxyMeshActorOptions : public FEditorScriptingJoinStaticMeshActorsOptions
{
GENERATED_BODY()
FEditorScriptingCreateProxyMeshActorOptions()
: bSpawnMergedActor(true)
{ }
// Spawn the new merged actors
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Options)
bool bSpawnMergedActor;
// The package path you want to save to. ie: /Game/MyFolder
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Options)
FString BasePackageName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Options)
FMeshProxySettings MeshProxySettings;
};
/**
* Utility class to do most of the common functionalities in the World Editor.
* The editor should not be in play in editor mode.
@@ -243,12 +264,22 @@ public:
* Merge the meshes into a unique mesh with the provided StaticMeshActors. There are multiple options on how to merge the meshes and their materials.
* The ActorsToMerge need to be in the same Level.
* This may have a high impact on performance depending of the MeshMergingSettings options.
* @param ActorsToMerge List of Actors to join.
* @param MergeOptions Options on how to join the actors.
* @param ActorsToMerge List of Actors to merge.
* @param MergeOptions Options on how to merge the actors.
* @param OutMergedActor The new created actor, if requested.
* @return if the operation is successful.
*/
UFUNCTION(BlueprintCallable, Category = "Editor Scripting | DataPrep")
static bool MergeStaticMeshActors(const TArray<class AStaticMeshActor*>& ActorsToMerge, const FEditorScriptingMergeStaticMeshActorsOptions& MergeOptions, class AStaticMeshActor*& OutMergedActor);
/**
* Build a proxy mesh actor that can replace a set of mesh actors.
* @param ActorsToMerge List of actors to build a proxy for.
* @param MergeOptions
* @param OutMergedActor generated actor if requested
* @return Success of the proxy creation
*/
UFUNCTION(BlueprintCallable, Category = "Editor Scripting | DataPrep")
static bool CreateProxyMeshActor(const TArray<class AStaticMeshActor*>& ActorsToMerge, const FEditorScriptingCreateProxyMeshActorOptions& MergeOptions, class AStaticMeshActor*& OutMergedActor);
};
@@ -9,6 +9,7 @@
#include "Engine/MeshMerging.h"
#include "GameFramework/Actor.h"
#include "PhysicsEngine/BodySetupEnums.h"
#include "UVMapSettings.h"
#include "EditorStaticMeshLibrary.generated.h"
@@ -90,6 +91,18 @@ public:
UFUNCTION(BlueprintCallable, Category = "Editor Scripting | StaticMesh")
static int32 SetLods(UStaticMesh* StaticMesh, const FEditorScriptingMeshReductionOptions& ReductionOptions);
/**
* Adds or create a LOD at DestinationLodIndex using the geometry from SourceStaticMesh SourceLodIndex
* @param DestinationStaticMesh The static mesh to set the LOD in.
* @param DestinationLodIndex The index of the LOD to set.
* @param SourceStaticMesh The static mesh to get the LOD from.
* @param SourceLodIndex The index of the LOD to get.
* @return The index of the LOD that was set. It can be different than DestinationLodIndex if it wasn't a valid index.
* A negative value indicates that the LOD was not set. See log for explanation.
*/
UFUNCTION(BlueprintCallable, Category = "Editor Scripting | StaticMesh")
static int32 SetLodFromStaticMesh(UStaticMesh* DestinationStaticMesh, int32 DestinationLodIndex, UStaticMesh* SourceStaticMesh, int32 SourceLodIndex);
/**
* Get number of LODs present on a static mesh.
* @param StaticMesh Mesh to process.
@@ -266,5 +279,37 @@ public:
*/
UFUNCTION(BlueprintCallable, Category = "Editor Scripting | StaticMesh")
static bool RemoveUVChannel(UStaticMesh* StaticMesh, int32 LODIndex, int32 UVChannelIndex);
};
/**
* Generates planar UV mapping in the specified UV channel on the given LOD of a StaticMesh.
* @param StaticMesh Static mesh on which to generate the UV mapping.
* @param LODIndex Index of the StaticMesh LOD.
* @param UVChannelIndex Channel where to save the UV mapping.
* @param UVSettings The settings to use to generate the UV mapping.
* @return true if the UV mapping was generated.
*/
UFUNCTION(BlueprintCallable, Category = "Editor Scripting | StaticMesh")
static bool GeneratePlanarUVChannel(UStaticMesh* StaticMesh, int32 LODIndex, int32 UVChannelIndex, const FUVMapSettings& UVSettings);
/**
* Generates cylindrical UV mapping in the specified UV channel on the given LOD of a StaticMesh.
* @param StaticMesh Static mesh on which to generate the UV mapping.
* @param LODIndex Index of the StaticMesh LOD.
* @param UVChannelIndex Channel where to save the UV mapping.
* @param UVSettings The settings to use to generate the UV mapping.
* @return true if the UV mapping was generated.
*/
UFUNCTION(BlueprintCallable, Category = "Editor Scripting | StaticMesh")
static bool GenerateCylindricalUVChannel(UStaticMesh* StaticMesh, int32 LODIndex, int32 UVChannelIndex, const FUVMapSettings& UVSettings);
/**
* Generates box UV mapping in the specified UV channel on the given LOD of a StaticMesh.
* @param StaticMesh Static mesh on which to generate the UV mapping.
* @param LODIndex Index of the StaticMesh LOD.
* @param UVChannelIndex Channel where to save the UV mapping.
* @param UVSettings The settings to use to generate the UV mapping.
* @return true if the UV mapping was generated.
*/
UFUNCTION(BlueprintCallable, Category = "Editor Scripting | StaticMesh")
static bool GenerateBoxUVChannel(UStaticMesh* StaticMesh, int32 LODIndex, int32 UVChannelIndex, const FUVMapSettings& UVSettings);
};
@@ -16,6 +16,13 @@ namespace UnrealBuildTool.Rules
"Engine"
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"Landscape"
}
);
}
}
}
@@ -0,0 +1,54 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "ObjectTemplates/DatasmithLandscapeTemplate.h"
#include "Landscape.h"
void UDatasmithLandscapeTemplate::Apply( UObject* Destination, bool bForce )
{
#if WITH_EDITORONLY_DATA
ALandscape* Landscape = Cast< ALandscape >( Destination );
if( !Landscape )
{
return;
}
UDatasmithLandscapeTemplate* PreviousTemplate = !bForce ? FDatasmithObjectTemplateUtils::GetObjectTemplate< UDatasmithLandscapeTemplate >( Destination ) : nullptr;
DATASMITHOBJECTTEMPLATE_CONDITIONALSET(LandscapeMaterial, Landscape, PreviousTemplate);
DATASMITHOBJECTTEMPLATE_CONDITIONALSET(StaticLightingLOD, Landscape, PreviousTemplate);
FDatasmithObjectTemplateUtils::SetObjectTemplate( Landscape->GetRootComponent(), this );
#endif // #if WITH_EDITORONLY_DATA
}
void UDatasmithLandscapeTemplate::Load( const UObject* Source )
{
#if WITH_EDITORONLY_DATA
const ALandscape* Landscape = Cast< ALandscape >( Source );
if( !Landscape )
{
return;
}
LandscapeMaterial = Landscape->LandscapeMaterial;
StaticLightingLOD = Landscape->StaticLightingLOD;
#endif // #if WITH_EDITORONLY_DATA
}
bool UDatasmithLandscapeTemplate::Equals( const UDatasmithObjectTemplate* Other ) const
{
const UDatasmithLandscapeTemplate* TypedOther = Cast< UDatasmithLandscapeTemplate >( Other );
if ( !TypedOther )
{
return false;
}
bool bEquals = ( LandscapeMaterial == TypedOther->LandscapeMaterial );
bEquals = bEquals && ( StaticLightingLOD == TypedOther->StaticLightingLOD );
return bEquals;
}

Some files were not shown because too many files have changed in this diff Show More