Skip to content

Instantly share code, notes, and snippets.

@trentpolack
Last active July 3, 2018 22:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save trentpolack/223e24ea8f8302536b22ebfa94825fd4 to your computer and use it in GitHub Desktop.
Save trentpolack/223e24ea8f8302536b22ebfa94825fd4 to your computer and use it in GitHub Desktop.
A sample data structure and its corresponding UE4 object for easy JSON serialization/deserialization.
// FMechPartDataBase Data Structure.
// This structure is solely for serialization/deserialization purposes (it gets transferred to the UObject instance after that process is done).
USTRUCT( )
struct FMechPartDataBase_SerializationStructure
{
GENERATED_BODY( )
public:
FMechPartDataBase_SerializationStructure( )
: ConfigName( NAME_None )
, PartType( 0 )
, Mass( 1.0f )
, HealthMax( 1.0f )
, AssetPath_MaterialPrimary( NAME_None )
, AssetPath_MaterialSecondary( NAME_None )
, AssetPath_MaterialAccent( NAME_None )
, AssetPath_MaterialChrome( NAME_None )
, AssetPath_MaterialMisc( NAME_None )
, AssetPath_SoundCue_Impact( NAME_None )
, AssetPath_SoundCue_Ricochet( NAME_None )
{ }
public:
/*
* Config Name.
*/
UPROPERTY( )
FName ConfigName;
/*
* Part Details.
*/
UPROPERTY( )
uint8 PartType;
UPROPERTY( )
float Mass;
UPROPERTY( )
float HealthMax;
/*
* Asset Reference Paths.
*/
UPROPERTY( )
FName AssetPath_MaterialPrimary;
UPROPERTY( )
FName AssetPath_MaterialSecondary;
UPROPERTY( )
FName AssetPath_MaterialAccent;
UPROPERTY( )
FName AssetPath_MaterialChrome;
UPROPERTY( )
FName AssetPath_MaterialMisc;
UPROPERTY( )
FName AssetPath_SoundCue_Impact;
UPROPERTY( )
FName AssetPath_SoundCue_Ricochet;
};
// UMechPartDataBase Class Definition.
// This is the class used for actual game code (as opposed to the data structure below, which is strictly for serialization.
UCLASS( BlueprintType )
class UMechPartDataBase : public UObject
{
GENERATED_BODY( )
public:
UMechPartDataBase( const class FObjectInitializer& ObjectInitializer );
private:
UPROPERTY( )
FMechPartDataBase_SerializationStructure BaseDataStructure;
protected:
// TSharedPtr< FMechPartDataBase_SerializationStructure > DataStructure;
FMechPartDataBase_SerializationStructure* DataStructure;
UPROPERTY( )
TEnumAsByte< EMechPartType::Type > PartType;
public:
virtual void SetSerializationData( const FMechPartDataBase_SerializationStructure* SerializationData );
// Read-only access to the data structure (weapon data structure, specifically, unlike the prior two).
const FMechPartDataBase_SerializationStructure& GetBaseSerializationDataRead( ) const;
// Writable access to the data structure (weapon data structure).
void GetBaseSerializationDataWrite( FMechPartDataBase_SerializationStructure& SerializationDataOut );
FMechPartDataBase_SerializationStructure& GetBaseSerializationDataWrite( );
public:
// NOTE (trent, 1/25/18): These accessor-generation macros do not result in the methods they define being treated as UFUNCTIONs (blueprint-exposable).
#define DEFINE_METHOD_SET_ACCESSOR( MemberType, Member ) \
FORCEINLINE_DEBUGGABLE void Set##Member( MemberType Member ) \
{ \
DataStructure->##Member = Member; \
}
#define DEFINE_METHOD_GET_ACCESSOR( MemberType, Member ) \
FORCEINLINE_DEBUGGABLE MemberType Get##Member( ) const \
{ \
return DataStructure->##Member; \
}
#define DEFINE_METHOD_ACCESSORS( MemberType, Member ) \
DEFINE_METHOD_SET_ACCESSOR( MemberType, Member ) \
DEFINE_METHOD_GET_ACCESSOR( MemberType, Member )
// Mech part type.
inline void SetPartType( TEnumAsByte< EMechPartType::Type > PartTypeIn )
{
PartType = PartTypeIn;
DataStructure->PartType = PartTypeIn;
}
inline TEnumAsByte< EMechPartType::Type > GetPartType( ) const
{
return PartType;
}
// Part JSON config name.
DEFINE_METHOD_ACCESSORS( const FName&, ConfigName )
DEFINE_METHOD_ACCESSORS( float, Mass )
DEFINE_METHOD_ACCESSORS( float, HealthMax )
DEFINE_METHOD_ACCESSORS( const FName&, AssetPath_MaterialPrimary )
DEFINE_METHOD_ACCESSORS( const FName&, AssetPath_MaterialSecondary )
DEFINE_METHOD_ACCESSORS( const FName&, AssetPath_MaterialAccent )
DEFINE_METHOD_ACCESSORS( const FName&, AssetPath_MaterialChrome )
DEFINE_METHOD_ACCESSORS( const FName&, AssetPath_MaterialMisc )
DEFINE_METHOD_ACCESSORS( const FName&, AssetPath_SoundCue_Impact )
DEFINE_METHOD_ACCESSORS( const FName&, AssetPath_SoundCue_Ricochet )
#undef DEFINE_METHOD_ACCESSORS
#undef DEFINE_METHOD_GET_ACCESSOR
#undef DEFINE_METHOD_SET_ACCESSOR
};
@inequation
Copy link

Just carrying over my comments from the Gamasutra article:

Why use FNames instead of FSoftObjectPath/TSoftObjectPtr? The latter would let you take advantage of the UI controls (i.e. picking asset with the content browser etc.) together with UI type safety.

Your accessor macros will be ignored by UnrealHeaderTool (it only does simplified parsing), so all the UFUNCTION() macros won't do anything (i.e. UHT will not generate reflection code for them).

Finally, why bother making members private if you then declare a bunch of boilerplate accessors, granting (almost) full access to the members in question? Why not just make them public in the first place?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment