504 lines
18 KiB
C++
504 lines
18 KiB
C++
/*
|
|
* Copyright (c) <2017> Side Effects Software Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
#include "HoudiniRuntimeSettings.h"
|
|
|
|
#include "HoudiniApi.h"
|
|
#include "HoudiniEngineRuntimePrivatePCH.h"
|
|
#include "HoudiniEngineUtils.h"
|
|
|
|
#include "Internationalization/Internationalization.h"
|
|
#define LOCTEXT_NAMESPACE HOUDINI_LOCTEXT_NAMESPACE
|
|
|
|
UHoudiniRuntimeSettings::UHoudiniRuntimeSettings( const FObjectInitializer & ObjectInitializer )
|
|
: Super( ObjectInitializer )
|
|
{
|
|
/** Session options. **/
|
|
SessionType = HRSST_NamedPipe;
|
|
ServerHost = HAPI_UNREAL_SESSION_SERVER_HOST;
|
|
ServerPort = HAPI_UNREAL_SESSION_SERVER_PORT;
|
|
ServerPipeName = HAPI_UNREAL_SESSION_SERVER_PIPENAME;
|
|
bStartAutomaticServer = HAPI_UNREAL_SESSION_SERVER_AUTOSTART;
|
|
AutomaticServerTimeout = HAPI_UNREAL_SESSION_SERVER_TIMEOUT;
|
|
|
|
#if PLATFORM_LINUX
|
|
// Since 4.17, Linux has library conflict, so we need to create an out-of-process session by default
|
|
// We default to a named pipe, but TCP Sockets should work fine too.
|
|
SessionType = HRSST_Socket;
|
|
bStartAutomaticServer = true;
|
|
#endif
|
|
|
|
/** Instantiation options. **/
|
|
bShowMultiAssetDialog = true;
|
|
|
|
/** Cooking options. **/
|
|
bPauseCookingOnStart = false;
|
|
bEnableCooking = true;
|
|
bUploadTransformsToHoudiniEngine = true;
|
|
bTransformChangeTriggersCooks = false;
|
|
bDisplaySlateCookingNotifications = true;
|
|
bCookCurvesOnMouseRelease = false;
|
|
|
|
TemporaryCookFolder = LOCTEXT("Temp", "/Game/HoudiniEngine/Temp");
|
|
|
|
/** Parameter options. **/
|
|
bTreatRampParametersAsMultiparms = false;
|
|
|
|
/** Collision generation. **/
|
|
CollisionGroupNamePrefix = TEXT( HAPI_UNREAL_GROUP_GEOMETRY_COLLISION );
|
|
RenderedCollisionGroupNamePrefix = TEXT(HAPI_UNREAL_GROUP_GEOMETRY_RENDERED_COLLISION );
|
|
UCXCollisionGroupNamePrefix = TEXT( HAPI_UNREAL_GROUP_GEOMETRY_COLLISION_UCX );
|
|
UCXRenderedCollisionGroupNamePrefix = TEXT( HAPI_UNREAL_GROUP_GEOMETRY_RENDERED_COLLISION_UCX );
|
|
SimpleCollisionGroupNamePrefix = TEXT( HAPI_UNREAL_GROUP_GEOMETRY_SIMPLE_COLLISION );
|
|
SimpleRenderedCollisionGroupNamePrefix = TEXT( HAPI_UNREAL_GROUP_GEOMETRY_SIMPLE_RENDERED_COLLISION );
|
|
|
|
/** Geometry marshalling. **/
|
|
MarshallingAttributeMaterial = TEXT( HAPI_UNREAL_ATTRIB_MATERIAL );
|
|
MarshallingAttributeMaterialHole = TEXT( HAPI_UNREAL_ATTRIB_MATERIAL_HOLE );
|
|
MarshallingAttributeInstanceOverride = TEXT( HAPI_UNREAL_ATTRIB_INSTANCE_OVERRIDE );
|
|
MarshallingAttributeFaceSmoothingMask = TEXT( HAPI_UNREAL_ATTRIB_FACE_SMOOTHING_MASK );
|
|
MarshallingAttributeLightmapResolution = TEXT( HAPI_UNREAL_ATTRIB_LIGHTMAP_RESOLUTION );
|
|
MarshallingAttributeGeneratedMeshName = TEXT( HAPI_UNREAL_ATTRIB_GENERATED_MESH_NAME );
|
|
MarshallingAttributeInputMeshName = TEXT( HAPI_UNREAL_ATTRIB_INPUT_MESH_NAME );
|
|
MarshallingAttributeInputSourceFile = TEXT( HAPI_UNREAL_ATTRIB_INPUT_SOURCE_FILE );
|
|
MarshallingSplineResolution = HAPI_UNREAL_PARAM_SPLINE_RESOLUTION_DEFAULT;
|
|
MarshallingLandscapesUseDefaultUnrealScaling = false;
|
|
MarshallingLandscapesUseFullResolution = true;
|
|
MarshallingLandscapesForceMinMaxValues = false;
|
|
MarshallingLandscapesForcedMinValue = -2000.0f;
|
|
MarshallingLandscapesForcedMaxValue = 4553.0f;
|
|
|
|
/** Geometry scaling. **/
|
|
GeneratedGeometryScaleFactor = HAPI_UNREAL_SCALE_FACTOR_POSITION;
|
|
TransformScaleFactor = HAPI_UNREAL_SCALE_FACTOR_TRANSLATION;
|
|
ImportAxis = HRSAI_Unreal;
|
|
|
|
/** Generated StaticMesh settings. **/
|
|
bDoubleSidedGeometry = false;
|
|
PhysMaterial = nullptr;
|
|
DefaultBodyInstance.SetCollisionProfileName("BlockAll");
|
|
CollisionTraceFlag = CTF_UseDefault;
|
|
LightMapResolution = 32;
|
|
LpvBiasMultiplier = 1.0f;
|
|
LightMapCoordinateIndex = 1;
|
|
bUseMaximumStreamingTexelRatio = false;
|
|
StreamingDistanceMultiplier = 1.0f;
|
|
GeneratedDistanceFieldResolutionScale = 0.0f;
|
|
|
|
/** Static Mesh build settings. **/
|
|
bUseFullPrecisionUVs = false;
|
|
SrcLightmapIndex = 0;
|
|
DstLightmapIndex = 1;
|
|
MinLightmapResolution = 64;
|
|
bRemoveDegenerates = true;
|
|
GenerateLightmapUVsFlag = HRSRF_OnlyIfMissing;
|
|
RecomputeNormalsFlag = HRSRF_OnlyIfMissing;
|
|
RecomputeTangentsFlag = HRSRF_OnlyIfMissing;
|
|
bUseMikkTSpace = true;
|
|
bBuildAdjacencyBuffer = false;
|
|
|
|
/** Custom Houdini location. **/
|
|
bUseCustomHoudiniLocation = false;
|
|
CustomHoudiniLocation.Path = TEXT( "" );
|
|
|
|
// Placement Mode Tools
|
|
bHidePlacementModeHoudiniTools = false;
|
|
|
|
/** Arguments for HAPI_Initialize */
|
|
CookingThreadStackSize = -1;
|
|
}
|
|
|
|
UHoudiniRuntimeSettings::~UHoudiniRuntimeSettings()
|
|
{}
|
|
|
|
FProperty *
|
|
UHoudiniRuntimeSettings::LocateProperty( const FString & PropertyName ) const
|
|
{
|
|
for ( TFieldIterator< FProperty > PropIt( GetClass() ); PropIt; ++PropIt )
|
|
{
|
|
FProperty * Property = *PropIt;
|
|
|
|
if ( Property->GetNameCPP() == PropertyName )
|
|
return Property;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void
|
|
UHoudiniRuntimeSettings::SetPropertyReadOnly( const FString & PropertyName, bool bReadOnly )
|
|
{
|
|
FProperty * Property = LocateProperty( PropertyName );
|
|
if ( Property )
|
|
{
|
|
if ( bReadOnly )
|
|
Property->SetPropertyFlags( CPF_EditConst );
|
|
else
|
|
Property->ClearPropertyFlags( CPF_EditConst );
|
|
}
|
|
}
|
|
|
|
void
|
|
UHoudiniRuntimeSettings::PostInitProperties()
|
|
{
|
|
Super::PostInitProperties();
|
|
|
|
// Set Collision generation options as read only
|
|
{
|
|
if ( FProperty* Property = LocateProperty( TEXT( "CollisionGroupNamePrefix" ) ) )
|
|
Property->SetPropertyFlags( CPF_EditConst );
|
|
|
|
if ( FProperty* Property = LocateProperty( TEXT( "RenderedCollisionGroupNamePrefix" ) ) )
|
|
Property->SetPropertyFlags( CPF_EditConst );
|
|
|
|
if ( FProperty* Property = LocateProperty(TEXT("UCXCollisionGroupNamePrefix" ) ) )
|
|
Property->SetPropertyFlags(CPF_EditConst);
|
|
|
|
if ( FProperty* Property = LocateProperty(TEXT("UCXRenderedCollisionGroupNamePrefix" ) ) )
|
|
Property->SetPropertyFlags(CPF_EditConst);
|
|
|
|
if ( FProperty* Property = LocateProperty(TEXT("SimpleCollisionGroupNamePrefix" ) ) )
|
|
Property->SetPropertyFlags(CPF_EditConst);
|
|
|
|
if ( FProperty* Property = LocateProperty(TEXT("SimpleRenderedCollisionGroupNamePrefix" ) ) )
|
|
Property->SetPropertyFlags(CPF_EditConst);
|
|
}
|
|
|
|
// Set marshalling attributes options as read only
|
|
{
|
|
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeMaterial")))
|
|
Property->SetPropertyFlags(CPF_EditConst);
|
|
|
|
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeMaterialHole")))
|
|
Property->SetPropertyFlags(CPF_EditConst);
|
|
|
|
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeInstanceOverride")))
|
|
Property->SetPropertyFlags(CPF_EditConst);
|
|
|
|
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeFaceSmoothingMask")))
|
|
Property->SetPropertyFlags(CPF_EditConst);
|
|
|
|
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeLightmapResolution")))
|
|
Property->SetPropertyFlags(CPF_EditConst);
|
|
|
|
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeGeneratedMeshName")))
|
|
Property->SetPropertyFlags(CPF_EditConst);
|
|
|
|
if (FProperty* Property = LocateProperty(TEXT("MarshallingAttributeInputMeshName")))
|
|
Property->SetPropertyFlags(CPF_EditConst);
|
|
}
|
|
|
|
/*
|
|
// Set Cook Folder as read-only
|
|
{
|
|
if ( FProperty* Property = LocateProperty( TEXT( "TemporaryCookFolder" ) ) )
|
|
Property->SetPropertyFlags( CPF_EditConst );
|
|
}
|
|
*/
|
|
|
|
// Set Landscape forced min/max as read only when not overriden
|
|
if ( !MarshallingLandscapesForceMinMaxValues )
|
|
{
|
|
if ( FProperty* Property = LocateProperty( TEXT( "MarshallingLandscapesForcedMinValue" ) ) )
|
|
Property->SetPropertyFlags( CPF_EditConst );
|
|
if ( FProperty* Property = LocateProperty( TEXT( "MarshallingLandscapesForcedMaxValue" ) ) )
|
|
Property->SetPropertyFlags( CPF_EditConst );
|
|
}
|
|
|
|
// Disable UI elements depending on current session type.
|
|
#if WITH_EDITOR
|
|
|
|
UpdateSessionUi();
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
SetPropertyReadOnly( TEXT( "CustomHoudiniLocation" ), !bUseCustomHoudiniLocation );
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
|
|
void
|
|
UHoudiniRuntimeSettings::PostEditChangeProperty( struct FPropertyChangedEvent & PropertyChangedEvent )
|
|
{
|
|
Super::PostEditChangeProperty( PropertyChangedEvent );
|
|
|
|
FProperty * Property = PropertyChangedEvent.MemberProperty;
|
|
FProperty * LookupProperty = nullptr;
|
|
|
|
if ( !Property )
|
|
return;
|
|
|
|
if ( Property->GetName() == TEXT( "GeneratedGeometryScaleFactor" ) )
|
|
GeneratedGeometryScaleFactor = FMath::Clamp( GeneratedGeometryScaleFactor, KINDA_SMALL_NUMBER, 10000.0f );
|
|
else if ( Property->GetName() == TEXT( "TransformScaleFactor" ) )
|
|
GeneratedGeometryScaleFactor = FMath::Clamp( GeneratedGeometryScaleFactor, KINDA_SMALL_NUMBER, 10000.0f );
|
|
else if ( Property->GetName() == TEXT( "SessionType" ) )
|
|
UpdateSessionUi();
|
|
else if ( Property->GetName() == TEXT( "bUseCustomHoudiniLocation" ) )
|
|
SetPropertyReadOnly( TEXT( "CustomHoudiniLocation" ), !bUseCustomHoudiniLocation );
|
|
else if ( Property->GetName() == TEXT( "CustomHoudiniLocation" ) )
|
|
{
|
|
FString LibHAPIName = FHoudiniEngineUtils::HoudiniGetLibHAPIName();
|
|
FString & CustomHoudiniLocationPath = CustomHoudiniLocation.Path;
|
|
FString LibHAPICustomPath = FString::Printf( TEXT( "%s/%s" ), *CustomHoudiniLocationPath, *LibHAPIName );
|
|
|
|
// If path does not point to libHAPI location, we need to let user know.
|
|
if ( !FPaths::FileExists( LibHAPICustomPath ) )
|
|
{
|
|
FString MessageString = FString::Printf(
|
|
TEXT( "%s was not found in %s" ), *LibHAPIName, *CustomHoudiniLocationPath );
|
|
|
|
FPlatformMisc::MessageBoxExt(
|
|
EAppMsgType::Ok, *MessageString,
|
|
TEXT( "Invalid Custom Location Specified, resetting." ) );
|
|
|
|
CustomHoudiniLocationPath = TEXT( "" );
|
|
}
|
|
}
|
|
else if (Property->GetName() == TEXT("MarshallingSplineResolution"))
|
|
MarshallingSplineResolution = FMath::Clamp(MarshallingSplineResolution, 0.0f, 10000.0f);
|
|
|
|
if ( Property->GetName() == TEXT( "MarshallingLandscapesForceMinMaxValues" ) )
|
|
{
|
|
// Set Landscape forced min/max as read only when not overriden
|
|
if ( !MarshallingLandscapesForceMinMaxValues )
|
|
{
|
|
if ( FProperty* MinProperty = LocateProperty( TEXT( "MarshallingLandscapesForcedMinValue") ) )
|
|
MinProperty->SetPropertyFlags( CPF_EditConst );
|
|
if ( FProperty* MaxProperty = LocateProperty( TEXT( "MarshallingLandscapesForcedMaxValue" ) ) )
|
|
MaxProperty->SetPropertyFlags( CPF_EditConst );
|
|
}
|
|
else
|
|
{
|
|
if ( FProperty* MinProperty = LocateProperty( TEXT( "MarshallingLandscapesForcedMinValue") ) )
|
|
MinProperty->ClearPropertyFlags( CPF_EditConst );
|
|
if ( FProperty* MaxProperty = LocateProperty( TEXT( "MarshallingLandscapesForcedMaxValue" ) ) )
|
|
MaxProperty->ClearPropertyFlags( CPF_EditConst );
|
|
}
|
|
}
|
|
|
|
/*
|
|
if ( Property->GetName() == TEXT( "bEnableCooking" ) )
|
|
{
|
|
// Cooking is disabled, we need to disable transform change triggers cooks option is as well.
|
|
if ( bEnableCooking )
|
|
{
|
|
LookupProperty = LocateProperty( TEXT( "bUploadTransformsToHoudiniEngine" ) );
|
|
if ( LookupProperty )
|
|
LookupProperty->ClearPropertyFlags( CPF_EditConst );
|
|
|
|
LookupProperty = LocateProperty( TEXT( "bTransformChangeTriggersCooks" ) );
|
|
if ( LookupProperty )
|
|
LookupProperty->ClearPropertyFlags( CPF_EditConst );
|
|
}
|
|
else
|
|
{
|
|
LookupProperty = LocateProperty( TEXT( "bUploadTransformsToHoudiniEngine" ) );
|
|
if ( LookupProperty )
|
|
LookupProperty->SetPropertyFlags( CPF_EditConst );
|
|
|
|
LookupProperty = LocateProperty( TEXT( "bTransformChangeTriggersCooks" ) );
|
|
if ( LookupProperty )
|
|
LookupProperty->SetPropertyFlags( CPF_EditConst );
|
|
}
|
|
}
|
|
else if ( Property->GetName() == TEXT( "bUploadTransformsToHoudiniEngine" ) )
|
|
{
|
|
// If upload of transformations is disabled, then there's no sense in cooking asset on transformation change.
|
|
if ( bUploadTransformsToHoudiniEngine )
|
|
{
|
|
LookupProperty = LocateProperty( TEXT( "bTransformChangeTriggersCooks" ) );
|
|
if ( LookupProperty )
|
|
LookupProperty->ClearPropertyFlags( CPF_EditConst );
|
|
}
|
|
else
|
|
{
|
|
LookupProperty = LocateProperty( TEXT( "bTransformChangeTriggersCooks" ) );
|
|
if ( LookupProperty )
|
|
LookupProperty->SetPropertyFlags( CPF_EditConst );
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
void
|
|
UHoudiniRuntimeSettings::SetMeshBuildSettings( FMeshBuildSettings & MeshBuildSettings, FRawMesh & RawMesh ) const
|
|
{
|
|
MeshBuildSettings.bRemoveDegenerates = bRemoveDegenerates;
|
|
MeshBuildSettings.bUseMikkTSpace = bUseMikkTSpace;
|
|
MeshBuildSettings.bBuildAdjacencyBuffer = bBuildAdjacencyBuffer;
|
|
MeshBuildSettings.MinLightmapResolution = MinLightmapResolution;
|
|
MeshBuildSettings.bUseFullPrecisionUVs = bUseFullPrecisionUVs;
|
|
MeshBuildSettings.SrcLightmapIndex = SrcLightmapIndex;
|
|
MeshBuildSettings.DstLightmapIndex = DstLightmapIndex;
|
|
|
|
// Recomputing normals.
|
|
switch ( RecomputeNormalsFlag )
|
|
{
|
|
case HRSRF_Always:
|
|
{
|
|
MeshBuildSettings.bRecomputeNormals = true;
|
|
break;
|
|
}
|
|
|
|
case HRSRF_OnlyIfMissing:
|
|
{
|
|
MeshBuildSettings.bRecomputeNormals = ( 0 == RawMesh.WedgeTangentZ.Num() );
|
|
break;
|
|
}
|
|
|
|
case HRSRF_Nothing:
|
|
default:
|
|
{
|
|
MeshBuildSettings.bRecomputeNormals = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Recomputing tangents.
|
|
switch ( RecomputeTangentsFlag )
|
|
{
|
|
case HRSRF_Always:
|
|
{
|
|
MeshBuildSettings.bRecomputeTangents = true;
|
|
break;
|
|
}
|
|
|
|
case HRSRF_OnlyIfMissing:
|
|
{
|
|
MeshBuildSettings.bRecomputeTangents = ( 0 == RawMesh.WedgeTangentX.Num() || 0 == RawMesh.WedgeTangentY.Num() );
|
|
break;
|
|
}
|
|
|
|
case HRSRF_Nothing:
|
|
default:
|
|
{
|
|
MeshBuildSettings.bRecomputeTangents = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Lightmap UV generation.
|
|
bool bHasLightmapUVSet = FHoudiniEngineUtils::CountUVSets( RawMesh ) > 1;
|
|
|
|
switch ( GenerateLightmapUVsFlag )
|
|
{
|
|
case HRSRF_Always:
|
|
{
|
|
MeshBuildSettings.bGenerateLightmapUVs = true;
|
|
break;
|
|
}
|
|
|
|
case HRSRF_OnlyIfMissing:
|
|
{
|
|
MeshBuildSettings.bGenerateLightmapUVs = !bHasLightmapUVSet;
|
|
break;
|
|
}
|
|
|
|
case HRSRF_Nothing:
|
|
default:
|
|
{
|
|
MeshBuildSettings.bGenerateLightmapUVs = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
UHoudiniRuntimeSettings::UpdateSessionUi()
|
|
{
|
|
SetPropertyReadOnly( TEXT( "ServerHost" ), true );
|
|
SetPropertyReadOnly( TEXT( "ServerPort" ), true );
|
|
SetPropertyReadOnly( TEXT( "ServerPipeName" ), true );
|
|
SetPropertyReadOnly( TEXT( "bStartAutomaticServer" ), true );
|
|
SetPropertyReadOnly( TEXT( "AutomaticServerTimeout" ), true );
|
|
|
|
bool bServerType = false;
|
|
|
|
switch ( SessionType )
|
|
{
|
|
case HRSST_Socket:
|
|
{
|
|
SetPropertyReadOnly( TEXT( "ServerHost" ), false);
|
|
SetPropertyReadOnly( TEXT( "ServerPort" ), false);
|
|
bServerType = true;
|
|
break;
|
|
}
|
|
|
|
case HRSST_NamedPipe:
|
|
{
|
|
SetPropertyReadOnly( TEXT( "ServerPipeName" ), false);
|
|
bServerType = true;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ( bServerType )
|
|
{
|
|
SetPropertyReadOnly( TEXT( "bStartAutomaticServer" ), false );
|
|
SetPropertyReadOnly( TEXT( "AutomaticServerTimeout" ), false );
|
|
}
|
|
}
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
bool
|
|
UHoudiniRuntimeSettings::GetSettingsValue( const FString & PropertyName, std::string & PropertyValue )
|
|
{
|
|
FString PropertyString = TEXT( "" );
|
|
if ( UHoudiniRuntimeSettings::GetSettingsValue( PropertyName, PropertyString ) )
|
|
{
|
|
FHoudiniEngineUtils::ConvertUnrealString( PropertyString, PropertyValue );
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
UHoudiniRuntimeSettings::GetSettingsValue( const FString & PropertyName, FString & PropertyValue )
|
|
{
|
|
const UHoudiniRuntimeSettings * HoudiniRuntimeSettings = GetDefault< UHoudiniRuntimeSettings >();
|
|
if ( HoudiniRuntimeSettings )
|
|
{
|
|
FStrProperty * Property = CastField< FStrProperty >( HoudiniRuntimeSettings->LocateProperty( PropertyName ) );
|
|
if ( Property )
|
|
{
|
|
const void * ValueRaw = Property->ContainerPtrToValuePtr< void >( HoudiniRuntimeSettings );
|
|
FString RetrievedPropertyValue = Property->GetPropertyValue( ValueRaw );
|
|
|
|
if ( !RetrievedPropertyValue.IsEmpty() )
|
|
{
|
|
PropertyValue = RetrievedPropertyValue;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE |