2021-01-26 11:48:50 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "EditorConfig.h"
2021-02-15 11:55:20 -04:00
# include "UObject/EnumProperty.h"
# include "UObject/TextProperty.h"
2021-01-26 11:48:50 -04:00
# include "UObject/UnrealType.h"
FEditorConfig : : FEditorConfig ( )
{
JsonConfig = MakeShared < UE : : FJsonConfig > ( ) ;
}
void FEditorConfig : : SetParent ( TSharedPtr < FEditorConfig > InConfig )
{
ParentConfig = InConfig ;
if ( ParentConfig . IsValid ( ) )
{
JsonConfig - > SetParent ( ParentConfig - > JsonConfig ) ;
}
else
{
JsonConfig - > SetParent ( TSharedPtr < UE : : FJsonConfig > ( ) ) ;
}
}
bool FEditorConfig : : LoadFromFile ( FStringView FilePath )
{
JsonConfig = MakeShared < UE : : FJsonConfig > ( ) ;
if ( ! JsonConfig - > LoadFromFile ( FilePath ) )
{
return false ;
}
if ( ParentConfig . IsValid ( ) )
{
JsonConfig - > SetParent ( ParentConfig - > JsonConfig ) ;
}
return true ;
}
bool FEditorConfig : : LoadFromString ( FStringView Content )
{
JsonConfig = MakeShared < UE : : FJsonConfig > ( ) ;
if ( ! JsonConfig - > LoadFromString ( Content ) )
{
return false ;
}
if ( ParentConfig . IsValid ( ) )
{
JsonConfig - > SetParent ( ParentConfig - > JsonConfig ) ;
}
return true ;
}
bool FEditorConfig : : SaveToString ( FString & OutResult ) const
{
if ( ! IsValid ( ) )
{
return false ;
}
return JsonConfig - > SaveToString ( OutResult ) ;
}
bool FEditorConfig : : SaveToFile ( FStringView FilePath ) const
{
if ( ! IsValid ( ) )
{
return false ;
}
return JsonConfig - > SaveToFile ( FilePath ) ;
}
bool FEditorConfig : : HasOverride ( FStringView Key ) const
{
return JsonConfig - > HasOverride ( UE : : FJsonPath ( Key ) ) ;
}
2021-05-26 08:27:40 -04:00
bool FEditorConfig : : TryGetRootUObject ( const UClass * Class , UObject * OutValue , EPropertyFilter Filter ) const
{
if ( ! IsValid ( ) )
{
return false ;
}
TSharedPtr < FJsonObject > UObjectData = JsonConfig - > GetRootObject ( ) ;
ReadUObject ( UObjectData , Class , OutValue , Filter ) ;
return true ;
}
bool FEditorConfig : : TryGetRootStruct ( const UStruct * Struct , void * OutValue , EPropertyFilter Filter ) const
{
if ( ! IsValid ( ) )
{
return false ;
}
TSharedPtr < FJsonObject > StructData = JsonConfig - > GetRootObject ( ) ;
ReadStruct ( StructData , Struct , OutValue , nullptr , Filter ) ;
return true ;
}
2021-05-25 10:01:03 -04:00
void FEditorConfig : : SetRootUObject ( const UClass * Class , const UObject * Instance , EPropertyFilter Filter )
{
if ( ! IsValid ( ) )
{
return ;
}
TSharedPtr < FJsonObject > JsonObject = WriteUObject ( Class , Instance , Filter ) ;
JsonConfig - > SetRootObject ( JsonObject ) ;
SetDirty ( ) ;
}
void FEditorConfig : : SetRootStruct ( const UStruct * Struct , const void * Instance , EPropertyFilter Filter )
{
if ( ! IsValid ( ) )
{
return ;
}
2022-04-26 10:20:56 -04:00
TSharedPtr < FJsonObject > JsonObject = WriteStruct ( Struct , Instance , nullptr , Filter ) ;
2021-05-25 10:01:03 -04:00
JsonConfig - > SetRootObject ( JsonObject ) ;
SetDirty ( ) ;
}
2022-04-26 10:20:56 -04:00
void FEditorConfig : : ReadStruct ( const TSharedPtr < FJsonObject > & JsonObject , const UStruct * Struct , void * Instance , UObject * Owner , EPropertyFilter Filter )
2021-01-26 11:48:50 -04:00
{
FString TypeName ;
JsonObject - > TryGetStringField ( TEXT ( " $type " ) , TypeName ) ;
2021-05-25 10:01:03 -04:00
if ( ! TypeName . IsEmpty ( ) & & ! ensureAlwaysMsgf ( Struct - > GetName ( ) . Equals ( TypeName ) , TEXT ( " Type name mismatch in FEditorConfig::ReadUObject. Expected: %s, Actual: %s " ) , * Struct - > GetName ( ) , * TypeName ) )
2021-01-26 11:48:50 -04:00
{
return ;
}
for ( TFieldIterator < FProperty > It ( Struct ) ; It ; + + It )
{
2021-05-25 10:01:03 -04:00
const FProperty * Property = * It ;
if ( Filter = = EPropertyFilter : : MetadataOnly & & ! Property - > HasMetaData ( " EditorConfig " ) )
2021-01-26 11:48:50 -04:00
{
2021-05-25 10:01:03 -04:00
continue ;
}
void * DataPtr = Property - > ContainerPtrToValuePtr < void > ( Instance ) ;
2021-01-26 11:48:50 -04:00
2021-05-25 10:01:03 -04:00
TSharedPtr < FJsonValue > Value = JsonObject - > TryGetField ( Property - > GetName ( ) ) ;
if ( Value . IsValid ( ) )
{
ReadValue ( Value , Property , DataPtr , Owner ) ;
2021-01-26 11:48:50 -04:00
}
}
}
2022-04-26 10:20:56 -04:00
void FEditorConfig : : ReadUObject ( const TSharedPtr < FJsonObject > & JsonObject , const UClass * Class , UObject * Instance , EPropertyFilter Filter )
2021-01-26 11:48:50 -04:00
{
FString TypeName ;
JsonObject - > TryGetStringField ( TEXT ( " $type " ) , TypeName ) ;
2021-05-25 10:01:03 -04:00
if ( ! TypeName . IsEmpty ( ) & & ! ensureAlwaysMsgf ( Class - > GetName ( ) . Equals ( TypeName ) , TEXT ( " Type name mismatch in FEditorConfig::ReadUObject. Expected: %s, Actual: %s " ) , * Class - > GetName ( ) , * TypeName ) )
2021-01-26 11:48:50 -04:00
{
return ;
}
for ( TFieldIterator < FProperty > It ( Class ) ; It ; + + It )
{
2021-05-25 10:01:03 -04:00
const FProperty * Property = * It ;
if ( Filter = = EPropertyFilter : : MetadataOnly & & ! Property - > HasMetaData ( " EditorConfig " ) )
2021-01-26 11:48:50 -04:00
{
2021-05-25 10:01:03 -04:00
continue ;
}
2021-01-26 11:48:50 -04:00
2021-05-25 10:01:03 -04:00
void * DataPtr = Property - > ContainerPtrToValuePtr < void > ( Instance ) ;
2022-04-26 10:20:56 -04:00
2021-05-25 10:01:03 -04:00
TSharedPtr < FJsonValue > Value = JsonObject - > TryGetField ( Property - > GetName ( ) ) ;
if ( Value . IsValid ( ) )
{
ReadValue ( Value , Property , DataPtr , Instance ) ;
2021-01-26 11:48:50 -04:00
}
}
}
2022-04-26 10:20:56 -04:00
void FEditorConfig : : ReadValue ( const TSharedPtr < FJsonValue > & JsonValue , const FProperty * Property , void * DataPtr , UObject * Owner )
2021-01-26 11:48:50 -04:00
{
if ( const FStrProperty * StrProperty = CastField < FStrProperty > ( Property ) )
{
FString * Value = ( FString * ) DataPtr ;
JsonValue - > TryGetString ( * Value ) ;
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FNameProperty * NameProperty = CastField < FNameProperty > ( Property ) )
{
FString TempValue ;
JsonValue - > TryGetString ( TempValue ) ;
* ( FName * ) DataPtr = * TempValue ;
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FTextProperty * TextProperty = CastField < FTextProperty > ( Property ) )
{
FString TempValue ;
JsonValue - > TryGetString ( TempValue ) ;
* ( FText * ) DataPtr = FText : : FromString ( TempValue ) ;
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FBoolProperty * BoolProperty = CastField < FBoolProperty > ( Property ) )
{
bool Value = BoolProperty - > GetDefaultPropertyValue ( ) ;
if ( JsonValue - > TryGetBool ( Value ) )
{
BoolProperty - > SetPropertyValue ( DataPtr , Value ) ;
}
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FFloatProperty * FloatProperty = CastField < FFloatProperty > ( Property ) )
{
float * Value = ( float * ) DataPtr ;
JsonValue - > TryGetNumber ( * Value ) ;
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FDoubleProperty * DoubleProperty = CastField < FDoubleProperty > ( Property ) )
{
double * Value = ( double * ) DataPtr ;
JsonValue - > TryGetNumber ( * Value ) ;
2022-04-26 10:20:56 -04:00
return ;
}
2021-01-26 11:48:50 -04:00
else if ( const FInt8Property * Int8Property = CastField < FInt8Property > ( Property ) )
{
int8 * Value = ( int8 * ) DataPtr ;
JsonValue - > TryGetNumber ( * Value ) ;
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FInt16Property * Int16Property = CastField < FInt16Property > ( Property ) )
{
int16 * Value = ( int16 * ) DataPtr ;
JsonValue - > TryGetNumber ( * Value ) ;
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FIntProperty * Int32Property = CastField < FIntProperty > ( Property ) )
{
int32 * Value = ( int32 * ) DataPtr ;
JsonValue - > TryGetNumber ( * Value ) ;
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FInt64Property * Int64Property = CastField < FInt64Property > ( Property ) )
{
int64 * Value = ( int64 * ) DataPtr ;
JsonValue - > TryGetNumber ( * Value ) ;
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FByteProperty * ByteProperty = CastField < FByteProperty > ( Property ) )
{
uint8 * Value = ( uint8 * ) DataPtr ;
JsonValue - > TryGetNumber ( * Value ) ;
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FUInt16Property * Uint16Property = CastField < FUInt16Property > ( Property ) )
{
uint16 * Value = ( uint16 * ) DataPtr ;
JsonValue - > TryGetNumber ( * Value ) ;
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FUInt32Property * Uint32Property = CastField < FUInt32Property > ( Property ) )
{
uint32 * Value = ( uint32 * ) DataPtr ;
JsonValue - > TryGetNumber ( * Value ) ;
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FUInt64Property * Uint64Property = CastField < FUInt64Property > ( Property ) )
{
uint64 * Value = ( uint64 * ) DataPtr ;
JsonValue - > TryGetNumber ( * Value ) ;
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FEnumProperty * EnumProperty = CastField < FEnumProperty > ( Property ) )
{
int64 * Value = ( int64 * ) DataPtr ;
UEnum * Enum = EnumProperty - > GetEnum ( ) ;
if ( Enum ! = nullptr )
{
FString ValueString ;
if ( JsonValue - > TryGetString ( ValueString ) )
{
int64 Index = Enum - > GetIndexByNameString ( ValueString ) ;
if ( Index ! = INDEX_NONE )
{
* Value = Enum - > GetValueByIndex ( Index ) ;
}
}
}
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FObjectPropertyBase * ObjectProperty = CastField < FObjectPropertyBase > ( Property ) )
{
FString PathString ;
if ( JsonValue - > TryGetString ( PathString ) )
{
2022-02-25 10:39:39 -05:00
Property - > ImportText_Direct ( * PathString , DataPtr , Owner , 0 ) ;
2021-01-26 11:48:50 -04:00
}
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FStructProperty * StructProperty = CastField < FStructProperty > ( Property ) )
{
const TSharedPtr < FJsonObject > * ObjectJsonValue ;
if ( JsonValue - > TryGetObject ( ObjectJsonValue ) )
{
2021-05-25 10:01:03 -04:00
ReadStruct ( * ObjectJsonValue , StructProperty - > Struct , DataPtr , Owner , EPropertyFilter : : All ) ;
2021-01-26 11:48:50 -04:00
}
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FArrayProperty * ArrayProperty = CastField < FArrayProperty > ( Property ) )
{
const TArray < TSharedPtr < FJsonValue > > * ArrayJsonValue ;
if ( JsonValue - > TryGetArray ( ArrayJsonValue ) )
{
FProperty * InnerProperty = ArrayProperty - > Inner ;
FScriptArrayHelper ArrayHelper ( ArrayProperty , DataPtr ) ;
ArrayHelper . EmptyAndAddValues ( ArrayJsonValue - > Num ( ) ) ;
for ( int32 Idx = 0 ; Idx < ArrayHelper . Num ( ) ; + + Idx )
{
TSharedPtr < FJsonValue > Value = ( * ArrayJsonValue ) [ Idx ] ;
ReadValue ( Value , InnerProperty , ArrayHelper . GetRawPtr ( Idx ) , Owner ) ;
}
}
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FSetProperty * SetProperty = CastField < FSetProperty > ( Property ) )
{
const TArray < TSharedPtr < FJsonValue > > * SetJsonValue ;
if ( JsonValue - > TryGetArray ( SetJsonValue ) )
{
const FProperty * InnerProperty = SetProperty - > ElementProp ;
FScriptSetHelper SetHelper ( SetProperty , DataPtr ) ;
SetHelper . EmptyElements ( SetJsonValue - > Num ( ) ) ;
// temporary buffer to read elements into
TArray < uint8 > TempBuffer ;
TempBuffer . AddUninitialized ( InnerProperty - > ElementSize ) ;
for ( int32 Idx = 0 ; Idx < SetJsonValue - > Num ( ) ; + + Idx )
{
InnerProperty - > InitializeValue ( TempBuffer . GetData ( ) ) ;
TSharedPtr < FJsonValue > Value = ( * SetJsonValue ) [ Idx ] ;
2022-04-26 10:20:56 -04:00
ReadValue ( Value , InnerProperty , TempBuffer . GetData ( ) , Owner ) ;
2021-01-26 11:48:50 -04:00
SetHelper . AddElement ( TempBuffer . GetData ( ) ) ;
InnerProperty - > DestroyValue ( TempBuffer . GetData ( ) ) ;
}
}
2022-04-26 10:20:56 -04:00
return ;
2021-01-26 11:48:50 -04:00
}
else if ( const FMapProperty * MapProperty = CastField < FMapProperty > ( Property ) )
{
const FProperty * KeyProperty = MapProperty - > KeyProp ;
const FProperty * ValueProperty = MapProperty - > ValueProp ;
FScriptMapHelper MapHelper ( MapProperty , DataPtr ) ;
// maps can either be stored as a simple JSON object, or as an array of { $key, $value } pairs
// first check for object storage - this will cover eg. numbers and strings as keys
const TSharedPtr < FJsonObject > * JsonObjectValue ;
if ( JsonValue - > TryGetObject ( JsonObjectValue ) )
{
MapHelper . EmptyValues ( ( * JsonObjectValue ) - > Values . Num ( ) ) ;
// temporary buffers to read elements into
TArray < uint8 > TempKey ;
TempKey . AddZeroed ( KeyProperty - > ElementSize ) ;
TArray < uint8 > TempValue ;
TempValue . AddZeroed ( ValueProperty - > ElementSize ) ;
for ( const TPair < FString , TSharedPtr < FJsonValue > > & JsonPair : ( * JsonObjectValue ) - > Values )
{
KeyProperty - > InitializeValue ( TempKey . GetData ( ) ) ;
2022-02-25 10:39:39 -05:00
KeyProperty - > ImportText_Direct ( * JsonPair . Key , TempKey . GetData ( ) , Owner , 0 ) ;
2021-01-26 11:48:50 -04:00
ValueProperty - > InitializeValue ( TempValue . GetData ( ) ) ;
2022-04-26 10:20:56 -04:00
ReadValue ( JsonPair . Value , ValueProperty , TempValue . GetData ( ) , Owner ) ;
2021-01-26 11:48:50 -04:00
MapHelper . AddPair ( TempKey . GetData ( ) , TempValue . GetData ( ) ) ;
KeyProperty - > DestroyValue ( TempKey . GetData ( ) ) ;
ValueProperty - > DestroyValue ( TempValue . GetData ( ) ) ;
}
2022-04-26 10:20:56 -04:00
2021-01-26 11:48:50 -04:00
return ;
}
// then check for array storage, this will cover complex keys eg. custom structs
const TArray < TSharedPtr < FJsonValue > > * JsonArrayPtr = nullptr ;
if ( JsonValue - > TryGetArray ( JsonArrayPtr ) )
{
MapHelper . EmptyValues ( JsonArrayPtr - > Num ( ) ) ;
2022-04-26 10:20:56 -04:00
2021-01-26 11:48:50 -04:00
// temporary buffers to read elements into
TArray < uint8 > TempKey ;
TempKey . AddUninitialized ( KeyProperty - > ElementSize ) ;
TArray < uint8 > TempValue ;
TempValue . AddUninitialized ( ValueProperty - > ElementSize ) ;
for ( const TSharedPtr < FJsonValue > & JsonElement : * JsonArrayPtr )
{
TSharedPtr < FJsonObject > * JsonObject = nullptr ;
if ( JsonElement - > TryGetObject ( JsonObject ) )
{
TSharedPtr < FJsonValue > JsonKeyField = ( * JsonObject ) - > TryGetField ( TEXT ( " $key " ) ) ;
TSharedPtr < FJsonValue > JsonValueField = ( * JsonObject ) - > TryGetField ( TEXT ( " $value " ) ) ;
if ( JsonKeyField . IsValid ( ) & & JsonValueField . IsValid ( ) )
{
KeyProperty - > InitializeValue ( TempKey . GetData ( ) ) ;
2022-04-26 10:20:56 -04:00
ReadValue ( JsonKeyField , KeyProperty , TempKey . GetData ( ) , Owner ) ;
2021-01-26 11:48:50 -04:00
ValueProperty - > InitializeValue ( TempValue . GetData ( ) ) ;
2022-04-26 10:20:56 -04:00
ReadValue ( JsonValueField , ValueProperty , TempValue . GetData ( ) , Owner ) ;
2021-01-26 11:48:50 -04:00
MapHelper . AddPair ( TempKey . GetData ( ) , TempValue . GetData ( ) ) ;
KeyProperty - > DestroyValue ( TempKey . GetData ( ) ) ;
ValueProperty - > DestroyValue ( TempValue . GetData ( ) ) ;
}
}
}
return ;
}
}
2022-04-26 10:20:56 -04:00
ensureAlwaysMsgf ( false , TEXT ( " Property type is unsupported: %s, type: %s " ) , * Property - > GetPathName ( ) , * Property - > GetClass ( ) - > GetName ( ) ) ;
2021-01-26 11:48:50 -04:00
}
2022-04-26 10:20:56 -04:00
TSharedPtr < FJsonValue > FEditorConfig : : WriteArray ( const FArrayProperty * ArrayProperty , const void * DataPtr )
{
FProperty * InnerProperty = ArrayProperty - > Inner ;
FScriptArrayHelper ArrayHelper ( ArrayProperty , DataPtr ) ;
TArray < TSharedPtr < FJsonValue > > JsonValuesArray ;
JsonValuesArray . Reserve ( ArrayHelper . Num ( ) ) ;
for ( int32 Idx = 0 ; Idx < ArrayHelper . Num ( ) ; + + Idx )
{
if ( ArrayHelper . IsValidIndex ( Idx ) )
{
TSharedPtr < FJsonValue > ElementValue = WriteValue ( InnerProperty , ArrayHelper . GetRawPtr ( Idx ) , nullptr ) ;
check ( ElementValue . IsValid ( ) ) ;
JsonValuesArray . Add ( ElementValue ) ;
}
}
return MakeShared < FJsonValueArray > ( JsonValuesArray ) ;
}
TSharedPtr < FJsonValue > FEditorConfig : : WriteSet ( const FSetProperty * SetProperty , const void * DataPtr )
{
FProperty * InnerProperty = SetProperty - > ElementProp ;
FScriptSetHelper SetHelper ( SetProperty , DataPtr ) ;
TArray < TSharedPtr < FJsonValue > > JsonValuesArray ;
JsonValuesArray . Reserve ( SetHelper . Num ( ) ) ;
for ( int32 Idx = 0 ; Idx < SetHelper . Num ( ) ; + + Idx )
{
if ( SetHelper . IsValidIndex ( Idx ) )
{
TSharedPtr < FJsonValue > ElementValue = WriteValue ( InnerProperty , SetHelper . GetElementPtr ( Idx ) , nullptr ) ;
check ( ElementValue . IsValid ( ) ) ;
JsonValuesArray . Add ( ElementValue ) ;
}
}
return MakeShared < FJsonValueArray > ( JsonValuesArray ) ;
}
TSharedPtr < FJsonValue > FEditorConfig : : WriteMap ( const FMapProperty * MapProperty , const void * DataPtr )
2021-01-26 11:48:50 -04:00
{
TSharedPtr < FJsonValue > ResultValue ;
2022-04-26 10:20:56 -04:00
FProperty * KeyProperty = MapProperty - > KeyProp ;
FProperty * ValueProperty = MapProperty - > ValueProp ;
FScriptMapHelper MapHelper ( MapProperty , DataPtr ) ;
if ( MapHelper . Num ( ) = = 0 )
{
ResultValue = MakeShared < FJsonValueObject > ( MakeShared < FJsonObject > ( ) ) ;
}
else
{
TArray < TSharedPtr < FJsonValue > > JsonKeysArray ;
JsonKeysArray . Reserve ( MapHelper . Num ( ) ) ;
TArray < TSharedPtr < FJsonValue > > JsonValuesArray ;
JsonValuesArray . Reserve ( MapHelper . Num ( ) ) ;
for ( int32 Idx = 0 ; Idx < MapHelper . Num ( ) ; + + Idx )
{
if ( MapHelper . IsValidIndex ( Idx ) )
{
TSharedPtr < FJsonValue > JsonKey = WriteValue ( KeyProperty , MapHelper . GetKeyPtr ( Idx ) , nullptr ) ;
check ( JsonKey . IsValid ( ) ) ;
JsonKeysArray . Add ( JsonKey ) ;
TSharedPtr < FJsonValue > JsonValue = WriteValue ( ValueProperty , MapHelper . GetValuePtr ( Idx ) , nullptr ) ;
check ( JsonValue . IsValid ( ) ) ;
JsonValuesArray . Add ( JsonValue ) ;
}
}
// maps can either be stored as $key, $value pairs or, if the keys can be stringified, as a JSON object
// check Filter we should use based on the first element
EJson KeyType = JsonKeysArray [ 0 ] - > Type ;
if ( KeyType = = EJson : : Object )
{
TArray < TSharedPtr < FJsonValue > > ResultArray ;
ResultArray . Reserve ( MapHelper . Num ( ) ) ;
for ( int32 Idx = 0 ; Idx < MapHelper . Num ( ) ; + + Idx )
{
if ( MapHelper . IsValidIndex ( Idx ) )
{
TSharedPtr < FJsonObject > ElementObject = MakeShared < FJsonObject > ( ) ;
ElementObject - > SetField ( TEXT ( " $key " ) , JsonKeysArray [ Idx ] ) ;
ElementObject - > SetField ( TEXT ( " $value " ) , JsonValuesArray [ Idx ] ) ;
ResultArray . Add ( MakeShared < FJsonValueObject > ( ElementObject ) ) ;
}
}
ResultValue = MakeShared < FJsonValueArray > ( ResultArray ) ;
}
else if ( KeyType = = EJson : : Boolean | |
KeyType = = EJson : : Number | |
KeyType = = EJson : : String )
{
TSharedPtr < FJsonObject > ResultObject = MakeShared < FJsonObject > ( ) ;
for ( int32 Idx = 0 ; Idx < MapHelper . Num ( ) ; + + Idx )
{
if ( MapHelper . IsValidIndex ( Idx ) )
{
FString KeyString ;
check ( JsonKeysArray [ Idx ] - > TryGetString ( KeyString ) ) ;
ResultObject - > SetField ( KeyString , JsonValuesArray [ Idx ] ) ;
}
}
ResultValue = MakeShared < FJsonValueObject > ( ResultObject ) ;
}
ensureMsgf ( ResultValue . IsValid ( ) , TEXT ( " Map key type is invalid. " ) ) ;
}
return ResultValue ;
}
TSharedPtr < FJsonValue > FEditorConfig : : WriteValue ( const FProperty * Property , const void * DataPtr , const void * DefaultPtr )
{
TSharedPtr < FJsonValue > ResultValue ;
if ( DefaultPtr ! = nullptr & & Property - > Identical ( DataPtr , DefaultPtr ) )
{
return ResultValue ;
}
2021-01-26 11:48:50 -04:00
if ( const FStrProperty * StrProperty = CastField < FStrProperty > ( Property ) )
{
FString * Value = ( FString * ) DataPtr ;
ResultValue = MakeShared < FJsonValueString > ( * Value ) ;
}
else if ( const FNameProperty * NameProperty = CastField < FNameProperty > ( Property ) )
{
FName * Value = ( FName * ) DataPtr ;
ResultValue = MakeShared < FJsonValueString > ( Value - > ToString ( ) ) ;
}
else if ( const FTextProperty * TextProperty = CastField < FTextProperty > ( Property ) )
{
FText * Value = ( FText * ) DataPtr ;
ResultValue = MakeShared < FJsonValueString > ( Value - > ToString ( ) ) ;
}
else if ( const FBoolProperty * BoolProperty = CastField < FBoolProperty > ( Property ) )
{
bool Value = BoolProperty - > GetPropertyValue ( DataPtr ) ;
ResultValue = MakeShared < FJsonValueBoolean > ( Value ) ;
}
else if ( const FFloatProperty * FloatProperty = CastField < FFloatProperty > ( Property ) )
{
float * Value = ( float * ) DataPtr ;
ResultValue = MakeShared < FJsonValueNumber > ( * Value ) ;
}
else if ( const FDoubleProperty * DoubleProperty = CastField < FDoubleProperty > ( Property ) )
{
double * Value = ( double * ) DataPtr ;
ResultValue = MakeShared < FJsonValueNumber > ( * Value ) ;
}
else if ( const FInt8Property * Int8Property = CastField < FInt8Property > ( Property ) )
{
int8 * Value = ( int8 * ) DataPtr ;
ResultValue = MakeShared < FJsonValueNumber > ( * Value ) ;
}
else if ( const FInt16Property * Int16Property = CastField < FInt16Property > ( Property ) )
{
int16 * Value = ( int16 * ) DataPtr ;
ResultValue = MakeShared < FJsonValueNumber > ( * Value ) ;
}
else if ( const FIntProperty * Int32Property = CastField < FIntProperty > ( Property ) )
{
int32 * Value = ( int32 * ) DataPtr ;
ResultValue = MakeShared < FJsonValueNumber > ( * Value ) ;
}
else if ( const FInt64Property * Int64Property = CastField < FInt64Property > ( Property ) )
{
int64 * Value = ( int64 * ) DataPtr ;
ResultValue = MakeShared < FJsonValueNumber > ( * Value ) ;
}
else if ( const FByteProperty * ByteProperty = CastField < FByteProperty > ( Property ) )
{
uint8 * Value = ( uint8 * ) DataPtr ;
ResultValue = MakeShared < FJsonValueNumber > ( * Value ) ;
}
else if ( const FUInt16Property * Uint16Property = CastField < FUInt16Property > ( Property ) )
{
uint16 * Value = ( uint16 * ) DataPtr ;
ResultValue = MakeShared < FJsonValueNumber > ( * Value ) ;
}
else if ( const FUInt32Property * Uint32Property = CastField < FUInt32Property > ( Property ) )
{
uint32 * Value = ( uint32 * ) DataPtr ;
ResultValue = MakeShared < FJsonValueNumber > ( * Value ) ;
}
else if ( const FUInt64Property * Uint64Property = CastField < FUInt64Property > ( Property ) )
{
uint64 * Value = ( uint64 * ) DataPtr ;
ResultValue = MakeShared < FJsonValueNumber > ( * Value ) ;
}
else if ( const FEnumProperty * EnumProperty = CastField < FEnumProperty > ( Property ) )
{
int64 * Value = ( int64 * ) DataPtr ;
UEnum * Enum = EnumProperty - > GetEnum ( ) ;
FName ValueName = Enum - > GetNameByValue ( * Value ) ;
ResultValue = MakeShared < FJsonValueString > ( ValueName . ToString ( ) ) ;
}
else if ( const FObjectPropertyBase * ObjectProperty = CastField < FObjectPropertyBase > ( Property ) )
{
FString ObjectPath ;
2022-02-25 10:39:39 -05:00
ObjectProperty - > ExportTextItem_Direct ( ObjectPath , DataPtr , nullptr , nullptr , PPF_None , nullptr ) ;
2021-01-26 11:48:50 -04:00
ResultValue = MakeShared < FJsonValueString > ( ObjectPath ) ;
}
else if ( const FStructProperty * StructProperty = CastField < FStructProperty > ( Property ) )
{
2022-04-26 10:20:56 -04:00
ResultValue = MakeShared < FJsonValueObject > ( WriteStruct ( StructProperty - > Struct , DataPtr , DefaultPtr , EPropertyFilter : : All ) ) ;
2021-01-26 11:48:50 -04:00
}
else if ( const FArrayProperty * ArrayProperty = CastField < FArrayProperty > ( Property ) )
{
2022-04-26 10:20:56 -04:00
ResultValue = WriteArray ( ArrayProperty , DataPtr ) ;
2021-01-26 11:48:50 -04:00
}
else if ( const FSetProperty * SetProperty = CastField < FSetProperty > ( Property ) )
{
2022-04-26 10:20:56 -04:00
ResultValue = WriteSet ( SetProperty , DataPtr ) ;
2021-01-26 11:48:50 -04:00
}
else if ( const FMapProperty * MapProperty = CastField < FMapProperty > ( Property ) )
{
2022-04-26 10:20:56 -04:00
ResultValue = WriteMap ( MapProperty , DataPtr ) ;
2021-01-26 11:48:50 -04:00
}
2022-04-26 10:20:56 -04:00
ensureAlwaysMsgf ( ResultValue . IsValid ( ) , TEXT ( " Property type is unsupported: %s, type: %s " ) , * Property - > GetPathName ( ) , * Property - > GetClass ( ) - > GetName ( ) ) ;
2021-01-26 11:48:50 -04:00
return ResultValue ;
}
2022-04-26 10:20:56 -04:00
TSharedPtr < FJsonObject > FEditorConfig : : WriteStruct ( const UStruct * Struct , const void * Instance , const void * Defaults , EPropertyFilter Filter )
2021-01-26 11:48:50 -04:00
{
TSharedPtr < FJsonObject > JsonObject = MakeShared < FJsonObject > ( ) ;
2021-05-25 10:01:03 -04:00
JsonObject - > SetStringField ( TEXT ( " $type " ) , Struct - > GetName ( ) ) ;
2022-04-26 10:20:56 -04:00
// Default initialize a struct here if we weren't passed one.
// This is necessary because structs can contain default initializations, eg.:
// struct Foo { float Bar = 5.0f; }
// The Bar FProperty does not store this value itself, only the struct does.
TArray < uint8 > TempDefaults ;
if ( Defaults = = nullptr )
{
TempDefaults . AddZeroed ( Struct - > GetStructureSize ( ) ) ;
Struct - > InitializeStruct ( TempDefaults . GetData ( ) ) ;
Defaults = TempDefaults . GetData ( ) ;
}
bool bAnyWritten = false ;
2021-01-26 11:48:50 -04:00
for ( TFieldIterator < FProperty > It ( Struct ) ; It ; + + It )
{
const FProperty * Property = * It ;
2021-05-25 10:01:03 -04:00
if ( Filter = = EPropertyFilter : : MetadataOnly & & ! Property - > HasMetaData ( " EditorConfig " ) )
{
continue ;
}
2022-04-26 10:20:56 -04:00
bAnyWritten = true ;
2021-01-26 11:48:50 -04:00
2022-04-26 10:20:56 -04:00
const void * ValuePtr = Property - > ContainerPtrToValuePtr < void > ( Instance ) ;
const void * PropertyDefaultPtr = Property - > ContainerPtrToValuePtr < void > ( Defaults ) ;
TSharedPtr < FJsonValue > PropertyValue = WriteValue ( Property , ValuePtr , PropertyDefaultPtr ) ;
if ( PropertyValue . IsValid ( ) )
2021-01-26 11:48:50 -04:00
{
JsonObject - > SetField ( Property - > GetName ( ) , PropertyValue ) ;
}
}
2022-04-26 10:20:56 -04:00
ensureAlwaysMsgf ( bAnyWritten , TEXT ( " Struct type has no properties to serialize: %s " ) , * Struct - > GetName ( ) ) ;
2021-01-26 11:48:50 -04:00
return JsonObject ;
}
/**
2021-05-25 10:01:03 -04:00
* This exists because of sparse class data that can exist for UObjects only , which is handled in ContainerPtrToValuePtr .
*/
TSharedPtr < FJsonObject > FEditorConfig : : WriteUObject ( const UClass * Class , const UObject * Instance , EPropertyFilter Filter )
2021-01-26 11:48:50 -04:00
{
TSharedPtr < FJsonObject > JsonObject = MakeShared < FJsonObject > ( ) ;
2021-05-25 10:01:03 -04:00
JsonObject - > SetStringField ( TEXT ( " $type " ) , Class - > GetName ( ) ) ;
2021-01-26 11:48:50 -04:00
2022-04-26 10:20:56 -04:00
const UObject * Defaults = Class - > GetDefaultObject ( ) ;
bool bAnyWritten = false ;
2021-05-25 10:01:03 -04:00
for ( TFieldIterator < FProperty > It ( Class ) ; It ; + + It )
2021-01-26 11:48:50 -04:00
{
const FProperty * Property = * It ;
2021-05-25 10:01:03 -04:00
if ( Filter = = EPropertyFilter : : MetadataOnly & & ! Property - > HasMetaData ( " EditorConfig " ) )
{
continue ;
}
2022-04-26 10:20:56 -04:00
bAnyWritten = true ;
2021-01-26 11:48:50 -04:00
2022-04-26 10:20:56 -04:00
const void * ValuePtr = Property - > ContainerPtrToValuePtr < void > ( Instance ) ;
const void * PropertyDefaultPtr = Property - > ContainerPtrToValuePtr < void > ( Defaults ) ;
TSharedPtr < FJsonValue > PropertyValue = WriteValue ( Property , ValuePtr , PropertyDefaultPtr ) ;
if ( PropertyValue . IsValid ( ) )
2021-01-26 11:48:50 -04:00
{
JsonObject - > SetField ( Property - > GetName ( ) , PropertyValue ) ;
}
}
2022-04-26 10:20:56 -04:00
ensureAlwaysMsgf ( bAnyWritten , TEXT ( " UObject type has no properties to serialize: %s " ) , * Class - > GetName ( ) ) ;
2021-01-26 11:48:50 -04:00
return JsonObject ;
}
2021-05-25 10:01:03 -04:00
void FEditorConfig : : SetDirty ( )
{
if ( ! Dirty )
{
Dirty = true ;
EditorConfigDirtiedEvent . Broadcast ( * this ) ;
}
}
void FEditorConfig : : OnSaved ( )
{
Dirty = false ;
}