2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "UnrealHeaderTool.h"
# include "UniquePtr.h"
# include "ParserHelper.h"
# include "NativeClassExporter.h"
# include "HeaderParser.h"
# include "ClassMaps.h"
2014-05-22 01:20:24 -04:00
# include "IScriptGeneratorPluginInterface.h"
2014-04-02 18:09:23 -04:00
# include "Manifest.h"
2014-04-23 18:46:37 -04:00
# include "StringUtils.h"
2014-06-30 06:19:02 -04:00
# include "IPluginManager.h"
2015-05-27 11:12:26 -04:00
# include "Runtime/Core/Public/Features/IModularFeatures.h"
2015-11-18 16:20:49 -05:00
# include "UHTMakefile/UHTMakefile.h"
# include "ScopeExit.h"
2014-03-14 14:13:41 -04:00
/////////////////////////////////////////////////////
2014-04-02 18:09:23 -04:00
// Globals
2014-03-14 14:13:41 -04:00
2014-04-02 18:09:23 -04:00
FManifest GManifest ;
2014-03-14 14:13:41 -04:00
2015-03-27 17:16:51 -04:00
double GMacroizeTime = 0.0 ;
2014-03-14 14:13:41 -04:00
static TArray < FString > ChangeMessages ;
static bool bWriteContents = false ;
static bool bVerifyContents = false ;
static const bool bMultiLineUFUNCTION = true ;
static const bool bMultiLineUPROPERTY = true ;
2015-11-18 16:20:49 -05:00
static TSharedRef < FUnrealSourceFile > PerformInitialParseOnHeader ( UPackage * InParent , const FString & FileName , EObjectFlags Flags , const TCHAR * Buffer , FUHTMakefile & UHTMakefile ) ;
2014-03-14 14:13:41 -04:00
2014-06-02 07:02:29 -04:00
FCompilerMetadataManager GScriptHelper ;
2014-03-14 14:13:41 -04:00
/** C++ name lookup helper */
2014-06-02 07:02:29 -04:00
FNameLookupCPP NameLookupCPP ;
2014-03-14 14:13:41 -04:00
2015-04-20 06:19:21 -04:00
/**
* Finds exact match of Identifier in string . Returns nullptr if none is found .
*
* @ param StringBegin Start of string to search .
* @ param StringEnd End of string to search .
* @ param Identifier Identifier to find .
* @ return Pointer to Identifier match within string . nullptr if none found .
*/
const TCHAR * FindIdentifierExactMatch ( const TCHAR * StringBegin , const TCHAR * StringEnd , const FString & Identifier )
2015-04-10 06:02:22 -04:00
{
2015-04-20 06:19:21 -04:00
int32 StringLen = StringEnd - StringBegin ;
// Check for exact match first.
if ( FCString : : Strncmp ( StringBegin , * Identifier , StringLen ) = = 0 )
{
return StringBegin ;
}
2015-11-18 16:20:49 -05:00
int32 FindLen = Identifier . Len ( ) ;
const TCHAR * StringToSearch = StringBegin ;
2015-04-10 06:02:22 -04:00
for ( ; ; )
{
2015-11-18 16:20:49 -05:00
const TCHAR * IdentifierStart = FCString : : Strstr ( StringToSearch , * Identifier ) ;
2015-04-20 06:19:21 -04:00
if ( IdentifierStart = = nullptr )
2015-04-10 06:02:22 -04:00
{
2015-04-20 06:19:21 -04:00
// Not found.
return nullptr ;
2015-04-10 06:02:22 -04:00
}
2015-11-18 16:20:49 -05:00
if ( IdentifierStart > StringEnd | | IdentifierStart + FindLen + 1 > StringEnd )
2015-04-10 06:02:22 -04:00
{
2015-04-20 06:19:21 -04:00
// Found match is out of string range.
return nullptr ;
2015-04-10 06:02:22 -04:00
}
2015-11-18 16:20:49 -05:00
if ( IdentifierStart = = StringBegin & & ! FChar : : IsIdentifier ( * ( IdentifierStart + FindLen + 1 ) ) )
2015-04-20 06:19:21 -04:00
{
// Found match is at the beginning of string.
return IdentifierStart ;
2015-04-17 04:04:20 -04:00
}
2015-11-18 16:20:49 -05:00
if ( IdentifierStart + FindLen = = StringEnd & & ! FChar : : IsIdentifier ( * ( IdentifierStart - 1 ) ) )
2015-04-20 06:19:21 -04:00
{
// Found match ends with end of string.
return IdentifierStart ;
}
2015-11-18 16:20:49 -05:00
if ( ! FChar : : IsIdentifier ( * ( IdentifierStart + FindLen ) ) & & ! FChar : : IsIdentifier ( * ( IdentifierStart - 1 ) ) )
2015-04-20 06:19:21 -04:00
{
// Found match is in the middle of string
return IdentifierStart ;
}
// Didn't find exact match, nor got to end of search string. Keep on searching.
StringToSearch = IdentifierStart + FindLen ;
}
2015-04-10 06:02:22 -04:00
// We should never get here.
checkNoEntry ( ) ;
2015-04-20 06:19:21 -04:00
return nullptr ;
}
/**
* Finds exact match of Identifier in string . Returns nullptr if none is found .
*
* @ param String String to search .
* @ param Identifier Identifier to find .
* @ return Index to Identifier match within String . INDEX_NONE if none found .
*/
int32 FindIdentifierExactMatch ( const FString & String , const FString & Identifier )
{
2015-11-18 16:20:49 -05:00
const TCHAR * IdentifierPtr = FindIdentifierExactMatch ( * String , * String + String . Len ( ) , Identifier ) ;
2015-04-20 06:19:21 -04:00
if ( IdentifierPtr = = nullptr )
{
return INDEX_NONE ;
}
return IdentifierPtr - * String ;
}
/**
* Checks if exact match of Identifier is in String .
*
* @ param StringBegin Start of string to search .
* @ param StringEnd End of string to search .
* @ param Identifier Identifier to find .
* @ return true if Identifier is within string , false otherwise .
*/
bool HasIdentifierExactMatch ( const TCHAR * StringBegin , const TCHAR * StringEnd , const FString & Find )
{
return FindIdentifierExactMatch ( StringBegin , StringEnd , Find ) ! = nullptr ;
}
/**
* Checks if exact match of Identifier is in String .
*
* @ param String String to search .
* @ param Identifier Identifier to find .
* @ return true if Identifier is within String , false otherwise .
*/
bool HasIdentifierExactMatch ( const FString & String , const FString & Identifier )
{
return FindIdentifierExactMatch ( String , Identifier ) ! = INDEX_NONE ;
2015-04-10 06:02:22 -04:00
}
2014-03-14 14:13:41 -04:00
/////////////////////////////////////////////////////
// FFlagAudit
//@todo: UCREMOVAL this is all audit stuff
static struct FFlagAudit
{
struct Pair
{
FString Name ;
uint64 Flags ;
2015-11-18 16:20:49 -05:00
Pair ( const UObject * Source , const TCHAR * FlagType , uint64 InFlags )
2014-03-14 14:13:41 -04:00
{
Name = Source - > GetFullName ( ) + TEXT ( " [ " ) + FlagType + TEXT ( " ] " ) ;
Flags = InFlags ;
}
} ;
TArray < Pair > Items ;
2015-11-18 16:20:49 -05:00
void Add ( const UObject * Source , const TCHAR * FlagType , uint64 Flags )
2014-03-14 14:13:41 -04:00
{
new ( Items ) Pair ( Source , FlagType , Flags ) ;
}
void WriteResults ( )
{
bool bDoDiff = false ;
FString Filename ;
FString RefFilename = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " ReferenceFlags.txt " ) ;
if ( ! FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " WRITEFLAGS " ) ) )
{
return ;
}
if ( FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " WRITEREF " ) ) )
{
Filename = RefFilename ;
}
else if ( FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " VERIFYREF " ) ) )
{
Filename = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " VerifyFlags.txt " ) ;
bDoDiff = true ;
}
struct FComparePairByName
{
FORCEINLINE bool operator ( ) ( const FFlagAudit : : Pair & A , const FFlagAudit : : Pair & B ) const { return A . Name < B . Name ; }
} ;
Items . Sort ( FComparePairByName ( ) ) ;
int32 MaxLen = 0 ;
for ( int32 Index = 0 ; Index < Items . Num ( ) ; Index + + )
{
MaxLen = FMath : : Max < int32 > ( Items [ Index ] . Name . Len ( ) , MaxLen ) ;
}
MaxLen + = 4 ;
FStringOutputDevice File ;
for ( int32 Index = 0 ; Index < Items . Num ( ) ; Index + + )
{
File . Logf ( TEXT ( " %s%s0x%016llx \r \n " ) , * Items [ Index ] . Name , FCString : : Spc ( MaxLen - Items [ Index ] . Name . Len ( ) ) , Items [ Index ] . Flags ) ;
}
FFileHelper : : SaveStringToFile ( File , * Filename ) ;
if ( bDoDiff )
{
FString Verify = File ;
FString Ref ;
if ( FFileHelper : : LoadFileToString ( Ref , * RefFilename ) )
{
FStringOutputDevice MisMatches ;
TArray < FString > VerifyLines ;
2015-03-02 15:51:37 -05:00
Verify . ParseIntoArray ( VerifyLines , TEXT ( " \n " ) , true ) ;
2014-03-14 14:13:41 -04:00
TArray < FString > RefLines ;
2015-03-02 15:51:37 -05:00
Ref . ParseIntoArray ( RefLines , TEXT ( " \n " ) , true ) ;
2014-03-14 14:13:41 -04:00
check ( VerifyLines . Num ( ) = = RefLines . Num ( ) ) ; // we aren't doing a sophisticated diff
for ( int32 Index = 0 ; Index < RefLines . Num ( ) ; Index + + )
{
if ( RefLines [ Index ] ! = VerifyLines [ Index ] )
{
MisMatches . Logf ( TEXT ( " REF : %s " ) , * RefLines [ Index ] ) ;
MisMatches . Logf ( TEXT ( " VERIFY: %s " ) , * VerifyLines [ Index ] ) ;
}
}
FString DiffFilename = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " FlagsDiff.txt " ) ;
FFileHelper : : SaveStringToFile ( MisMatches , * DiffFilename ) ;
}
}
}
} TheFlagAudit ;
2015-11-18 16:20:49 -05:00
void ConvertToBuildIncludePath ( const UPackage * Package , FString & LocalPath )
2014-05-19 06:57:00 -04:00
{
FPaths : : MakePathRelativeTo ( LocalPath , * GPackageToManifestModuleMap . FindChecked ( Package ) - > IncludeBase ) ;
}
2014-03-14 14:13:41 -04:00
/**
* Helper function for finding the location of a package
* This is required as source now lives in several possible directories
*
* @ param InPackage The name of the package of interest
* @ param OutLocation The location of the given package , if found
* @ param OutHeaderLocation The directory where generated headers should be placed
*
* @ return bool true if found , false if not
*/
2014-09-18 04:05:01 -04:00
bool FindPackageLocation ( const TCHAR * InPackage , FString & OutLocation , FString & OutHeaderLocation )
2014-03-14 14:13:41 -04:00
{
// Mapping of processed packages to their locations
// An empty location string means it was processed but not found
2014-04-23 20:18:55 -04:00
static TMap < FString , FManifestModule * > CheckedPackageList ;
2014-03-14 14:13:41 -04:00
FString CheckPackage ( InPackage ) ;
2015-11-18 16:20:49 -05:00
FManifestModule * ModuleInfoPtr = CheckedPackageList . FindRef ( CheckPackage ) ;
2014-03-14 14:13:41 -04:00
if ( ! ModuleInfoPtr )
{
2015-11-18 16:20:49 -05:00
FManifestModule * ModuleInfoPtr2 = GManifest . Modules . FindByPredicate ( [ & ] ( FManifestModule & Module ) { return Module . Name = = CheckPackage ; } ) ;
2014-03-14 14:13:41 -04:00
if ( ModuleInfoPtr2 & & IFileManager : : Get ( ) . DirectoryExists ( * ModuleInfoPtr2 - > BaseDirectory ) )
{
ModuleInfoPtr = ModuleInfoPtr2 ;
CheckedPackageList . Add ( CheckPackage , ModuleInfoPtr ) ;
}
}
if ( ! ModuleInfoPtr )
2015-11-18 16:20:49 -05:00
{
2014-03-14 14:13:41 -04:00
return false ;
2015-11-18 16:20:49 -05:00
}
2014-03-14 14:13:41 -04:00
OutLocation = ModuleInfoPtr - > BaseDirectory ;
OutHeaderLocation = ModuleInfoPtr - > GeneratedIncludeDirectory ;
return true ;
}
2015-03-27 17:16:51 -04:00
FString Macroize ( const TCHAR * MacroName , const TCHAR * StringToMacroize )
2014-03-14 14:13:41 -04:00
{
2015-03-27 17:16:51 -04:00
FScopedDurationTimer Tracker ( GMacroizeTime ) ;
2014-03-14 14:13:41 -04:00
FString Result = StringToMacroize ;
if ( Result . Len ( ) )
{
2015-03-27 18:10:52 -04:00
Result . ReplaceInline ( TEXT ( " \r \n " ) , TEXT ( " \n " ) , ESearchCase : : CaseSensitive ) ;
Result . ReplaceInline ( TEXT ( " \n " ) , TEXT ( " \\ \n " ) , ESearchCase : : CaseSensitive ) ;
checkSlow ( Result . EndsWith ( TEXT ( " \\ \n " ) , ESearchCase : : CaseSensitive ) ) ;
if ( Result . Len ( ) > = 3 )
{
for ( int32 Index = Result . Len ( ) - 3 ; Index < Result . Len ( ) ; + + Index )
{
Result [ Index ] = TEXT ( ' \n ' ) ;
}
}
else
{
Result = TEXT ( " \n \n \n " ) ;
}
Result . ReplaceInline ( TEXT ( " \n " ) , TEXT ( " \r \n " ) , ESearchCase : : CaseSensitive ) ;
2014-03-14 14:13:41 -04:00
}
return FString : : Printf ( TEXT ( " #define %s%s \r \n " ) , MacroName , Result . Len ( ) ? TEXT ( " \\ " ) : TEXT ( " " ) ) + Result ;
}
2014-10-30 09:53:47 -04:00
/** Generates a CRC tag string for the specified field */
static FString GetGeneratedCodeCRCTag ( UField * Field )
{
FString Tag ;
2015-11-18 16:20:49 -05:00
const uint32 * FieldCrc = GGeneratedCodeCRCs . Find ( Field ) ;
2014-10-30 09:53:47 -04:00
if ( FieldCrc )
{
Tag = FString : : Printf ( TEXT ( " // %u " ) , * FieldCrc ) ;
}
return Tag ;
}
2014-03-14 14:13:41 -04:00
struct FParmsAndReturnProperties
{
FParmsAndReturnProperties ( )
: Return ( NULL )
{
}
# if PLATFORM_COMPILER_HAS_DEFAULTED_FUNCTIONS
FParmsAndReturnProperties ( FParmsAndReturnProperties & & ) = default ;
FParmsAndReturnProperties ( const FParmsAndReturnProperties & ) = default ;
FParmsAndReturnProperties & operator = ( FParmsAndReturnProperties & & ) = default ;
FParmsAndReturnProperties & operator = ( const FParmsAndReturnProperties & ) = default ;
# else
FParmsAndReturnProperties ( FParmsAndReturnProperties & & Other ) : Parms ( MoveTemp ( Other . Parms ) ) , Return ( MoveTemp ( Other . Return ) ) { }
FParmsAndReturnProperties ( const FParmsAndReturnProperties & Other ) : Parms ( Other . Parms ) , Return ( Other . Return ) { }
FParmsAndReturnProperties & operator = ( FParmsAndReturnProperties & & Other ) { Parms = MoveTemp ( Other . Parms ) ; Return = MoveTemp ( Other . Return ) ; return * this ; }
FParmsAndReturnProperties & operator = ( const FParmsAndReturnProperties & Other ) { Parms = Other . Parms ; Return = Other . Return ; return * this ; }
# endif
bool HasParms ( ) const
{
return Parms . Num ( ) | | Return ;
}
TArray < UProperty * > Parms ;
UProperty * Return ;
} ;
/**
* Get parameters and return type for a given function .
*
* @ param Function The function to get the parameters for .
* @ return An aggregate containing the parameters and return type of that function .
*/
FParmsAndReturnProperties GetFunctionParmsAndReturn ( UFunction * Function )
{
FParmsAndReturnProperties Result ;
for ( TFieldIterator < UProperty > It ( Function ) ; It ; + + It )
{
UProperty * Field = * It ;
if ( ( It - > PropertyFlags & ( CPF_Parm | CPF_ReturnParm ) ) = = CPF_Parm )
{
Result . Parms . Add ( Field ) ;
}
else if ( It - > PropertyFlags & CPF_ReturnParm )
{
Result . Return = Field ;
}
}
return Result ;
}
/**
* Determines whether the glue version of the specified native function
* should be exported
*
* @ param Function the function to check
* @ return true if the glue version of the function should be exported .
*/
bool FNativeClassHeaderGenerator : : ShouldExportFunction ( UFunction * Function )
{
// export any script stubs for native functions declared in interface classes
bool bIsBlueprintNativeEvent = ( Function - > FunctionFlags & FUNC_BlueprintEvent ) & & ( Function - > FunctionFlags & FUNC_Native ) ;
if ( Function - > GetOwnerClass ( ) - > HasAnyClassFlags ( CLASS_Interface ) & & ! bIsBlueprintNativeEvent )
return true ;
// always export if the function is static
if ( Function - > FunctionFlags & FUNC_Static )
return true ;
// don't export the function if this is not the original declaration and there is
// at least one parent version of the function that is declared native
for ( UFunction * ParentFunction = Function - > GetSuperFunction ( ) ; ParentFunction ; ParentFunction = ParentFunction - > GetSuperFunction ( ) )
{
if ( ParentFunction - > FunctionFlags & FUNC_Native )
return false ;
}
return true ;
}
FString CreateLiteralString ( const FString & Str )
{
FString Result = TEXT ( " TEXT( \" " ) ;
// Have a reasonable guess at reserving the right size
Result . Reserve ( Str . Len ( ) + Result . Len ( ) ) ;
bool bPreviousCharacterWasHex = false ;
const TCHAR * Ptr = * Str ;
while ( TCHAR Ch = * Ptr + + )
{
switch ( Ch )
{
case TEXT ( ' \r ' ) : continue ;
case TEXT ( ' \n ' ) : Result + = TEXT ( " \\ n " ) ; bPreviousCharacterWasHex = false ; break ;
case TEXT ( ' \\ ' ) : Result + = TEXT ( " \\ \\ " ) ; bPreviousCharacterWasHex = false ; break ;
case TEXT ( ' \" ' ) : Result + = TEXT ( " \\ \" " ) ; bPreviousCharacterWasHex = false ; break ;
default :
if ( Ch < 31 | | Ch > = 128 )
{
Result + = FString : : Printf ( TEXT ( " \\ x%04x " ) , Ch ) ;
bPreviousCharacterWasHex = true ;
}
else
{
// We close and open the literal (with TEXT) here in order to ensure that successive hex characters aren't appended to the hex sequence, causing a different number
if ( bPreviousCharacterWasHex & & FCharWide : : IsHexDigit ( Ch ) )
{
Result + = " \" )TEXT( \" " ;
}
bPreviousCharacterWasHex = false ;
Result + = Ch ;
}
break ;
}
}
Result + = TEXT ( " \" ) " ) ;
return Result ;
}
2015-11-18 16:20:49 -05:00
static FString GetMetaDataCodeForObject ( const UObject * Object , const TCHAR * SymbolName , const TCHAR * Spaces )
2014-03-14 14:13:41 -04:00
{
TMap < FName , FString > * MetaData = UMetaData : : GetMapForObject ( Object ) ;
FString Result ;
if ( MetaData & & MetaData - > Num ( ) )
{
typedef TKeyValuePair < FName , FString > KVPType ;
TArray < KVPType > KVPs ;
2015-11-18 16:20:49 -05:00
for ( TPair < FName , FString > & KVP : * MetaData )
2014-03-14 14:13:41 -04:00
{
KVPs . Add ( KVPType ( KVP . Key , KVP . Value ) ) ;
}
// We sort the metadata here so that we can get consistent output across multiple runs
// even when metadata is added in a different order
KVPs . Sort ( [ ] ( const KVPType & Lhs , const KVPType & Rhs ) { return Lhs . Key < Rhs . Key ; } ) ;
2015-11-18 16:20:49 -05:00
for ( const KVPType & KVP : KVPs )
2014-03-14 14:13:41 -04:00
{
Result + = FString : : Printf ( TEXT ( " %sMetaData->SetValue(%s, TEXT( \" %s \" ), %s); \r \n " ) , Spaces , SymbolName , * KVP . Key . ToString ( ) , * CreateLiteralString ( KVP . Value ) ) ;
}
}
return Result ;
}
/**
* Exports the struct ' s C + + properties to the specified output device and adds special
* compiler directives for GCC to pack as we expect .
*
* @ param Struct UStruct to export properties
* @ param TextIndent Current text indentation
* @ param ImportsDefaults whether this struct will be serialized with a default value
*/
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportProperties ( UStruct * Struct , int32 TextIndent , bool bAccessSpecifiers , FUHTStringBuilder * Output )
2014-03-14 14:13:41 -04:00
{
UProperty * Previous = NULL ;
UProperty * PreviousNonEditorOnly = NULL ;
UProperty * LastInSuper = NULL ;
UStruct * InheritanceSuper = Struct - > GetInheritanceSuper ( ) ;
bool bEmittedHasEditorOnlyMacro = false ;
bool bEmittedHasScriptAlign = false ;
2015-03-27 18:10:52 -04:00
check ( Output ! = NULL ) ;
FUHTStringBuilder & HeaderOutput = * Output ;
2014-03-14 14:13:41 -04:00
// Find last property in the lowest base class that has any properties
UStruct * CurrentSuper = InheritanceSuper ;
while ( LastInSuper = = NULL & & CurrentSuper )
{
for ( TFieldIterator < UProperty > It ( CurrentSuper , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
{
UProperty * Current = * It ;
// Disregard properties with 0 size like functions.
if ( It . GetStruct ( ) = = CurrentSuper & & Current - > ElementSize )
{
LastInSuper = Current ;
}
}
// go up a layer in the hierarchy
CurrentSuper = CurrentSuper - > GetSuperStruct ( ) ;
}
EPropertyHeaderExportFlags CurrentExportType = PROPEXPORT_Public ;
// find structs that are nothing but bytes, account for editor only properties being
// removed on consoles
int32 NumProperties = 0 ;
int32 NumByteProperties = 0 ;
int32 NumNonEditorOnlyProperties = 0 ;
int32 NumNonEditorOnlyByteProperties = 0 ;
for ( TFieldIterator < UProperty > It ( Struct , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
{
// treat bitfield and bytes the same
bool bIsByteProperty = It - > IsA ( UByteProperty : : StaticClass ( ) ) ; // || It->IsA(UBoolProperty::StaticClass());
bool bIsEditorOnlyProperty = It - > IsEditorOnlyProperty ( ) ;
// count our propertie
NumProperties + + ;
if ( bIsByteProperty )
{
2014-04-02 18:09:23 -04:00
NumByteProperties + + ;
2014-03-14 14:13:41 -04:00
}
if ( ! bIsEditorOnlyProperty )
{
NumNonEditorOnlyProperties + + ;
}
if ( ! bIsEditorOnlyProperty & & bIsByteProperty )
{
NumNonEditorOnlyByteProperties + + ;
}
}
bool bCurrentlyInNotCPPBlock = false ;
// Iterate over all properties in this struct.
for ( TFieldIterator < UProperty > It ( Struct , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
{
UProperty * Current = * It ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder PropertyText ;
2014-03-14 14:13:41 -04:00
// Disregard properties with 0 size like functions.
if ( It . GetStruct ( ) = = Struct )
{
FString AccessSpecifier = TEXT ( " public " ) ;
if ( bAccessSpecifiers )
{
// find the class info for this class
2015-01-20 09:33:54 -05:00
FClassMetaData * ClassData = GScriptHelper . FindClassData ( Struct ) ;
2015-04-30 10:25:31 -04:00
check ( ClassData ) ;
2014-03-14 14:13:41 -04:00
// find the compiler token for this property
FTokenData * PropData = ClassData - > FindTokenData ( Current ) ;
if ( PropData ! = NULL )
{
// if this property has a different access specifier, then export that now
if ( ( PropData - > Token . PropertyExportFlags & CurrentExportType ) = = 0 )
{
if ( ( PropData - > Token . PropertyExportFlags & PROPEXPORT_Private ) ! = 0 )
{
CurrentExportType = PROPEXPORT_Private ;
AccessSpecifier = TEXT ( " private " ) ;
}
else if ( ( PropData - > Token . PropertyExportFlags & PROPEXPORT_Protected ) ! = 0 )
{
CurrentExportType = PROPEXPORT_Protected ;
AccessSpecifier = TEXT ( " protected " ) ;
}
else
{
CurrentExportType = PROPEXPORT_Public ;
AccessSpecifier = TEXT ( " public " ) ;
}
if ( AccessSpecifier . Len ( ) )
{
// If we are changing the access specifier we need to emit the #endif for the WITH_EDITORONLY_DATA macro first otherwise the access specifier may
// only be conditionally compiled in.
if ( bEmittedHasEditorOnlyMacro )
{
PropertyText . Logf ( TEXT ( " #endif // WITH_EDITORONLY_DATA \r \n " ) ) ;
bEmittedHasEditorOnlyMacro = false ;
}
2015-03-27 18:10:52 -04:00
PropertyText . Logf ( TEXT ( " %s: " ) LINE_TERMINATOR , * AccessSpecifier ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
// If we are switching from editor to non-editor or vice versa and the state of the WITH_EDITORONLY_DATA macro emission doesn't match, generate the
// #if or #endif appropriately.
bool RequiresHasEditorOnlyMacro = Current - > IsEditorOnlyProperty ( ) ;
if ( ! bEmittedHasEditorOnlyMacro & & RequiresHasEditorOnlyMacro )
{
// Indent code and export CPP text.
PropertyText . Logf ( TEXT ( " #if WITH_EDITORONLY_DATA \r \n " ) ) ;
bEmittedHasEditorOnlyMacro = true ;
}
else if ( bEmittedHasEditorOnlyMacro & & ! RequiresHasEditorOnlyMacro )
{
PropertyText . Logf ( TEXT ( " #endif // WITH_EDITORONLY_DATA \r \n " ) ) ;
bEmittedHasEditorOnlyMacro = false ;
}
// Export property specifiers
// Indent code and export CPP text.
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder JustPropertyDecl ;
2014-03-14 14:13:41 -04:00
const FString * Dim = GArrayDimensions . Find ( Current ) ;
Current - > ExportCppDeclaration ( JustPropertyDecl , EExportedDeclaration : : Member , Dim ? * * Dim : NULL ) ;
ApplyAlternatePropertyExportText ( * It , JustPropertyDecl ) ;
// Finish up line.
2015-09-21 07:53:49 -04:00
PropertyText . Logf ( TEXT ( " %s%s; \r \n " ) , FCString : : Tab ( TextIndent + 1 ) , * JustPropertyDecl ) ;
2014-03-14 14:13:41 -04:00
}
LastInSuper = NULL ;
2015-03-27 18:10:52 -04:00
Previous = Current ;
2014-03-14 14:13:41 -04:00
if ( ! Current - > IsEditorOnlyProperty ( ) )
{
PreviousNonEditorOnly = Current ;
}
HeaderOutput . Log ( PropertyText ) ;
}
}
if ( bCurrentlyInNotCPPBlock )
{
2015-03-27 18:10:52 -04:00
HeaderOutput + = TEXT ( " #endif \r \n " ) ;
2014-03-14 14:13:41 -04:00
bCurrentlyInNotCPPBlock = false ;
}
// End of property list. If we haven't generated the WITH_EDITORONLY_DATA #endif, do so now.
if ( bEmittedHasEditorOnlyMacro )
{
2015-03-27 18:10:52 -04:00
HeaderOutput + = TEXT ( " #endif // WITH_EDITORONLY_DATA \r \n " ) ;
2014-03-14 14:13:41 -04:00
}
// if the last property that was exported wasn't public, emit a line to reset the access to "public" so that we don't interfere with cpptext
2015-03-27 18:10:52 -04:00
if ( CurrentExportType ! = PROPEXPORT_Public )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
HeaderOutput + = TEXT ( " public: " ) LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
}
}
2015-05-22 02:54:27 -04:00
/**
* Class that is representing a type singleton .
*/
struct FTypeSingleton
2014-03-14 14:13:41 -04:00
{
2015-05-22 02:54:27 -04:00
public :
/** Constructor */
FTypeSingleton ( FString InName , UField * InType )
: Name ( MoveTemp ( InName ) ) , Type ( InType ) { }
2014-06-02 07:02:29 -04:00
2015-05-22 02:54:27 -04:00
/**
* Gets this singleton ' s name .
*/
const FString & GetName ( ) const
{
return Name ;
2014-03-14 14:13:41 -04:00
}
2015-05-22 02:54:27 -04:00
/**
* Gets this singleton ' s extern declaration .
*/
const FString & GetExternDecl ( ) const
2014-03-14 14:13:41 -04:00
{
2015-05-22 02:54:27 -04:00
if ( ExternDecl . IsEmpty ( ) )
2014-03-14 14:13:41 -04:00
{
2015-05-22 02:54:27 -04:00
ExternDecl = GenerateExternDecl ( Type , GetName ( ) ) ;
}
return ExternDecl ;
}
private :
/**
* Extern declaration generator .
*/
static FString GenerateExternDecl ( UField * InType , const FString & InName )
{
const TCHAR * FormatStr = nullptr ;
if ( InType - > GetClass ( ) = = UClass : : StaticClass ( ) )
{
2015-09-21 07:53:49 -04:00
FormatStr = TEXT ( " \t %s_API class UClass* %s; \r \n " ) ;
2015-05-22 02:54:27 -04:00
}
else if ( InType - > GetClass ( ) = = UFunction : : StaticClass ( ) | | InType - > GetClass ( ) = = UDelegateFunction : : StaticClass ( ) )
{
2015-09-21 07:53:49 -04:00
FormatStr = TEXT ( " \t %s_API class UFunction* %s; \r \n " ) ;
2015-05-22 02:54:27 -04:00
}
else if ( InType - > GetClass ( ) = = UScriptStruct : : StaticClass ( ) )
{
2015-09-21 07:53:49 -04:00
FormatStr = TEXT ( " \t %s_API class UScriptStruct* %s; \r \n " ) ;
2015-05-22 02:54:27 -04:00
}
else if ( InType - > GetClass ( ) = = UEnum : : StaticClass ( ) )
{
2015-09-21 07:53:49 -04:00
FormatStr = TEXT ( " \t %s_API class UEnum* %s; \r \n " ) ;
2015-05-22 02:54:27 -04:00
}
else
{
FError : : Throwf ( TEXT ( " Unsupported item type to get extern for. " ) ) ;
}
return FString : : Printf ( FormatStr ,
* FPackageName : : GetShortName ( InType - > GetOutermost ( ) ) . ToUpper ( ) ,
* InName ) ;
}
/** Field that stores this singleton name. */
FString Name ;
/** Cached field that stores this singleton extern declaration. */
mutable FString ExternDecl ;
/** Type of the singleton */
UField * Type ;
} ;
/**
* Class that represents type singleton cache .
*/
class FTypeSingletonCache
{
public :
/**
* Gets type singleton from cache .
*
* @ param Type Singleton type .
* @ param bRequiresValidObject Does it require a valid object ?
*/
static const FTypeSingleton & Get ( UField * Type , bool bRequiresValidObject = true )
{
static TMap < FTypeSingletonCacheKey , FTypeSingleton > CacheData ;
FTypeSingletonCacheKey Key ( Type , bRequiresValidObject ) ;
if ( FTypeSingleton * SingletonPtr = CacheData . Find ( Key ) )
{
return * SingletonPtr ;
}
return CacheData . Add ( Key ,
FTypeSingleton ( GenerateSingletonName ( Type , bRequiresValidObject ) , Type )
) ;
}
private :
/**
* Private type that represents cache map key .
*/
struct FTypeSingletonCacheKey
{
/** FTypeSingleton type */
UField * Type ;
/** If this type singleton requires valid object. */
bool bRequiresValidObject ;
/* Constructor */
FTypeSingletonCacheKey ( UField * InType , bool bInRequiresValidObject )
: Type ( InType ) , bRequiresValidObject ( bInRequiresValidObject )
{ }
/**
* Equality operator .
*
* @ param Other Other key .
*
* @ returns True if this is equal to Other . False otherwise .
*/
bool operator = = ( const FTypeSingletonCacheKey & Other ) const
{
return Type = = Other . Type & & bRequiresValidObject = = Other . bRequiresValidObject ;
}
/**
* Gets hash value for this object .
*/
friend uint32 GetTypeHash ( const FTypeSingletonCacheKey & Object )
{
return HashCombine (
GetTypeHash ( Object . Type ) ,
GetTypeHash ( Object . bRequiresValidObject )
) ;
}
} ;
/**
* Generates singleton name .
*/
static FString GenerateSingletonName ( UField * Item , bool bRequiresValidObject )
{
FString Suffix ;
if ( UClass * ItemClass = Cast < UClass > ( Item ) )
{
if ( ItemClass - > HasAllClassFlags ( CLASS_Intrinsic ) )
2014-03-14 14:13:41 -04:00
{
2015-05-22 02:54:27 -04:00
return FString : : Printf ( TEXT ( " %s::StaticClass() " ) , NameLookupCPP . GetNameCPP ( ItemClass ) ) ;
}
if ( ! bRequiresValidObject & & ItemClass - > HasAllClassFlags ( CLASS_Native ) )
{
Suffix = TEXT ( " _NoRegister " ) ;
}
}
FString Result ;
for ( UObject * Outer = Item ; Outer ; Outer = Outer - > GetOuter ( ) )
{
if ( ! Result . IsEmpty ( ) )
{
Result = TEXT ( " _ " ) + Result ;
}
if ( Cast < UClass > ( Outer ) | | Cast < UScriptStruct > ( Outer ) )
{
FString OuterName = NameLookupCPP . GetNameCPP ( Cast < UStruct > ( Outer ) ) ;
Result = OuterName + Result ;
// Structs can also have UPackage outer.
if ( Cast < UClass > ( Outer ) | | Cast < UPackage > ( Outer - > GetOuter ( ) ) )
{
break ;
}
2014-03-14 14:13:41 -04:00
}
else
{
2015-05-22 02:54:27 -04:00
Result = Outer - > GetName ( ) + Result ;
2014-03-14 14:13:41 -04:00
}
}
2015-05-22 02:54:27 -04:00
// Can't use long package names in function names.
if ( Result . StartsWith ( TEXT ( " /Script/ " ) , ESearchCase : : CaseSensitive ) )
2014-03-14 14:13:41 -04:00
{
2015-05-22 02:54:27 -04:00
Result = FPackageName : : GetShortName ( Result ) ;
2014-03-14 14:13:41 -04:00
}
2015-05-22 02:54:27 -04:00
FString ClassString = NameLookupCPP . GetNameCPP ( Item - > GetClass ( ) ) ;
return FString ( TEXT ( " Z_Construct_ " ) ) + ClassString + TEXT ( " _ " ) + Result + Suffix + TEXT ( " () " ) ;
}
} ;
FString FNativeClassHeaderGenerator : : GetSingletonName ( UField * Item , bool bRequiresValidObject )
{
FString Result = FTypeSingletonCache : : Get ( Item , bRequiresValidObject ) . GetName ( ) ;
UClass * ItemClass = Cast < UClass > ( Item ) ;
if ( ItemClass ! = nullptr & & ItemClass - > HasAllClassFlags ( CLASS_Intrinsic ) )
{
return Result ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
2014-03-14 14:13:41 -04:00
if ( CastChecked < UPackage > ( Item - > GetOutermost ( ) ) ! = Package )
{
// this is a cross module reference, we need to include the right extern decl
2015-05-22 02:54:27 -04:00
FString Extern = FTypeSingletonCache : : Get ( Item , bRequiresValidObject ) . GetExternDecl ( ) ;
2014-03-14 14:13:41 -04:00
2015-05-22 02:54:27 -04:00
bool bAlreadyInSet = false ;
UniqueCrossModuleReferences . Add ( * Extern , & bAlreadyInSet ) ;
if ( ! bAlreadyInSet )
{
CrossModuleGeneratedFunctionDeclarations . Log ( * Extern ) ;
2014-03-14 14:13:41 -04:00
}
}
return Result ;
}
2014-06-02 07:02:29 -04:00
FString FNativeClassHeaderGenerator : : GetSingletonName ( FClass * Item , bool bRequiresValidObject )
{
return GetSingletonName ( ( UClass * ) Item , bRequiresValidObject ) ;
}
2015-09-09 14:07:28 -04:00
FString FNativeClassHeaderGenerator : : GetOverriddenName ( const UField * Item )
{
FString OverriddenName = Item - > GetMetaData ( TEXT ( " OverrideNativeName " ) ) ;
if ( ! OverriddenName . IsEmpty ( ) )
{
return OverriddenName ;
}
return Item - > GetName ( ) ;
}
2015-09-28 14:27:23 -04:00
FString FNativeClassHeaderGenerator : : GetOverriddenNameForLiteral ( const UField * Item )
{
FString OverriddenName = Item - > GetMetaData ( TEXT ( " OverrideNativeName " ) ) ;
if ( ! OverriddenName . IsEmpty ( ) )
{
return TEXT ( " TEXT( \" " ) + OverriddenName + TEXT ( " \" ) " ) ;
}
return TEXT ( " \" " ) + Item - > GetName ( ) + TEXT ( " \" " ) ;
}
2014-03-14 14:13:41 -04:00
FString FNativeClassHeaderGenerator : : PropertyNew ( FString & Meta , UProperty * Prop , const FString & OuterString , const FString & PropMacro , const TCHAR * NameSuffix , const TCHAR * Spaces , const TCHAR * SourceStruct )
{
FString ExtraArgs ;
2014-07-29 02:43:48 -04:00
FString GeneratedCrc ;
2014-03-14 14:13:41 -04:00
FString PropNameDep = Prop - > GetName ( ) ;
if ( Prop - > HasAllPropertyFlags ( CPF_Deprecated ) )
{
PropNameDep + = TEXT ( " _DEPRECATED " ) ;
}
if ( UObjectPropertyBase * ObjectProperty = Cast < UObjectPropertyBase > ( Prop ) )
{
UClass * TargetClass = ObjectProperty - > PropertyClass ;
if ( UClassProperty * ClassProperty = Cast < UClassProperty > ( Prop ) )
{
TargetClass = ClassProperty - > MetaClass ;
}
if ( UAssetClassProperty * SubclassOfProperty = Cast < UAssetClassProperty > ( Prop ) )
{
TargetClass = SubclassOfProperty - > MetaClass ;
}
ExtraArgs = FString : : Printf ( TEXT ( " , %s " ) , * GetSingletonName ( TargetClass , false ) ) ;
}
else if ( UInterfaceProperty * InterfaceProperty = Cast < UInterfaceProperty > ( Prop ) )
{
UClass * TargetClass = InterfaceProperty - > InterfaceClass ;
ExtraArgs = FString : : Printf ( TEXT ( " , %s " ) , * GetSingletonName ( TargetClass , false ) ) ;
}
else if ( UStructProperty * StructProperty = Cast < UStructProperty > ( Prop ) )
{
UScriptStruct * Struct = StructProperty - > Struct ;
check ( Struct ) ;
ExtraArgs = FString : : Printf ( TEXT ( " , %s " ) , * GetSingletonName ( Struct ) ) ;
}
else if ( UByteProperty * ByteProperty = Cast < UByteProperty > ( Prop ) )
{
if ( ByteProperty - > Enum )
{
ExtraArgs = FString : : Printf ( TEXT ( " , %s " ) , * GetSingletonName ( ByteProperty - > Enum ) ) ;
}
}
else if ( UBoolProperty * BoolProperty = Cast < UBoolProperty > ( Prop ) )
{
if ( Cast < UArrayProperty > ( BoolProperty - > GetOuter ( ) ) )
{
ExtraArgs = FString ( TEXT ( " , 0 " ) ) ; // this is an array of C++ bools so the mask is irrelevant.
}
else
{
check ( SourceStruct ) ;
ExtraArgs = FString : : Printf ( TEXT ( " , CPP_BOOL_PROPERTY_BITMASK(%s, %s) " ) , * PropNameDep , SourceStruct ) ;
}
ExtraArgs + = FString : : Printf ( TEXT ( " , sizeof(%s), %s " ) , * BoolProperty - > GetCPPType ( NULL , 0 ) , BoolProperty - > IsNativeBool ( ) ? TEXT ( " true " ) : TEXT ( " false " ) ) ;
}
else if ( UDelegateProperty * DelegateProperty = Cast < UDelegateProperty > ( Prop ) )
{
UFunction * TargetFunction = DelegateProperty - > SignatureFunction ;
ExtraArgs = FString : : Printf ( TEXT ( " , %s " ) , * GetSingletonName ( TargetFunction ) ) ;
}
else if ( UMulticastDelegateProperty * MulticastDelegateProperty = Cast < UMulticastDelegateProperty > ( Prop ) )
{
UFunction * TargetFunction = MulticastDelegateProperty - > SignatureFunction ;
ExtraArgs = FString : : Printf ( TEXT ( " , %s " ) , * GetSingletonName ( TargetFunction ) ) ;
}
2015-11-18 16:20:49 -05:00
FString Constructor = FString : : Printf ( TEXT ( " new(EC_InternalUseOnlyConstructor, %s, TEXT( \" %s \" ), RF_Public|RF_Transient|RF_MarkAsNative) U%s(%s, 0x%016llx%s); " ) ,
2014-03-14 14:13:41 -04:00
* OuterString ,
2015-09-09 14:07:28 -04:00
* FNativeClassHeaderGenerator : : GetOverriddenName ( Prop ) ,
2014-03-14 14:13:41 -04:00
* Prop - > GetClass ( ) - > GetName ( ) ,
* PropMacro ,
Prop - > PropertyFlags & ~ CPF_ComputedFlags ,
* ExtraArgs ) ;
TheFlagAudit . Add ( Prop , TEXT ( " PropertyFlags " ) , Prop - > PropertyFlags ) ;
FString Symbol = FString : : Printf ( TEXT ( " NewProp_%s%s " ) , * Prop - > GetName ( ) , NameSuffix ) ;
2014-07-29 02:43:48 -04:00
FString Lines = FString : : Printf ( TEXT ( " %sUProperty* %s = %s%s \r \n " ) ,
2014-03-14 14:13:41 -04:00
Spaces ,
* Symbol ,
2014-07-29 02:43:48 -04:00
* Constructor ,
2014-10-30 09:53:47 -04:00
* GetGeneratedCodeCRCTag ( Prop ) ) ;
2014-03-14 14:13:41 -04:00
if ( Prop - > ArrayDim ! = 1 )
{
Lines + = FString : : Printf ( TEXT ( " %s%s->ArrayDim = CPP_ARRAY_DIM(%s, %s); \r \n " ) , Spaces , * Symbol , * PropNameDep , SourceStruct ) ;
}
if ( Prop - > RepNotifyFunc ! = NAME_None )
{
Lines + = FString : : Printf ( TEXT ( " %s%s->RepNotifyFunc = FName(TEXT( \" %s \" )); \r \n " ) , Spaces , * Symbol , * Prop - > RepNotifyFunc . ToString ( ) ) ;
}
Meta + = GetMetaDataCodeForObject ( Prop , * Symbol , Spaces ) ;
return Lines ;
}
void FNativeClassHeaderGenerator : : OutputProperties ( FString & Meta , FOutputDevice & OutputDevice , const FString & OuterString , TArray < UProperty * > & Properties , const TCHAR * Spaces )
{
bool bEmittedHasEditorOnlyMacro = false ;
for ( int32 Index = Properties . Num ( ) - 1 ; Index > = 0 ; Index - - )
{
bool RequiresHasEditorOnlyMacro = Properties [ Index ] - > IsEditorOnlyProperty ( ) ;
if ( ! bEmittedHasEditorOnlyMacro & & RequiresHasEditorOnlyMacro )
{
// Indent code and export CPP text.
OutputDevice . Logf ( TEXT ( " #if WITH_EDITORONLY_DATA \r \n " ) ) ;
bEmittedHasEditorOnlyMacro = true ;
}
else if ( bEmittedHasEditorOnlyMacro & & ! RequiresHasEditorOnlyMacro )
{
OutputDevice . Logf ( TEXT ( " #endif // WITH_EDITORONLY_DATA \r \n " ) ) ;
bEmittedHasEditorOnlyMacro = false ;
}
2014-11-06 15:16:05 -05:00
OutputProperty ( Meta , OutputDevice , OuterString , Properties [ Index ] , Spaces ) ;
2014-03-14 14:13:41 -04:00
}
if ( bEmittedHasEditorOnlyMacro )
{
OutputDevice . Logf ( TEXT ( " #endif // WITH_EDITORONLY_DATA \r \n " ) ) ;
}
}
2015-01-20 09:33:54 -05:00
inline FString GetEventStructParamsName ( UObject * Outer , const TCHAR * FunctionName )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
FString OuterName ;
if ( Outer - > IsA < UClass > ( ) )
{
OuterName = ( ( UClass * ) Outer ) - > GetName ( ) ;
}
else if ( Outer - > IsA < UPackage > ( ) )
{
2015-03-27 18:10:52 -04:00
OuterName = ( ( UPackage * ) Outer ) - > GetName ( ) ;
OuterName . ReplaceInline ( TEXT ( " / " ) , TEXT ( " _ " ) , ESearchCase : : CaseSensitive ) ;
2015-01-20 09:33:54 -05:00
}
else
{
FError : : Throwf ( TEXT ( " Unrecognized outer type " ) ) ;
}
FString Result = FString : : Printf ( TEXT ( " %s_event%s_Parms " ) , * OuterName , FunctionName ) ;
2014-03-14 14:13:41 -04:00
return Result ;
}
void FNativeClassHeaderGenerator : : OutputProperty ( FString & Meta , FOutputDevice & OutputDevice , const FString & OuterString , UProperty * Prop , const TCHAR * Spaces )
{
{
FString SourceStruct ;
UFunction * Function = Cast < UFunction > ( Prop - > GetOuter ( ) ) ;
if ( Function )
{
while ( Function - > GetSuperFunction ( ) )
{
Function = Function - > GetSuperFunction ( ) ;
}
FString FunctionName = Function - > GetName ( ) ;
if ( Function - > HasAnyFunctionFlags ( FUNC_Delegate ) )
{
FunctionName = FunctionName . LeftChop ( FString ( HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX ) . Len ( ) ) ;
}
2015-01-20 09:33:54 -05:00
SourceStruct = GetEventStructParamsName ( Function - > GetOuter ( ) , * FunctionName ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-06-02 07:02:29 -04:00
SourceStruct = NameLookupCPP . GetNameCPP ( CastChecked < UStruct > ( Prop - > GetOuter ( ) ) ) ;
2014-03-14 14:13:41 -04:00
}
FString PropMacroOuterClass ;
FString PropNameDep = Prop - > GetName ( ) ;
if ( Prop - > HasAllPropertyFlags ( CPF_Deprecated ) )
{
PropNameDep + = TEXT ( " _DEPRECATED " ) ;
}
UBoolProperty * BoolProperty = Cast < UBoolProperty > ( Prop ) ;
if ( BoolProperty )
{
OutputDevice . Logf ( TEXT ( " %sCPP_BOOL_PROPERTY_BITMASK_STRUCT(%s, %s, %s); \r \n " ) ,
Spaces ,
* PropNameDep ,
* SourceStruct ,
* BoolProperty - > GetCPPType ( NULL , 0 ) ) ;
2014-10-14 10:29:11 -04:00
PropMacroOuterClass = FString : : Printf ( TEXT ( " FObjectInitializer(), EC_CppProperty, CPP_BOOL_PROPERTY_OFFSET(%s, %s) " ) ,
2014-03-14 14:13:41 -04:00
* PropNameDep , * SourceStruct ) ;
}
else
{
PropMacroOuterClass = FString : : Printf ( TEXT ( " CPP_PROPERTY_BASE(%s, %s) " ) , * PropNameDep , * SourceStruct ) ;
}
OutputDevice . Log ( * PropertyNew ( Meta , Prop , OuterString , PropMacroOuterClass , TEXT ( " " ) , Spaces , * SourceStruct ) ) ;
}
2015-04-21 10:25:59 -04:00
if ( UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( Prop ) )
2014-03-14 14:13:41 -04:00
{
FString InnerOuterString = FString : : Printf ( TEXT ( " NewProp_%s " ) , * Prop - > GetName ( ) ) ;
2014-10-14 10:29:11 -04:00
FString PropMacroOuterArray = TEXT ( " FObjectInitializer(), EC_CppProperty, 0 " ) ;
2014-03-14 14:13:41 -04:00
OutputDevice . Log ( * PropertyNew ( Meta , ArrayProperty - > Inner , InnerOuterString , PropMacroOuterArray , TEXT ( " _Inner " ) , Spaces ) ) ;
}
2015-04-21 10:25:59 -04:00
if ( UMapProperty * MapProperty = Cast < UMapProperty > ( Prop ) )
{
FString InnerOuterString = FString : : Printf ( TEXT ( " NewProp_%s " ) , * Prop - > GetName ( ) ) ;
FString PropMacroOuterMap = TEXT ( " FObjectInitializer(), EC_CppProperty, " ) ;
OutputDevice . Log ( * PropertyNew ( Meta , MapProperty - > KeyProp , InnerOuterString , PropMacroOuterMap + TEXT ( " 0 " ) , TEXT ( " _KeyProp " ) , Spaces ) ) ;
OutputDevice . Log ( * PropertyNew ( Meta , MapProperty - > ValueProp , InnerOuterString , PropMacroOuterMap + TEXT ( " 1 " ) , TEXT ( " _ValueProp " ) , Spaces ) ) ;
}
2014-03-14 14:13:41 -04:00
}
static FString BackSlashAndIndent ( const FString & Text )
{
2015-09-21 07:53:49 -04:00
FString Trailer ( TEXT ( " \t \\ \r \n \t " ) ) ;
FString Result = FString ( TEXT ( " \t " ) ) + Text . Replace ( TEXT ( " \r \n " ) , * Trailer , ESearchCase : : CaseSensitive ) ;
2014-03-14 14:13:41 -04:00
return Result . LeftChop ( Trailer . Len ( ) ) + TEXT ( " \r \n " ) ;
}
static bool IsAlwaysAccessible ( UScriptStruct * Script )
{
FName ToTest = Script - > GetFName ( ) ;
if ( ToTest = = NAME_Matrix )
{
return false ; // special case, the C++ FMatrix does not have the same members.
}
bool Result = Script - > HasDefaults ( ) ; // if we have cpp struct ops in it for UHT, then we can assume it is always accessible
if ( ToTest = = NAME_Plane
| | ToTest = = NAME_Vector
| | ToTest = = NAME_Vector4
| | ToTest = = NAME_Quat
| | ToTest = = NAME_Color
)
{
check ( Result ) ;
}
return Result ;
}
static void FindNoExportStructs ( TArray < UScriptStruct * > & Structs , UStruct * Start )
{
while ( Start )
{
if ( UScriptStruct * StartScript = Cast < UScriptStruct > ( Start ) )
{
if ( StartScript - > StructFlags & STRUCT_Native )
{
break ;
}
if ( ! IsAlwaysAccessible ( StartScript ) ) // these are a special cases that already exists and if wrong if exported nievely
{
// this will topologically sort them in reverse order
Structs . Remove ( StartScript ) ;
Structs . Add ( StartScript ) ;
}
}
2015-04-21 10:25:59 -04:00
for ( UProperty * Prop : TFieldRange < UProperty > ( Start , EFieldIteratorFlags : : ExcludeSuper ) )
2014-03-14 14:13:41 -04:00
{
2015-04-21 10:25:59 -04:00
if ( UStructProperty * StructProp = Cast < UStructProperty > ( Prop ) )
2014-03-14 14:13:41 -04:00
{
2015-04-21 10:25:59 -04:00
FindNoExportStructs ( Structs , StructProp - > Struct ) ;
2014-03-14 14:13:41 -04:00
}
2015-04-21 10:25:59 -04:00
else if ( UArrayProperty * ArrayProp = Cast < UArrayProperty > ( Prop ) )
2014-03-14 14:13:41 -04:00
{
2015-04-21 10:25:59 -04:00
if ( UStructProperty * InnerStructProp = Cast < UStructProperty > ( ArrayProp - > Inner ) )
{
FindNoExportStructs ( Structs , InnerStructProp - > Struct ) ;
}
}
else if ( UMapProperty * MapProp = Cast < UMapProperty > ( Prop ) )
{
if ( UStructProperty * KeyStructProp = Cast < UStructProperty > ( MapProp - > KeyProp ) )
{
FindNoExportStructs ( Structs , KeyStructProp - > Struct ) ;
}
if ( UStructProperty * ValueStructProp = Cast < UStructProperty > ( MapProp - > ValueProp ) )
{
FindNoExportStructs ( Structs , ValueStructProp - > Struct ) ;
}
2014-03-14 14:13:41 -04:00
}
}
Start = Start - > GetSuperStruct ( ) ;
}
}
2015-11-18 16:20:49 -05:00
FString GetPackageSingletonName ( const UPackage * Package )
2014-03-14 14:13:41 -04:00
{
2014-06-02 07:02:29 -04:00
static FString ClassString = NameLookupCPP . GetNameCPP ( UPackage : : StaticClass ( ) ) ;
2015-11-18 16:20:49 -05:00
return FString ( TEXT ( " Z_Construct_ " ) ) + ClassString + TEXT ( " _ " ) + Package - > GetName ( ) . Replace ( TEXT ( " / " ) , TEXT ( " _ " ) ) + TEXT ( " () " ) ;
2014-03-14 14:13:41 -04:00
}
2015-11-18 16:20:49 -05:00
void FNativeClassHeaderGenerator : : ExportGeneratedPackageInitCode ( const UPackage * InPackage )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
FString ApiString = GetAPIString ( ) ;
2015-04-22 14:15:56 -04:00
FString SingletonName ( GetPackageSingletonName ( InPackage ) ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
FUHTStringBuilder & GeneratedFunctionText = GetGeneratedFunctionTextDevice ( ) ;
2014-03-14 14:13:41 -04:00
2015-09-21 07:53:49 -04:00
GeneratedFunctionDeclarations . Logf ( TEXT ( " \t %sclass UPackage* %s; \r \n " ) , * ApiString , * SingletonName ) ;
2014-03-14 14:13:41 -04:00
2015-09-21 07:53:49 -04:00
GeneratedFunctionText . Logf ( TEXT ( " \t UPackage* %s \r \n " ) , * SingletonName ) ;
GeneratedFunctionText . Logf ( TEXT ( " \t { \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " \t \t static UPackage* ReturnPackage = NULL; \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " \t \t if (!ReturnPackage) \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " \t \t { \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " \t \t \t ReturnPackage = CastChecked<UPackage>(StaticFindObjectFast(UPackage::StaticClass(), NULL, FName(TEXT( \" %s \" )), false, false)); \r \n " ) , * InPackage - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
2015-09-21 07:53:49 -04:00
FString Meta = GetMetaDataCodeForObject ( InPackage , TEXT ( " ReturnPackage " ) , TEXT ( " \t \t \t " ) ) ;
2014-03-14 14:13:41 -04:00
if ( Meta . Len ( ) )
{
GeneratedFunctionText . Logf ( TEXT ( " #if WITH_METADATA \r \n " ) ) ;
2015-09-21 07:53:49 -04:00
GeneratedFunctionText . Logf ( TEXT ( " \t \t \t UMetaData* MetaData = ReturnPackage->GetMetaData(); \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
GeneratedFunctionText . Log ( * Meta ) ;
GeneratedFunctionText . Logf ( TEXT ( " #endif \r \n " ) ) ;
}
Copying //UE4/Dev-Framework to Dev-Main (//UE4/Dev-Main)
#lockdown Nick.Penwarden
==========================
MAJOR FEATURES + CHANGES
==========================
Change 2720406 on 2015/10/07 by Aaron.McLeran
Audio optimization
Don't search for nearest listener if there's only 1 listener.
Change 2720411 on 2015/10/07 by Aaron.McLeran
Fixing HRTF spatialization code with recent changes to stereo spatialization.
HRTF emitter posiition doesn't need to be converted to XAudio2 coordinates.
Change 2723829 on 2015/10/09 by Mieszko.Zielinski
Fixed NavigationSystem trying to set label of newly spawned navigation data #UE4
UE-21880
Change 2723873 on 2015/10/09 by Mieszko.Zielinski
Fixed a bug in FNavAgentProperties::IsEquivalent resulting in failing the test for FNavAgentProperties instances having default AgentStepHeight value (-1) #UE4
UE-21977
Change 2724834 on 2015/10/12 by Ori.Cohen
PR #1634: Add PxVehicleDriveNW support to PhysXVehicleManager.cpp (Contributed by zeduk)
Change 2724850 on 2015/10/12 by Marc.Audy
Fix sound not restarting in matinee preview when jumping back along timeline after reaching end
#codereview Nick.Darnell
Change 2726499 on 2015/10/13 by Ori.Cohen
Fix edge case where sphyl length and radius are 0 and they are not properly clamped to 0.1
Change 2726689 on 2015/10/13 by Marc.Audy
Make UPackage::PackageFlags private
Add debugging for UE-21181 to try and track down when EditorWorld's PackageFlags are getting flagged as PlayInEditor
#codereview Mike.Fricker
Change 2726862 on 2015/10/13 by Lukasz.Furman
removed unused code from DetourNavMeshQuery
#ue4 UE-21988
Change 2726888 on 2015/10/13 by Lukasz.Furman
fixed observer abort: both mode in behavior tree's cone check decorator
#ue4 UE-19375
Change 2726913 on 2015/10/13 by Lukasz.Furman
navmesh raycast will use nearest poly containing ray origin instead of just closest one
#ue4 UE-19334
Change 2726920 on 2015/10/13 by Marc.Audy
Re-unify ULevelStreaming::GetWorldAssetPackageName and GetWorldAssetPackageFName
#codereview Dmitriy.Dyomin, Bob.Tellez
Change 2726931 on 2015/10/13 by Lukasz.Furman
fixed missing Tick event in aborting behavior tree tasks from abandoned subtree
#ue4 UE-21777
Change 2728093 on 2015/10/14 by Ori.Cohen
Fix edge case of sphyl scale take two. The previous approach did double scaling
Change 2728577 on 2015/10/14 by Mieszko.Zielinski
Improved navmesh labeling condition #UE4
Change suggested by github user
#rb Lukasz.Furman
Change 2728587 on 2015/10/14 by Lukasz.Furman
fixed crowd simulation for auto possessed pawns placed on level
#ue4
#rb Mieszko.Zielinski
Change 2728629 on 2015/10/14 by Lukasz.Furman
fixed influence of navmesh edges on crowd simulation near end of path
#ue4 UE-21380
#rb Mieszko.Zielinski
Change 2728678 on 2015/10/14 by Lukasz.Furman
added Z check to detour's crowd avoidance segment gathering
#ue4 UE-20889
#rb Mieszko.Zielinski
Change 2728745 on 2015/10/14 by Lukasz.Furman
fixed copy&paste operation in behavior tree's composite decorators subgraphs
#ue4 UE-18740
Change 2729276 on 2015/10/14 by Stan.Melax
ensure all actors get recreated with new collision shape specification.
this wasn't being done for a couple of editing methods.
todo: this should be merged into 4.10
#UE-20961
#rb ori.cohen
Change 2730709 on 2015/10/15 by Marc.Audy
Prevent memory corruption when an invalid controller ID is passed in to the forcefeedback channel functions
#rb Lina.Halper
Change 2733590 on 2015/10/19 by Benn.Gallagher
Fixed various crashes when using undo and redo while manipulating state machines UE 22088
Change 2735143 on 2015/10/20 by Lukasz.Furman
clearing behavior tree debugger's state when displayed subtree becomes inactive
#ue4
#rb Mieszko.Zielinski
Change 2735144 on 2015/10/20 by Lukasz.Furman
rebuilding behavior tree graph node order when node is being moved
#ue4
#rb Mieszko.Zielinski
Change 2735403 on 2015/10/20 by sebastian.kowalczyk
Integrated fix for issue UE-18594 "Gameplay Debugger is hijacking the Canvas" issue from 4.10 (2735391). Extended previous fix to care about OSX users - it's possible to configure shortcuts in engine config file now (little different ones for osx platform).
Change 2736406 on 2015/10/21 by sebastian.kowalczyk
Added new GameplayDebugger as a plugin. Old gameplay debugger is still here to keep backward compatibility but it's deprecated now. Current projects should be moved to use new plugin soon.
Change 2736436 on 2015/10/21 by sebastian.kowalczyk
Fixed crash in gameplay debugger with player set as debug target.
Change 2736437 on 2015/10/21 by sebastian.kowalczyk
Added visual indicator around selected pawn to fix FORT-10273 issue. (FN is not using new gd plugin yet).
Change 2736489 on 2015/10/21 by sebastian.kowalczyk
Hide internal and debug hud classes from drop down lists.
Change 2736504 on 2015/10/21 by sebastian.kowalczyk
Fix for UE-18548 "EnableGDT does not work correctly in PIE".
Change 2736529 on 2015/10/21 by sebastian.kowalczyk
Fixed UE-18548 "EnableGDT does not work correctly in PIE"
Change 2736588 on 2015/10/21 by sebastian.kowalczyk
Removed old log visualizer classes.
Change 2736700 on 2015/10/21 by sebastian.kowalczyk
Fixed UE-19256 "Perception debug data doesn't get replicated by Gameplay Debuger" for old gameplay debugger module.
Change 2737180 on 2015/10/21 by Zak.Middleton
#ue4 - Fix UPrimitiveComponent::GetCollisionShape not correctly enforcing bounds limits.
#rb Aaron.Mcleran
#jira UE-22436
Change 2738084 on 2015/10/22 by sebastian.kowalczyk
Better indication of selected pawn for Gameplay Debugger.
Change 2738413 on 2015/10/22 by Marc.Audy
Disable duplication of worlds/maps via the content browser
#jira UE-22200
#rb James.Golding
Change 2739743 on 2015/10/23 by bruce.nesbit
UE-18707 - Issue with drawing material triangle on canvas #1387
Added DrawTriangleUsingVertexColor
Change 2739751 on 2015/10/23 by bruce.nesbit
Revised bShowDebugForReticleTarget should not be static #1539
Change 2739788 on 2015/10/23 by bruce.nesbit
Revised the 2 functions that used FTriangleRenderer::DrawTriangle to use FTriangleRenderer::DrawTriangleUsingVertexColor
Fixed compile error
Change 2739870 on 2015/10/23 by Marc.Audy
Avoid issues while detaching child components if OnAttachmentChange were to remove a sibling component itself.
#jira UE-22362
#rb Zak.Middleton
Change 2739882 on 2015/10/23 by sebastian.kowalczyk
Fix for UE-20901 "VisualLog redirections are broken after PIE finishes" issue.
Change 2740140 on 2015/10/23 by Marc.Audy
Ensure that components reregister tick functions after seamless travel
#jira UE-20892
#rb Zak.Middleton
Change 2740614 on 2015/10/23 by Ori.Cohen
Fix linker issues for people wanting to use physics lock lambdas
Change 2740674 on 2015/10/23 by Aaron.McLeran
Sound Focus Feature
Added new parameters to SoundAttenuation settings to allow audio to change behavior based on its angle to the listener
- Define the min/max azimuth angle to establish in-focus and non-focus regions
- Can scale the priority of a sound based on focus angle
- Can attenuate the volume of a sound based on focus angle
- Can scale the listener-emitter distance based on focus angle
- Distance scale is applied when determining max audible distance for USoundBase
- Can opt-out of focus effects for a sound at the USoundBase level
#rb Ryan.Vance
Change 2741542 on 2015/10/26 by Lukasz.Furman
lowered min value clamping in navigation filter properties
#ue4
#rb Mieszko.Zielinski
Change 2743227 on 2015/10/27 by Marc.Audy
Make ASceneCaptureCube subclassable outside of Engine module
#jira UE-22609
Make USceneCaptureComponentCube::UpdateContent callable outside of Engine module
#jira UE-22610
#rb Jeff.Farris
Change 2743255 on 2015/10/27 by Marc.Audy
Wrap FActorSpawnParameters class with deprecation warning disable pragma instead of hand implementing copy constructor
#rb Jeff.Farris
Change 2743729 on 2015/10/27 by Ori.Cohen
Fix case where we spawn and adjust location which gives us implicit velocity.
#codereview Stan.Melax
Change 2746135 on 2015/10/29 by sebastian.kowalczyk
Fixed UE-21668 "Saving log filters selected in LogVisualizer causes insane ini file sizes! And doesn't really work."
Change 2746437 on 2015/10/29 by Lukasz.Furman
pass on verifying behavior tree stack before accessing its elements
#ue4
#rb Mieszko.Zielinski
Change 2748028 on 2015/10/30 by sebastian.kowalczyk
Changed GameplayDebugger's console variable from gd.EQSOnHUD to ai.gd.EQSOnHUD" after suggestion with MieszkoZ.
Change 2748184 on 2015/10/30 by Aaron.McLeran
UE-22693 Fix for streaming bug
- 3rd decoded buffer in initial 3 buffers was not getting submitted to xaudio2 voice resulting in garbled/skipped audio.
- Wasn't able to repro the 'cannot read chunk' part of the bug
#rb ryan.vance
Change 2749255 on 2015/10/31 by sebastian.kowalczyk
Fixed ai.gd.EQSOnHUD console variable after rename from gd.EQSOnHUD.
Change 2749276 on 2015/10/31 by sebastian.kowalczyk
Added switch to toggle highlight of selected actor to GameplayDebugger.
Change 2749318 on 2015/10/31 by sebastian.kowalczyk
New Gameplay Debugger plugin can be used with old module simultaneously. It's best to configure different keyboard binding for plugin when using old module (it can be set in project settings, for new gameplay debugger plugin - when activated for project).
Change 2749337 on 2015/10/31 by sebastian.kowalczyk
Fixed GameplayDebugger compilation in shipping/test builds.
Change 2749376 on 2015/10/31 by sebastian.kowalczyk
Small clean-up in gameplay debugger class for BT.
Change 2749931 on 2015/11/02 by James.Golding
Add stats to ProcMeshComp
Change 2749932 on 2015/11/02 by James.Golding
Remove PhysicsThrusterComponent.h from Engine.h
Change 2749960 on 2015/11/02 by James.Golding
- Fix PS4 compile errors in ActiveSound.cpp
- Constructor order of FActiveSound
- Shadowed AudioComponent var in CheckOcclusion
#RB thomas.sarkanen
#codereview aaron.mcleran
Change 2749961 on 2015/11/02 by James.Golding
Fix PS4 compile errors in GameplayDebuggerBaseObject.cpp
- Shadowed DefaultContext function param, now just Context, which matches declaration
#RB thomas.sarkanen
#codereview sebastian.kowalczyk
Change 2750026 on 2015/11/02 by Thomas.Sarkanen
Anim Multithreading: thread-safety refactor
Segregated access to various parts of anim update data by spitting off a new proxy class (FAnimInstanceProxy) containing all data accessed in Update() and Evaluate() passes. Gated access to the proxy data on the game thread in a number of ways:
- Explicit access via GetValueOnGameThread() - this blocks on any existing task, completes and then allows control to return to the accessing function. This allows stuff like Blueprints to continue to operate as normal.
- Explicit access via GetValueOnAnyThread() - this ensures that in the limited set of circumstances we need this (Blueprint pure functions mostly) that conditions are met about concurrent access.
- Deprecating many APIs on UAnimInstance that should not be used (and in fact are not used at present, happily).
Derived classes of UAnimInstance can override the creation of the proxy class to create their own type. We do this for UAnimSingleNodeInstance etc.
Any API deprecation should continue to function - no functions have been removed yet. The only things that are not backwards-compatible are direct access to some public member variables for which there is no way to support (e.g. via references, for example UngroupedActivePlayerArrays).
Some APIs have been changed to more specifically represent the dependencies involved. For example TickAssetPlayerInstance() used to take a UAnimInstance*, only to use it to simply queue notifies. This has been deprecated and replaced with a new FNotifyQueue API. FNotifyQueue also uses a thread-safe FRandomStream instead of FMath::Rand.
Many changes are due to substituting accessor functions for direct variable access.
Removed 'service' tick group as we no longer need to segregate the running of our parallel update.
Anim nodes that need to do some game thread-side update should register for a pre-update callback delegate in the proxy. See FAnimNode_AnimDynamics for an example of this.
Moved UpdateActiveVertexAnims into FAnimRuntime so I can subsume some of the code that was in USkeletalMeshComponent::EvaluateAnimation into UAnimInstance (and hence keep the proxy access private).
#rb Martin.Wilson,Lina.Halper
#codereview Michael.Noland
Change 2750077 on 2015/11/02 by Marc.Audy
Expose UInputComponent::BindAction that supports WithKey delegate signature
Change 2751767 on 2015/11/03 by Thomas.Sarkanen
Added extra support to Anim Blueprint 'fast-path'
Added support for negated bools (value gets negated during copy).
Added support for copying from struct members (via break struct) and split struct pins.
Removed potentially troublesome references to BP-constructed UProperties, replacing them with the property FName. This adds some extra Initialize() overhead, but prevents various crash-on load issues (one when generating the class CRC). Added guard to prevent multiple initialization to save this more expensive work being done more often.
#rb Martin.Wilson
Change 2752158 on 2015/11/03 by Jeff.Farris
Fixed UGameplayStatics::SpawnEmitterAttached() to register the ParticleSystemComponent after it spawns.
#rb marc.audy
Change 2752159 on 2015/11/03 by Jeff.Farris
Improvements to camera lens effects to (EmitterCameraLensEffectBase)
- can now specify a transform to align the emitter with the camera
- exposed several key parameters to Blueprints
- ENGINE_API now applies to the entire class
#rb marc.audy
Change 2753454 on 2015/11/04 by Thomas.Sarkanen
Fixup deprecation warnings fallout from multithreaded update changes.
Fixed up use of AnimInstance in Vicon plugin.
Fixed up use of AnimInstance in slope warping node.
Un-deprecated some APIs to become warning free (these APIs are safe to call but just a 'bad idea if you want to do it right').
Also an extra API to allow for smoother transition: Allow custom allocation/deallocation (including using a proxy member struct) by providing an override point for proxy destruction.
#rb Martin.Wilson
Change 2754099 on 2015/11/04 by Ori.Cohen
Fix for task threads dropping stats (from Gil)
#rb Gil.Gribb
Change 2754449 on 2015/11/04 by Marc.Audy
Ensure that components created from an Actor's blueprint BeginPlay implementation get BeginPlay called on them and register their component ticks
#jira UE-20853
Reorganize some booleans to get better bit packing
#rb Jeff.Farris
#codereview Mieszko.Zielinski
Change 2754573 on 2015/11/04 by Aaron.McLeran
Fixing audio component PostLoad code to not set all LowPassFilterFrequency values to 0.0f
Change 2755345 on 2015/11/05 by Thomas.Sarkanen
Added deprecated constructors for various animation contexts
Allows existing code to compile if it creates its own contexts from UAnimInstance.
#rb James.Golding
Change 2755348 on 2015/11/05 by James.Golding
Add BP-exposed SetBoundsScale function to PrimitiveComponent
#RB thomas.sarkanen
Change 2755437 on 2015/11/05 by Marc.Audy
Fix compile errors
#codereview Thomas.Sarkanen, Mieszko.Zielinski, Aaron.McLeran
Change 2755982 on 2015/11/05 by Marc.Audy
Move HeaderParse changes for deprecation macro from Core
Fix world settings warning
Change 2756028 on 2015/11/05 by Marc.Audy
Fix shadow variable issue
Change 2756090 on 2015/11/05 by Ori.Cohen
Improve budget tool so that task threads are computed automatically.
#rb Gil.Gribb
Change 2756120 on 2015/11/05 by Mieszko.Zielinski
Fixed AIController::MoveTo not using DefaultQueryExtent of its navigation data #UE4
#rb Lukasz.Furman
Change 2756243 on 2015/11/05 by Mieszko.Zielinski
Fixed AI perception sight's "auto-visibility" mechanism totally skipping distance and vision cone checks #UE4
The old way was resulting in false positives when for example observer teleported somewhere far
#rb Lukasz.Furman
#codereview John.Abercrombie
Change 2756280 on 2015/11/05 by Mieszko.Zielinski
Minor VLog code cleanup and dumb-fixing visual logger accessing timer manager off of game thread #UE4
#rb Lukasz.Furman
Change 2756500 on 2015/11/05 by Mieszko.Zielinski
Added sanity-checking to BlueprintNodeHelpers::HasBlueprintFunction and cleaned up its usage #UE4
Also, refactored its parameters into references over pointers.
#rb Lukasz.Furman
Change 2757041 on 2015/11/06 by Thomas.Sarkanen
Removed check() in UAnimInstance::GetProxyOnAnyThread()
The check was no longer needed as if we are on the game thread we block until tasks are completed below, and if we are on any other thread we are 'safe' anyway.
#rb James.Golding
Change 2757207 on 2015/11/06 by Ori.Cohen
Fix incorrect root body cache which causes a single frame "freak out" when simulating physics from an animation
#rb Lina.Halper
Change 2757238 on 2015/11/06 by Marc.Audy
Force compiler generated functions to be generated for FHierarchicalSimplification in WorldSettings.h so that they are generated while the deprecation warnings are disabled.
#rb Mike.Fricker
Change 2757284 on 2015/11/06 by Stan.Melax
tapered capsule drawing
cloth collision happens with spheres and for the hull or tapered capsule goemetry between any specified pair of spheres.
(this was already code reviewed before, but missed the check-in window before streamtime)
#rb ori.cohen
Change 2757743 on 2015/11/06 by Lukasz.Furman
fixed node memory allocations for injected behavior tree decorators
#ue4 UE-22783
#rb Mieszko.Zielinski
Change 2757772 on 2015/11/06 by Lukasz.Furman
added setters for crowd avoidance
#ue4 UE-22785
#rb Mieszko.Zielinski
Change 2758422 on 2015/11/07 by Lina.Halper
Potential fix for invalid root bone index input
#jira :/UE-23086
#code review: Ori.Cohen
Change 2758429 on 2015/11/07 by Mieszko.Zielinski
Reimplemented a fix for AI Sight's "auto seeing" mechanics in a more flexible way #UE4
#jira UE-23089
Change 2758571 on 2015/11/08 by Mieszko.Zielinski
Modified ensure condition in UAIPerceptionComponent::OnRegister so it doesn't go off when BP does it's magic when components are being added to a BP actor class #UE4
#jira UE-23080
Change 2758821 on 2015/11/09 by Thomas.Sarkanen
Fixed animations no longer playing when using a dedicated server.
Uses correct logic to determine whether we are running as a server or not.
#rb Martin.Wilson
Change 2758920 on 2015/11/09 by Marc.Audy
Don't dereference weak object pointers repeatedly in FBoneContainer::Initialize
#rb Lina.Halper
Change 2758944 on 2015/11/09 by Ori.Cohen
Fix crash when stats are only on one thread and budget mode is used
Change 2758967 on 2015/11/09 by Benn.Gallagher
Fix for crash undoing notify socket changes in Persona, needed to recache the notify track data after the transaction had reserialized the sequence.
#jira UE-22963
Change 2758973 on 2015/11/09 by Benn.Gallagher
Added new 'Random Player' node for anim graphs allowing the user to play a selection of animations in a random order with certain randomised paramers. Also allows 'Shuffle Mode' to act more like a playlist in that it will play everything on the list before repeating.
#rb Bruce.Nesbit
Change 2759219 on 2015/11/09 by Ori.Cohen
Character perf test is now looking at stats directly and sending to analytics
#RB Ben.Salem
Change 2759398 on 2015/11/09 by Lina.Halper
Fix issue where placed montages are not playing.
- the issue is that IsPlaying does not consider montage, but SetPlaying does. It is asymmetry, so I made it same. However, there are other functions that need to be re-looked at wr.t. montage
#code review: Thomas.Sarkanen
#RB: Marc.Audy
Change 2759491 on 2015/11/09 by Lina.Halper
#Anim: Fix not getting input correctly for Copy Pose node
#RB: Marc.Audy
Change 2759602 on 2015/11/09 by Marc.Audy
Fix imporperly named struct
Change 2759795 on 2015/11/09 by Aaron.McLeran
UE-23145 Adding a Priority value to USoundBase to use in concurrency evaluation and sorting wave instances for voice stealing.
#rb zak.middleton
Change 2760081 on 2015/11/09 by Aaron.McLeran
UE-23091 Adding more logging for NaN checks and fixing one source of NaNs for audio.
OmniDirectional Math Explanation:
For XAudio2, because we do our own distance-attenuation calculations, we use the X3dAudio2 API to simply compute a speaker-map for spatialization and force the listener to be at the origin and the emitter to be on the unit-circle. Thus, from XAudio2's perspective, all distances for every listener-emitter pair will be 1.0.
So in order to use the InnerRadius blending feature, we need to trick it into doing a an inner radius blend relative to a distance of 1.0. For example, if OmniRadius and Distance are the same, then the "NormalizedOmniRadius" is 1.0 and XAudio2 will begin its "blend" of the sound to an omni-directional speaker map.
If Emitter-listener distance is less than the OmniRadius, we'll want to do more blending to an omni-directional speaker map, but we need to set the InnerRadius to something greater than 1.0 (i.e. so that the normalized distance of 1.0 will be treated as less than the InnerRadius). To do "full" omni-directional blending, the emitter-listener distance will be 0 or close to zero, and the NormalizedOmniRadius will be very large (i.e. close to infiinity).
The previous math just set the NormalizedOmniRadius to FLT_MAX which is fine but that number is eventually squared before making the API call. FLT_MAX squared is INF.
Note: I do not think we need to square the OmniRadius in:
Emitter.InnerRadius = OmniRadius*OmniRadius;
But I am keeping it t here because of legacy content which depends on that behavior.
#rb zak.middleton
hange 2760401 on 2015/11/10 by Thomas.Sarkanen@Thomas.Sarkanen-Dev-Framework
Re-instated deleted protected functions in UAnimInstance.
Fixed access of UAnimInstance in FAnimNode_StateMachine.
#rb Martin.Wilson
Change 2760407 on 2015/11/10 by Jurre.deBaare
Construct raw meshes for spline meshes now uses the render data instead of original model data (preserves tangents/normals)
Change 2760468 on 2015/11/10 by Benn.Gallagher
Anim Dynamics optimizations, cached iteration independant data to reduce footprint of iteration on limits.
#rb Graeme.Thornton
Change 2760613 on 2015/11/10 by Jeff.Farris
Fixed async collision completion delegate potentially firing repeatedly. (UE-23149)
#cr marc.audy
#codereview lina.halper
Change 2760795 on 2015/11/10 by Marc.Audy
Don't compile in pointless AddReferencedObjects when with editoronly data not defined
Minor coding standard cleanup (NULL and auto)
Change 2760848 on 2015/11/10 by Benn.Gallagher
Fix to anim instance proxy to not rely on state machine initialization to bind native delegates as nested state machines are not guaranteed to be initialized. This was fixed in UAnimInstance originally but broken again by the proxy instance code.
#jira UE-23164
#rb Martin.Wilson
Change 2760866 on 2015/11/10 by Marc.Audy
Manage transient visualization components for camera component in the same way that sprite component for other actor components are
#rb Mike.Beach
Change 2760963 on 2015/11/10 by Marc.Audy
Since construction script can cause actors to be spawned don't use a ranged for to iterate
#jira UE-22639
#rb Jeff.Farris
#codereview Dmitriy.Dyomin
Change 2762297 on 2015/11/11 by James.Golding
UE-23086 Don't ensure in SetRootBodyIndex when Bodies array is empty (ie no physics state created)
#rb martin.wilson
#codereview ori.cohen, lina.halper
Change 2763566 on 2015/11/11 by Lina.Halper
FAnimNode_CopyPoseFromMesh::Evaluate - was accessing skeleton joint, not mesh joint.
#RB: Laurent.Delayen
Change 2763926 on 2015/11/12 by Thomas.Sarkanen
Fix anim notifies not firing from single anim instances
UE-23248 - Anim Notifies are not working for Animation Sequences
UE-23249 - Anim Notifies using Sound Cues do not work
#rb James.Golding
Change 2764039 on 2015/11/12 by Jurre.deBaare
Fix for issue with incorrect material indices after reducing a skeletal mesh with non LOD0 mesh as BaseLOD (OR-9243) #rb Lina.Halper
Change 2764307 on 2015/11/12 by Jurre.deBaare
VS2015 SSF library
Change 2764314 on 2015/11/12 by Stan.Melax
crashfix was putting bad bodies to sleep at start
Fatal error!
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x00000000
UE4Editor-Engine.dll!USkeletalMeshComponent::InitArticulated() [...\\engine\\source\\runtime\\engine\\private\\skeletalmeshcomponentphysics.cpp:875]
On some skeletalmeshcomponent, some bodies aren't getting created correctly. Trying to force them to sleep was causing a crash - it expected instantiated physx bodies. Seems that all the rest of the code is able to tolerate bad bodies.
Added check to ensure physx body exists before trying to force it to sleep.
not sure if bad bodies are the norm or if this fix is just more "kicking the can down the road".
#codereview ori.cohen
Change 2764343 on 2015/11/12 by Jurre.deBaare
- Fixed crash when building a LOD with SubActors.Num < 2
- Force HLOD level slider is now always enabled, however won't show complete image if not all HLODs are build
- LODActor tree view item now scrolls into view if selected in the world
- Set bAllowCullDistanceVolume to false for LODActor's static mesh components by default
- Added 7zip files
- Fixed issue with WinINet complaining about http-request without 'http://' prefix
- Changed % reduced or original triangles display string, now uses float instead of int (for < 1% reductions)
- Override texture sizes and automatic texture bias
- Fixed issue with incorrect material merging, not picking up it required mesh-data during baking. Added extra conditions for rendering with mesh-data.
- Now incorporate static meshes with opague materials into HLOD merging
- Fixed issue with incorrect normals after merging meshes who's owning components had been negatively scaled
- Fixed issue with incorrect texture size being set from MergeActor window (was only changing .X component)
- Fixed issue with material merging when meshes with multiple LODs are merged, right now only merges LOD0's together if we are also merging the materials (otherwise, merge each LOD)
- Added ENUM for texture scaling/resizing type that has to be applied while merging the materials
- Added detail customization class for FMaterialProxySettings
#rb James.Golding
[CL 2765024 by Marc Audy in Main branch]
2015-11-12 18:11:48 -05:00
GeneratedFunctionText . Logf ( TEXT ( " \t \t \t ReturnPackage->SetPackageFlags(PKG_CompiledIn | 0x%08X); \r \n " ) , InPackage - > GetPackageFlags ( ) & ( PKG_ClientOptional | PKG_ServerSideOnly | PKG_EditorOnly ) ) ;
TheFlagAudit . Add ( InPackage , TEXT ( " PackageFlags " ) , InPackage - > GetPackageFlags ( ) ) ;
2014-03-14 14:13:41 -04:00
{
FGuid Guid ;
2015-01-13 12:24:06 -05:00
uint32 CombinedCRC = 0 ;
2015-11-18 16:20:49 -05:00
for ( TUniqueObj < FUHTStringBuilderLineCounter > & Split : GeneratedFunctionBodyTextSplit )
2015-01-13 12:24:06 -05:00
{
2015-04-14 08:03:34 -04:00
uint32 SplitCRC = GenerateTextCRC ( * Split - > ToUpper ( ) ) ;
2015-01-13 12:24:06 -05:00
if ( CombinedCRC = = 0 )
{
// Don't combine in the first case because it keeps GUID backwards compatibility
CombinedCRC = SplitCRC ;
}
else
{
CombinedCRC = HashCombine ( SplitCRC , CombinedCRC ) ;
}
}
Guid . A = CombinedCRC ;
2014-12-11 04:58:57 -05:00
Guid . B = GenerateTextCRC ( * GeneratedFunctionDeclarations . ToUpper ( ) ) ;
2015-09-21 07:53:49 -04:00
GeneratedFunctionText . Logf ( TEXT ( " \t \t \t FGuid Guid; \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " \t \t \t Guid.A = 0x%08X; \r \n " ) , Guid . A ) ;
GeneratedFunctionText . Logf ( TEXT ( " \t \t \t Guid.B = 0x%08X; \r \n " ) , Guid . B ) ;
GeneratedFunctionText . Logf ( TEXT ( " \t \t \t Guid.C = 0x%08X; \r \n " ) , Guid . C ) ;
GeneratedFunctionText . Logf ( TEXT ( " \t \t \t Guid.D = 0x%08X; \r \n " ) , Guid . D ) ;
GeneratedFunctionText . Logf ( TEXT ( " \t \t \t ReturnPackage->SetGuid(Guid); \r \n " ) , Guid . D ) ;
2015-01-20 09:33:54 -05:00
GeneratedFunctionText . Log ( TEXT ( " \r \n " ) ) ;
for ( UField * ScriptType : TObjectRange < UField > ( ) )
{
2015-04-22 14:15:56 -04:00
if ( ScriptType - > GetOutermost ( ) ! = InPackage )
2015-01-20 09:33:54 -05:00
{
continue ;
}
if (
( ScriptType - > IsA < UScriptStruct > ( ) & & ( ( ( UScriptStruct * ) ScriptType ) - > StructFlags & STRUCT_NoExport ) ! = 0 ) | |
ScriptType - > IsA < UDelegateFunction > ( )
)
{
2015-09-08 09:23:57 -04:00
UField * FieldOuter = Cast < UField > ( ScriptType - > GetOuter ( ) ) ;
if ( ! FieldOuter | | ! FClass : : IsDynamic ( FieldOuter ) )
{
2015-09-21 07:53:49 -04:00
GeneratedFunctionText . Logf ( TEXT ( " \t \t \t %s; \r \n " ) , * GetSingletonName ( ScriptType ) ) ;
2015-09-08 09:23:57 -04:00
}
2015-01-20 09:33:54 -05:00
}
}
2014-03-14 14:13:41 -04:00
}
2015-09-21 07:53:49 -04:00
GeneratedFunctionText . Logf ( TEXT ( " \t \t } \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " \t \t return ReturnPackage; \r \n " ) ) ;
GeneratedFunctionText . Logf ( TEXT ( " \t } \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportNativeGeneratedInitCode ( FClass * Class , FUHTStringBuilder & OutFriendText )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder & GeneratedFunctionText = GetGeneratedFunctionTextDevice ( ) ;
2015-01-20 09:33:54 -05:00
check ( ! OutFriendText . Len ( ) ) ;
2014-03-14 14:13:41 -04:00
// Emit code to build the UObjects that used to be in .u files
2015-09-08 09:23:57 -04:00
const bool bIsNoExport = Class - > HasAnyClassFlags ( CLASS_NoExport ) ;
const bool bIsDynamic = FClass : : IsDynamic ( Class ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder BodyText ;
FUHTStringBuilder CallSingletons ;
2015-01-20 09:33:54 -05:00
FString ApiString = GetAPIString ( ) ;
2014-03-14 14:13:41 -04:00
TArray < UFunction * > FunctionsToExport ;
for ( TFieldIterator < UFunction > Function ( Class , EFieldIteratorFlags : : ExcludeSuper ) ; Function ; + + Function )
{
FunctionsToExport . Add ( * Function ) ;
}
// Sort the list of functions
FunctionsToExport . Sort ( ) ;
// Export the init code for each function
for ( int32 FuncIndex = 0 ; FuncIndex < FunctionsToExport . Num ( ) ; FuncIndex + + )
{
UFunction * Function = FunctionsToExport [ FuncIndex ] ;
2015-03-12 14:06:13 -04:00
if ( ! Function - > IsA < UDelegateFunction > ( ) )
{
ExportFunction ( Function , & FScope : : GetTypeScope ( Class ) . Get ( ) , bIsNoExport ) ;
}
2015-09-21 07:53:49 -04:00
CallSingletons . Logf ( TEXT ( " \t \t \t \t OuterClass->LinkChild(%s); \r \n " ) , * GetSingletonName ( Function ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
FUHTStringBuilder GeneratedClassRegisterFunctionText ;
2014-07-29 02:43:48 -04:00
2015-01-20 09:33:54 -05:00
// The class itself.
2014-03-14 14:13:41 -04:00
{
// simple ::StaticClass wrapper to avoid header, link and DLL hell
{
FString SingletonNameNoRegister ( GetSingletonName ( Class , false ) ) ;
2015-05-22 02:54:27 -04:00
GeneratedFunctionDeclarations . Log ( FTypeSingletonCache : : Get ( Class , false ) . GetExternDecl ( ) ) ;
2014-03-14 14:13:41 -04:00
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t UClass* %s \r \n " ) , * SingletonNameNoRegister ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t { \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t return %s::StaticClass(); \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t } \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
}
FString SingletonName ( GetSingletonName ( Class ) ) ;
2015-09-21 07:53:49 -04:00
OutFriendText . Logf ( TEXT ( " \t friend %sclass UClass* %s; \r \n " ) , * ApiString , * SingletonName ) ;
2015-05-22 02:54:27 -04:00
GeneratedFunctionDeclarations . Log ( FTypeSingletonCache : : Get ( Class ) . GetExternDecl ( ) ) ;
2014-03-14 14:13:41 -04:00
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t UClass* %s \r \n " ) , * SingletonName ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t { \r \n " ) ) ;
2015-09-08 09:23:57 -04:00
if ( ! bIsDynamic )
{
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t static UClass* OuterClass = NULL; \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t if (!OuterClass) \r \n " ) ) ;
2015-09-08 09:23:57 -04:00
}
else
{
2015-11-18 16:20:49 -05:00
const FString DynamicClassPackageName = FClass : : GetTypePackageName ( Class ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t UPackage* OuterPackage = FindOrConstructDynamicTypePackage(TEXT( \" %s \" )); \r \n " ) , * DynamicClassPackageName ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t UClass* OuterClass = Cast<UClass>(StaticFindObjectFast(UClass::StaticClass(), OuterPackage, TEXT( \" %s \" ))); \r \n " ) , * Class - > GetName ( ) ) ;
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t if (!OuterClass || !(OuterClass->ClassFlags & CLASS_Constructed)) \r \n " ) ) ;
2015-09-08 09:23:57 -04:00
}
2015-09-11 10:08:33 -04:00
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t { \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
if ( Class - > GetSuperClass ( ) & & Class - > GetSuperClass ( ) ! = Class )
{
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t %s; \r \n " ) , * GetSingletonName ( Class - > GetSuperClass ( ) ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t %s; \r \n " ) , * GetPackageSingletonName ( CastChecked < UPackage > ( Class - > GetOutermost ( ) ) ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t OuterClass = %s::StaticClass(); \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t if (!(OuterClass->ClassFlags & CLASS_Constructed)) \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t { \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t \t UObjectForceRegistration(OuterClass); \r \n " ) ) ;
2014-11-06 15:16:05 -05:00
uint32 Flags = ( Class - > ClassFlags & CLASS_SaveInCompiledInClasses ) | CLASS_Constructed ;
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t \t OuterClass->ClassFlags |= 0x%08X; \r \n " ) , Flags ) ;
2014-03-14 14:13:41 -04:00
TheFlagAudit . Add ( Class , TEXT ( " ClassFlags " ) , Flags ) ;
2014-07-29 02:43:48 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Log ( CallSingletons ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
FString OuterString = FString ( TEXT ( " OuterClass " ) ) ;
2015-09-21 07:53:49 -04:00
FString Meta = GetMetaDataCodeForObject ( Class , * OuterString , TEXT ( " \t \t \t \t " ) ) ;
2014-03-14 14:13:41 -04:00
// properties
{
TArray < UProperty * > Props ;
for ( TFieldIterator < UProperty > ItInner ( Class , EFieldIteratorFlags : : ExcludeSuper ) ; ItInner ; + + ItInner )
{
Props . Add ( * ItInner ) ;
}
2015-02-05 13:10:48 -05:00
if ( Props . Num ( ) > 0 )
{
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " PRAGMA_DISABLE_DEPRECATION_WARNINGS \r \n " ) ) ;
2015-09-21 07:53:49 -04:00
OutputProperties ( Meta , GeneratedClassRegisterFunctionText , OuterString , Props , TEXT ( " \t \t \t \t " ) ) ;
2015-05-12 17:44:46 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " PRAGMA_ENABLE_DEPRECATION_WARNINGS \r \n " ) ) ;
2015-02-05 13:10:48 -05:00
}
2014-03-14 14:13:41 -04:00
}
// function table
{
// Grab and sort the list of functions in the function map
TArray < UFunction * > FunctionsInMap ;
for ( auto Function : TFieldRange < UFunction > ( Class , EFieldIteratorFlags : : ExcludeSuper ) )
{
FunctionsInMap . Add ( Function ) ;
}
FunctionsInMap . Sort ( ) ;
// Emit code to construct each UFunction and rebuild the function map at runtime
for ( UFunction * Function : FunctionsInMap )
{
2015-09-28 14:27:23 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t \t OuterClass->AddFunctionToFunctionMapWithOverriddenName(%s, %s);%s \r \n " ) , * GetSingletonName ( Function ) , * FNativeClassHeaderGenerator : : GetOverriddenNameForLiteral ( Function ) , * GetGeneratedCodeCRCTag ( Function ) ) ;
2014-03-14 14:13:41 -04:00
}
}
// class flags are handled by the intrinsic bootstrap code
2015-09-21 07:53:49 -04:00
//GeneratedClassRegisterFunctionText.Logf(TEXT("\t\t\tOuterClass->ClassFlags = 0x%08X;\r\n"), Class->ClassFlags);
2014-03-14 14:13:41 -04:00
if ( Class - > ClassConfigName ! = NAME_None )
{
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t \t OuterClass->ClassConfigName = FName(TEXT( \" %s \" )); \r \n " ) , * Class - > ClassConfigName . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
for ( auto & Inter : Class - > Interfaces )
{
check ( Inter . Class ) ;
FString OffsetString ( TEXT ( " 0 " ) ) ;
if ( Inter . PointerOffset )
{
2014-06-02 07:02:29 -04:00
OffsetString = FString : : Printf ( TEXT ( " VTABLE_OFFSET(%s, %s) " ) , NameLookupCPP . GetNameCPP ( Class ) , NameLookupCPP . GetNameCPP ( Inter . Class , true ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t \t OuterClass->Interfaces.Add(FImplementedInterface(%s, %s, %s )); \r \n " ) ,
2014-03-14 14:13:41 -04:00
* GetSingletonName ( Inter . Class , false ) ,
* OffsetString ,
Inter . bImplementedByK2 ? TEXT ( " true " ) : TEXT ( " false " )
) ;
}
if ( Class - > ClassGeneratedBy )
{
UE_LOG ( LogCompile , Fatal , TEXT ( " For intrinsic and compiled-in classes, ClassGeneratedBy should always be NULL " ) ) ;
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t \t OuterClass->ClassGeneratedBy = %s; \r \n " ) , * GetSingletonName ( CastChecked < UClass > ( Class - > ClassGeneratedBy ) , false ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t \t OuterClass->StaticLink(); \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
if ( Meta . Len ( ) )
{
2014-07-29 02:43:48 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " #if WITH_METADATA \r \n " ) ) ;
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t \t UMetaData* MetaData = OuterClass->GetOutermost()->GetMetaData(); \r \n " ) ) ;
2014-07-29 02:43:48 -04:00
GeneratedClassRegisterFunctionText . Log ( * Meta ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " #endif \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-09-21 07:53:49 -04:00
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t \t } \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t } \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t check(OuterClass->GetClass()); \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t \t return OuterClass; \r \n " ) ) ;
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \t } \r \n " ) ) ;
2014-07-29 02:43:48 -04:00
GeneratedFunctionText + = GeneratedClassRegisterFunctionText ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
if ( OutFriendText . Len ( ) & & bIsNoExport )
2014-03-14 14:13:41 -04:00
{
2015-09-21 07:53:49 -04:00
GeneratedFunctionText . Logf ( TEXT ( " \t /* friend declarations for pasting into noexport class %s \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2015-01-20 09:33:54 -05:00
GeneratedFunctionText . Log ( OutFriendText ) ;
2015-09-21 07:53:49 -04:00
GeneratedFunctionText . Logf ( TEXT ( " \t */ \r \n " ) ) ;
2015-03-27 18:10:52 -04:00
OutFriendText . Reset ( ) ;
2014-03-14 14:13:41 -04:00
}
FString SingletonName ( GetSingletonName ( Class ) ) ;
2015-03-27 18:10:52 -04:00
SingletonName . ReplaceInline ( TEXT ( " () " ) , TEXT ( " " ) , ESearchCase : : CaseSensitive ) ; // function address
2014-03-14 14:13:41 -04:00
2014-07-29 02:43:48 -04:00
{
2015-09-29 17:44:18 -04:00
FString OverriddenClassName = * FNativeClassHeaderGenerator : : GetOverriddenName ( Class ) ;
2015-05-07 05:55:26 -04:00
const TCHAR * ClassNameCPP = NameLookupCPP . GetNameCPP ( Class ) ;
2015-09-08 09:23:57 -04:00
2015-09-21 07:53:49 -04:00
GeneratedFunctionText . Logf ( TEXT ( " \t static FCompiledInDefer Z_CompiledInDefer_UClass_%s(%s, &%s::StaticClass, TEXT( \" %s \" ), %s); \r \n " ) ,
2015-09-29 18:25:32 -04:00
ClassNameCPP , * SingletonName , ClassNameCPP , bIsDynamic ? * OverriddenClassName : ClassNameCPP ,
2015-09-08 09:23:57 -04:00
bIsDynamic ? TEXT ( " true " ) : TEXT ( " false " ) ) ;
2014-07-29 02:43:48 -04:00
2015-05-07 05:55:26 -04:00
// Append base class' CRC at the end of the generated code, this will force update derived classes
// when base class changes during hot-reload.
uint32 BaseClassCRC = 0 ;
if ( Class - > GetSuperClass ( ) & & ! Class - > GetSuperClass ( ) - > HasAnyClassFlags ( CLASS_Intrinsic ) )
{
BaseClassCRC = GGeneratedCodeCRCs . FindChecked ( Class - > GetSuperClass ( ) ) ;
}
GeneratedClassRegisterFunctionText . Logf ( TEXT ( " \r \n // %u \r \n " ) , BaseClassCRC ) ;
2014-07-29 02:43:48 -04:00
// Calculate generated class initialization code CRC so that we know when it changes after hot-reload
2014-12-11 04:58:57 -05:00
uint32 ClassCrc = GenerateTextCRC ( * GeneratedClassRegisterFunctionText ) ;
2015-05-07 05:55:26 -04:00
GGeneratedCodeCRCs . Add ( Class , ClassCrc ) ;
2015-11-18 16:20:49 -05:00
UHTMakefile . AddGeneratedCodeCRC ( CurrentSourceFile . Top ( ) , Class , ClassCrc ) ;
2014-07-29 02:43:48 -04:00
// Emit the IMPLEMENT_CLASS macro to go in the generated cpp file.
2015-09-08 09:23:57 -04:00
if ( ! bIsDynamic )
{
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t IMPLEMENT_CLASS(%s, %u); \r \n " ) , ClassNameCPP , ClassCrc ) ;
2015-09-08 09:23:57 -04:00
}
else
{
2015-09-29 17:44:18 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t IMPLEMENT_DYNAMIC_CLASS(%s, TEXT( \" %s \" ), %u); \r \n " ) , ClassNameCPP , * OverriddenClassName , ClassCrc ) ;
2015-09-08 09:23:57 -04:00
}
2014-03-14 14:13:41 -04:00
}
}
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportFunction ( UFunction * Function , FScope * Scope , bool bIsNoExport )
{
UFunction * SuperFunction = Function - > GetSuperFunction ( ) ;
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
bool bIsDelegate = Function - > HasAnyFunctionFlags ( FUNC_Delegate ) ;
const FFuncInfo & FunctionData = CompilerInfo - > GetFunctionData ( ) ;
const FString SingletonName ( GetSingletonName ( Function ) ) ;
2015-05-22 02:54:27 -04:00
GeneratedFunctionDeclarations . Log ( FTypeSingletonCache : : Get ( Function ) . GetExternDecl ( ) ) ;
2015-01-20 09:33:54 -05:00
2015-03-27 18:10:52 -04:00
FUHTStringBuilder CurrentFunctionText ;
2015-01-20 09:33:54 -05:00
2015-09-21 07:53:49 -04:00
CurrentFunctionText . Logf ( TEXT ( " \t UFunction* %s \r \n " ) , * SingletonName ) ;
CurrentFunctionText . Logf ( TEXT ( " \t { \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
if ( bIsNoExport | | ! ( Function - > FunctionFlags & FUNC_Event ) ) // non-events do not export a params struct, so lets do that locally for offset determination
{
TGuardValue < bool > Guard ( bIsExportingForOffsetDeterminationOnly , true ) ;
TArray < UScriptStruct * > Structs ;
FindNoExportStructs ( Structs , Function ) ;
if ( Structs . Num ( ) )
{
2015-03-27 18:10:52 -04:00
ExportMirrorsForNoexportStructs ( Structs , /*Indent=*/ 2 , CurrentFunctionText ) ;
2015-01-20 09:33:54 -05:00
}
TArray < UFunction * > CallbackFunctions ;
CallbackFunctions . Add ( Function ) ;
2015-03-27 18:10:52 -04:00
ExportEventParms ( * Scope , CallbackFunctions , CurrentFunctionText , /*Indent=*/ 2 , /*bOutputConstructor=*/ false ) ;
2015-01-20 09:33:54 -05:00
}
if ( UObject * Outer = Function - > GetOuter ( ) )
{
2015-09-21 07:53:49 -04:00
CurrentFunctionText . Logf ( TEXT ( " \t \t UObject* Outer=%s; \r \n " ) , Outer - > IsA < UPackage > ( ) ? * GetPackageSingletonName ( ( UPackage * ) Outer ) : * GetSingletonName ( Function - > GetOwnerClass ( ) ) ) ;
2015-01-20 09:33:54 -05:00
}
else
{
2015-09-21 07:53:49 -04:00
CurrentFunctionText . Logf ( TEXT ( " \t \t UObject* Outer=nullptr; \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
}
2015-09-21 07:53:49 -04:00
CurrentFunctionText . Logf ( TEXT ( " \t \t static UFunction* ReturnFunction = NULL; \r \n " ) ) ;
CurrentFunctionText . Logf ( TEXT ( " \t \t if (!ReturnFunction) \r \n " ) ) ;
CurrentFunctionText . Logf ( TEXT ( " \t \t { \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
FString SuperFunctionString ( TEXT ( " NULL " ) ) ;
if ( SuperFunction )
{
SuperFunctionString = GetSingletonName ( SuperFunction ) ;
}
TArray < UProperty * > Props ;
for ( TFieldIterator < UProperty > ItInner ( Function , EFieldIteratorFlags : : ExcludeSuper ) ; ItInner ; + + ItInner )
{
Props . Add ( * ItInner ) ;
}
FString StructureSize ;
if ( Props . Num ( ) )
{
UFunction * TempFunction = Function ;
while ( TempFunction - > GetSuperFunction ( ) )
{
TempFunction = TempFunction - > GetSuperFunction ( ) ;
}
FString FunctionName = TempFunction - > GetName ( ) ;
if ( TempFunction - > HasAnyFunctionFlags ( FUNC_Delegate ) )
{
FunctionName = FunctionName . LeftChop ( FString ( HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX ) . Len ( ) ) ;
}
StructureSize = FString : : Printf ( TEXT ( " , sizeof(%s) " ) , * GetEventStructParamsName ( TempFunction - > GetOuter ( ) , * FunctionName ) ) ;
}
FString UFunctionType = bIsDelegate ? TEXT ( " UDelegateFunction " ) : TEXT ( " UFunction " ) ;
2015-11-18 16:20:49 -05:00
CurrentFunctionText . Logf ( TEXT ( " \t \t \t ReturnFunction = new(EC_InternalUseOnlyConstructor, Outer, TEXT( \" %s \" ), RF_Public|RF_Transient|RF_MarkAsNative) %s(FObjectInitializer(), %s, 0x%08X, %d%s); \r \n " ) ,
2015-09-09 14:07:28 -04:00
* FNativeClassHeaderGenerator : : GetOverriddenName ( Function ) ,
2015-01-20 09:33:54 -05:00
* UFunctionType ,
* SuperFunctionString ,
Function - > FunctionFlags ,
( uint32 ) Function - > RepOffset ,
* StructureSize
) ;
TheFlagAudit . Add ( Function , TEXT ( " FunctionFlags " ) , Function - > FunctionFlags ) ;
FString OuterString = FString ( TEXT ( " ReturnFunction " ) ) ;
2015-09-21 07:53:49 -04:00
FString Meta = GetMetaDataCodeForObject ( Function , * OuterString , TEXT ( " \t \t \t " ) ) ;
2015-01-20 09:33:54 -05:00
for ( int32 Index = Props . Num ( ) - 1 ; Index > = 0 ; Index - - )
{
2015-09-21 07:53:49 -04:00
OutputProperty ( Meta , CurrentFunctionText , OuterString , Props [ Index ] , TEXT ( " \t \t \t " ) ) ;
2015-01-20 09:33:54 -05:00
}
if ( FunctionData . FunctionFlags & ( FUNC_NetRequest | FUNC_NetResponse ) )
{
2015-09-21 07:53:49 -04:00
CurrentFunctionText . Logf ( TEXT ( " \t \t \t ReturnFunction->RPCId=%d; \r \n " ) , FunctionData . RPCId ) ;
CurrentFunctionText . Logf ( TEXT ( " \t \t \t ReturnFunction->RPCResponseId=%d; \r \n " ) , FunctionData . RPCResponseId ) ;
2015-01-20 09:33:54 -05:00
}
2015-09-21 07:53:49 -04:00
CurrentFunctionText . Logf ( TEXT ( " \t \t \t ReturnFunction->Bind(); \r \n " ) ) ;
CurrentFunctionText . Logf ( TEXT ( " \t \t \t ReturnFunction->StaticLink(); \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
if ( Meta . Len ( ) )
{
CurrentFunctionText . Logf ( TEXT ( " #if WITH_METADATA \r \n " ) ) ;
2015-09-21 07:53:49 -04:00
CurrentFunctionText . Logf ( TEXT ( " \t \t \t UMetaData* MetaData = ReturnFunction->GetOutermost()->GetMetaData(); \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
CurrentFunctionText . Log ( * Meta ) ;
CurrentFunctionText . Logf ( TEXT ( " #endif \r \n " ) ) ;
}
2015-09-21 07:53:49 -04:00
CurrentFunctionText . Logf ( TEXT ( " \t \t } \r \n " ) ) ;
CurrentFunctionText . Logf ( TEXT ( " \t \t return ReturnFunction; \r \n " ) ) ;
CurrentFunctionText . Logf ( TEXT ( " \t } \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
uint32 FunctionCrc = GenerateTextCRC ( * CurrentFunctionText ) ;
GGeneratedCodeCRCs . Add ( Function , FunctionCrc ) ;
2015-11-18 16:20:49 -05:00
UHTMakefile . AddGeneratedCodeCRC ( CurrentSourceFile . Top ( ) , Function , FunctionCrc ) ;
2015-01-20 09:33:54 -05:00
GetGeneratedFunctionTextDevice ( ) + = CurrentFunctionText ;
}
2014-06-02 07:02:29 -04:00
void FNativeClassHeaderGenerator : : ExportNatives ( FClass * Class )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
// Skip no export classes.
if ( Class - > HasAnyClassFlags ( CLASS_NoExport ) )
{
2014-03-14 14:13:41 -04:00
return ;
2015-01-20 09:33:54 -05:00
}
2014-03-14 14:13:41 -04:00
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t void %s::StaticRegisterNatives%s() \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t { \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
{
TArray < UFunction * > FunctionsToExport ;
for ( auto * Function : TFieldRange < UFunction > ( Class , EFieldIteratorFlags : : ExcludeSuper ) )
{
if ( ( Function - > FunctionFlags & ( FUNC_Native | FUNC_NetRequest ) ) = = FUNC_Native )
{
FunctionsToExport . Add ( Function ) ;
}
}
FunctionsToExport . Sort ( ) ;
for ( auto Func : FunctionsToExport )
{
2015-09-28 14:27:23 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t FNativeFunctionRegistrar::RegisterFunction(%s::StaticClass(), %s,(Native)&%s::exec%s); \r \n " ) ,
2014-06-02 07:02:29 -04:00
NameLookupCPP . GetNameCPP ( Class ) ,
2015-09-28 14:27:23 -04:00
* FNativeClassHeaderGenerator : : GetOverriddenNameForLiteral ( Func ) ,
2014-06-02 07:02:29 -04:00
Class - > HasAnyClassFlags ( CLASS_Interface ) ? * FString : : Printf ( TEXT ( " I%s " ) , * Class - > GetName ( ) ) : NameLookupCPP . GetNameCPP ( Class ) ,
2014-03-14 14:13:41 -04:00
* Func - > GetName ( )
) ;
}
}
for ( auto * Struct : TFieldRange < UScriptStruct > ( Class , EFieldIteratorFlags : : ExcludeSuper ) )
{
if ( Struct - > StructFlags & STRUCT_Native )
{
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t UScriptStruct::DeferCppStructOps(FName(TEXT( \" %s \" )),new UScriptStruct::TCppStructOps<%s%s>); \r \n " ) , * Struct - > GetName ( ) , Struct - > GetPrefixCPP ( ) , * Struct - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t } \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-11-18 16:20:49 -05:00
void FNativeClassHeaderGenerator : : ExportInterfaceCallFunctions ( const TArray < UFunction * > & InCallbackFunctions , UClass * Class , FUHTStringBuilder & HeaderOutput )
2014-03-14 14:13:41 -04:00
{
TArray < UFunction * > CallbackFunctions = InCallbackFunctions ;
CallbackFunctions . Sort ( ) ;
for ( auto FuncIt = CallbackFunctions . CreateConstIterator ( ) ; FuncIt ; + + FuncIt )
{
UFunction * Function = * FuncIt ;
FString FunctionName = Function - > GetName ( ) ;
2015-01-20 09:33:54 -05:00
FString ClassName = Class - > GetName ( ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
2014-03-14 14:13:41 -04:00
const FFuncInfo & FunctionData = CompilerInfo - > GetFunctionData ( ) ;
const TCHAR * ConstQualifier = FunctionData . FunctionReference - > HasAllFunctionFlags ( FUNC_Const ) ? TEXT ( " const " ) : TEXT ( " " ) ;
FString ExtraParam = FString : : Printf ( TEXT ( " %sUObject* O " ) , ConstQualifier ) ;
ExportNativeFunctionHeader ( FunctionData , HeaderOutput , EExportFunctionType : : Interface , EExportFunctionHeaderStyle : : Declaration , * ExtraParam ) ;
2015-03-27 18:10:52 -04:00
HeaderOutput . Logf ( TEXT ( " ; " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
ExportNativeFunctionHeader ( FunctionData , GeneratedPackageCPP , EExportFunctionType : : Interface , EExportFunctionHeaderStyle : : Definition , * ExtraParam ) ;
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( LINE_TERMINATOR TEXT ( " \t { " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t check(O != NULL); " ) LINE_TERMINATOR ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t \t check(O->GetClass()->ImplementsInterface(U%s::StaticClass())); " ) LINE_TERMINATOR , * ClassName ) ;
2014-03-14 14:13:41 -04:00
auto Parameters = GetFunctionParmsAndReturn ( FunctionData . FunctionReference ) ;
// See if we need to create Parms struct
2015-03-27 18:10:52 -04:00
const bool bHasParms = Parameters . HasParms ( ) ;
2014-03-14 14:13:41 -04:00
if ( bHasParms )
{
2015-01-20 09:33:54 -05:00
FString EventParmStructName = GetEventStructParamsName ( Function - > GetOuter ( ) , * FunctionName ) ;
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t %s Parms; " ) LINE_TERMINATOR , * EventParmStructName ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t UFunction* const Func = O->FindFunction(%s_%s); " ) LINE_TERMINATOR , * API , * FunctionName ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t \t if (Func) " ) LINE_TERMINATOR ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t \t { " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
// code to populate Parms struct
for ( auto It = Parameters . Parms . CreateConstIterator ( ) ; It ; + + It )
{
UProperty * Param = * It ;
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t \t Parms.%s=%s; " ) LINE_TERMINATOR , * Param - > GetName ( ) , * Param - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
}
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
const FString ObjectRef = FunctionData . FunctionReference - > HasAllFunctionFlags ( FUNC_Const ) ? FString : : Printf ( TEXT ( " const_cast<UObject*>(O) " ) , * ClassName ) : TEXT ( " O " ) ;
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t \t %s->ProcessEvent(Func, %s); " ) LINE_TERMINATOR , * ObjectRef , bHasParms ? TEXT ( " &Parms " ) : TEXT ( " NULL " ) ) ;
2014-03-14 14:13:41 -04:00
for ( auto It = Parameters . Parms . CreateConstIterator ( ) ; It ; + + It )
{
UProperty * Param = * It ;
if ( Param - > HasAllPropertyFlags ( CPF_OutParm ) & & ! Param - > HasAnyPropertyFlags ( CPF_ConstParm | CPF_ReturnParm ) )
{
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t \t %s=Parms.%s; " ) LINE_TERMINATOR , * Param - > GetName ( ) , * Param - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP + = TEXT ( " \t \t } " ) LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
// else clause to call back into native if it's a BlueprintNativeEvent
if ( Function - > FunctionFlags & FUNC_Native )
{
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t else if (auto I = (%sI%s*)(O->GetNativeInterfaceAddress(U%s::StaticClass()))) " ) LINE_TERMINATOR , ConstQualifier , * ClassName , * ClassName ) ;
GeneratedPackageCPP + = TEXT ( " \t \t { " ) LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP + = TEXT ( " \t \t \t " ) ;
2014-03-14 14:13:41 -04:00
if ( Parameters . Return )
{
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP + = TEXT ( " Parms.ReturnValue = " ) ;
2014-03-14 14:13:41 -04:00
}
GeneratedPackageCPP . Logf ( TEXT ( " I->%s_Implementation( " ) , * FunctionName ) ;
bool First = true ;
for ( auto It = Parameters . Parms . CreateConstIterator ( ) ; It ; + + It )
{
UProperty * Param = * It ;
if ( ! First )
{
GeneratedPackageCPP . Logf ( TEXT ( " , " ) ) ;
}
First = false ;
GeneratedPackageCPP . Logf ( TEXT ( " %s " ) , * Param - > GetName ( ) ) ;
}
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " ); " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t } " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
}
if ( Parameters . Return )
{
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t return Parms.ReturnValue; " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t } " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-10-10 04:34:56 -04:00
/**
* Gets preprocessor string to emit GENERATED_U * _BODY ( ) macro is deprecated .
*
* @ param MacroName Name of the macro to be deprecated .
*
* @ returns Preprocessor string to emit the message .
*/
FString GetGeneratedMacroDeprecationWarning ( const TCHAR * MacroName )
{
// Deprecation warning is disabled right now. After people get familiar with the new macro it should be re-enabled.
//return FString() + TEXT("EMIT_DEPRECATED_WARNING_MESSAGE(\"") + MacroName + TEXT("() macro is deprecated. Please use GENERATED_BODY() macro instead.\")") LINE_TERMINATOR;
return TEXT ( " " ) ;
}
2014-10-13 10:31:50 -04:00
/**
* Returns a string with access specifier that was met before parsing GENERATED_BODY ( ) macro to preserve it .
*
* @ param Class Class for which to return the access specifier .
*
* @ returns Access specifier string .
*/
FString GetPreservedAccessSpecifierString ( FClass * Class )
{
2014-11-07 13:17:32 -05:00
FString PreservedAccessSpecifier ( FString : : Printf ( TEXT ( " static_assert(false, \" Unknown access specifier for GENERATED_BODY() macro in class % s . \ " ) ; " ), *GetNameSafe(Class)));
2015-04-30 10:25:31 -04:00
FClassMetaData * Data = GScriptHelper . FindClassData ( Class ) ;
2014-11-07 13:17:32 -05:00
if ( Data )
2014-10-13 10:31:50 -04:00
{
2014-11-07 13:17:32 -05:00
switch ( Data - > GeneratedBodyMacroAccessSpecifier )
{
case EAccessSpecifier : : ACCESS_Private :
PreservedAccessSpecifier = " private: " ;
break ;
case EAccessSpecifier : : ACCESS_Protected :
PreservedAccessSpecifier = " protected: " ;
break ;
case EAccessSpecifier : : ACCESS_Public :
PreservedAccessSpecifier = " public: " ;
break ;
2015-04-02 16:31:18 -04:00
case EAccessSpecifier : : ACCESS_NotAnAccessSpecifier :
break ;
2014-11-07 13:17:32 -05:00
}
2014-10-13 10:31:50 -04:00
}
return PreservedAccessSpecifier + LINE_TERMINATOR ;
}
2014-03-14 14:13:41 -04:00
/**
2015-01-20 09:33:54 -05:00
* Exports interface body macros .
2014-03-14 14:13:41 -04:00
*/
2015-03-27 18:10:52 -04:00
void ExportInterfaceBodyMacros ( FUHTStringBuilder & Out , FUnrealSourceFile & SourceFile , int32 ClassGeneratedBodyLine , FClass * Class , const FString & StdCtorCall , const FString & EnhCtorCall , const FString & UInterfaceBoilerplate )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
Out . Log ( TEXT ( " #undef GENERATED_UINTERFACE_BODY_COMMON \r \n " ) ) ;
Out . Log ( Macroize ( TEXT ( " GENERATED_UINTERFACE_BODY_COMMON() " ) , * UInterfaceBoilerplate ) ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
auto DeprecationWarning = GetGeneratedMacroDeprecationWarning ( TEXT ( " GENERATED_UINTERFACE_BODY " ) ) ;
auto DeprecationPushString = TEXT ( " PRAGMA_DISABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ;
2015-05-12 17:44:46 -04:00
auto DeprecationPopString = TEXT ( " PRAGMA_ENABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ;
2015-03-27 18:10:52 -04:00
auto Offset = TEXT ( " \t " ) ;
2015-01-20 09:33:54 -05:00
Out . Log ( Macroize ( * SourceFile . GetGeneratedBodyMacroName ( ClassGeneratedBodyLine , true ) , * ( FString ( ) +
Offset + DeprecationWarning +
Offset + DeprecationPushString +
Offset + TEXT ( " GENERATED_UINTERFACE_BODY_COMMON() " ) LINE_TERMINATOR +
StdCtorCall +
Offset + DeprecationPopString ) ) ) ;
Out . Log ( Macroize ( * SourceFile . GetGeneratedBodyMacroName ( ClassGeneratedBodyLine ) , * ( FString ( ) +
Offset + DeprecationPushString +
Offset + TEXT ( " GENERATED_UINTERFACE_BODY_COMMON() " ) LINE_TERMINATOR +
EnhCtorCall +
GetPreservedAccessSpecifierString ( Class ) +
Offset + DeprecationPopString ) ) ) ;
}
void FNativeClassHeaderGenerator : : ExportSourceFileHeader ( FClasses & AllClasses , FUnrealSourceFile * SourceFile )
{
TSet < const FUnrealSourceFile * > VisitedSet ;
ExportSourceFileHeaderRecursive ( AllClasses , SourceFile , VisitedSet , false ) ;
}
2015-03-27 18:10:52 -04:00
void WriteMacro ( FUHTStringBuilder & Output , const FString & MacroName , const FString & MacroContent )
2015-01-20 09:33:54 -05:00
{
Output . Log ( * Macroize ( * MacroName , * MacroContent ) ) ;
}
2015-03-17 09:34:18 -04:00
/**
* Writes to output device auto - includes for the given source file .
*
* @ param Out Output device .
* @ param SourceFile Source file .
*/
void ExportAutoIncludes ( FStringOutputDevice & Out , const FUnrealSourceFile & SourceFile )
{
for ( const auto & Include : SourceFile . GetIncludes ( ) )
{
if ( ! Include . IsAutoInclude ( ) )
{
continue ;
}
const auto * AutoIncludedSourceFile = Include . GetResolved ( ) ;
if ( AutoIncludedSourceFile = = nullptr )
{
continue ;
}
Out . Logf (
TEXT ( " #ifndef %s " ) LINE_TERMINATOR
TEXT ( " #include \" %s \" " ) LINE_TERMINATOR
TEXT ( " #endif " ) LINE_TERMINATOR
LINE_TERMINATOR ,
* AutoIncludedSourceFile - > GetFileDefineName ( ) , * AutoIncludedSourceFile - > GetIncludePath ( ) ) ;
}
}
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportClassesFromSourceFileInner ( FUnrealSourceFile & SourceFile )
{
2015-11-18 16:20:49 -05:00
CurrentSourceFile . Push ( & SourceFile ) ;
ON_SCOPE_EXIT
{
CurrentSourceFile . Pop ( ) ;
} ;
NameLookupCPP . SetCurrentSourceFile ( & SourceFile ) ;
UHTMakefile . AddToHeaderOrder ( & SourceFile ) ;
2015-01-20 09:33:54 -05:00
TArray < UEnum * > Enums ;
TArray < UScriptStruct * > Structs ;
TArray < UDelegateFunction * > DelegateFunctions ;
GeneratedHeaderText . Logf (
2015-03-17 09:34:18 -04:00
TEXT ( " #ifdef %s " ) LINE_TERMINATOR
2015-01-20 09:33:54 -05:00
TEXT ( " #error \" %s.generated.h already included, missing '#pragma once' in %s.h \" " ) LINE_TERMINATOR
TEXT ( " #endif " ) LINE_TERMINATOR
2015-03-17 09:34:18 -04:00
TEXT ( " #define %s " ) LINE_TERMINATOR
2015-01-20 09:33:54 -05:00
LINE_TERMINATOR ,
2015-03-17 09:34:18 -04:00
* SourceFile . GetFileDefineName ( ) , * SourceFile . GetStrippedFilename ( ) , * SourceFile . GetStrippedFilename ( ) , * SourceFile . GetFileDefineName ( ) ) ;
ExportAutoIncludes ( GeneratedHeaderText , SourceFile ) ;
2014-03-14 14:13:41 -04:00
// get the lists of fields that belong to this class that should be exported
2015-01-20 09:33:54 -05:00
SourceFile . GetScope ( ) - > SplitTypesIntoArrays ( Enums , Structs , DelegateFunctions ) ;
2014-03-14 14:13:41 -04:00
// export enum declarations
ExportEnums ( Enums ) ;
// export delegate definitions
2015-01-20 09:33:54 -05:00
ExportDelegateDefinitions ( SourceFile , DelegateFunctions , false ) ;
2014-03-14 14:13:41 -04:00
// Export enums declared in non-UClass headers.
ExportGeneratedEnumsInitCode ( Enums ) ;
2015-01-20 09:33:54 -05:00
// export boilerplate macros for structs
2015-11-18 16:20:49 -05:00
ExportGeneratedStructBodyMacros ( Structs ) ;
2014-03-14 14:13:41 -04:00
// export delegate wrapper function implementations
2015-01-20 09:33:54 -05:00
ExportDelegateDefinitions ( SourceFile , DelegateFunctions , true ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
for ( auto * RawUClass : SourceFile . GetDefinedClasses ( ) )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
PrologMacroCalls . Reset ( ) ;
InClassMacroCalls . Reset ( ) ;
InClassNoPureDeclsMacroCalls . Reset ( ) ;
StandardUObjectConstructorsMacroCall . Reset ( ) ;
EnhancedUObjectConstructorsMacroCall . Reset ( ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
auto * Class = ( FClass * ) RawUClass ;
if ( Class - > ClassFlags & CLASS_Intrinsic )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
continue ;
2014-03-14 14:13:41 -04:00
}
2015-04-30 10:25:31 -04:00
auto * ClassData = GScriptHelper . FindClassData ( Class ) ;
check ( ClassData ) ;
2015-01-20 09:33:54 -05:00
// C++ -> VM stubs (native function execs)
ExportNativeFunctions ( SourceFile , Class , ClassData ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
// VM -> C++ proxies (events and delegates).
TArray < UFunction * > CallbackFunctions = ExportCallbackFunctions ( SourceFile , Class , ClassData ) ;
// Class definition.
ExportNatives ( Class ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder FriendText ;
2015-01-20 09:33:54 -05:00
ExportNativeGeneratedInitCode ( Class , FriendText ) ;
FClass * SuperClass = Class - > GetSuperClass ( ) ;
// the name for the C++ version of the UClass
const TCHAR * ClassCPPName = NameLookupCPP . GetNameCPP ( Class ) ;
const TCHAR * SuperClassCPPName = ( SuperClass ! = nullptr ) ? NameLookupCPP . GetNameCPP ( SuperClass ) : nullptr ;
if ( Class - > HasAnyClassFlags ( CLASS_Interface ) )
2014-03-14 14:13:41 -04:00
{
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder UInterfaceBoilerplate ;
2015-01-20 09:33:54 -05:00
// Export the class's native function registration.
2015-09-21 07:53:49 -04:00
UInterfaceBoilerplate . Logf ( TEXT ( " \t private: \r \n " ) ) ;
UInterfaceBoilerplate . Logf ( TEXT ( " \t static void StaticRegisterNatives%s(); \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2015-01-20 09:33:54 -05:00
UInterfaceBoilerplate . Log ( * FriendText ) ;
2015-03-27 18:10:52 -04:00
FriendText . Reset ( ) ;
2015-01-20 09:33:54 -05:00
UInterfaceBoilerplate . Logf ( TEXT ( " public: \r \n " ) ) ;
// Build the DECLARE_CLASS line
FString APIArg ( API ) ;
if ( ! Class - > HasAnyClassFlags ( CLASS_MinimalAPI ) )
{
APIArg = TEXT ( " NO " ) ;
}
const bool bCastedClass = Class - > HasAnyCastFlag ( CASTCLASS_AllFlags ) & & SuperClass & & Class - > ClassCastFlags ! = SuperClass - > ClassCastFlags ;
2015-11-18 16:20:49 -05:00
UInterfaceBoilerplate . Logf ( TEXT ( " \t DECLARE_CLASS(%s, %s, COMPILED_IN_FLAGS(CLASS_Abstract%s), %s, TEXT( \" %s \" ), %s_API) \r \n " ) ,
2015-01-20 09:33:54 -05:00
ClassCPPName ,
SuperClassCPPName ,
* GetClassFlagExportText ( Class ) ,
bCastedClass ? * FString : : Printf ( TEXT ( " CASTCLASS_%s " ) , ClassCPPName ) : TEXT ( " 0 " ) ,
2015-11-18 16:20:49 -05:00
* FClass : : GetTypePackageName ( Class ) ,
2015-01-20 09:33:54 -05:00
* APIArg ) ;
2015-09-21 07:53:49 -04:00
UInterfaceBoilerplate . Logf ( TEXT ( " \t DECLARE_SERIALIZER(%s) \r \n " ) , ClassCPPName ) ;
UInterfaceBoilerplate . Log ( TEXT ( " \t enum {IsIntrinsic=COMPILED_IN_INTRINSIC}; \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
if ( Class - > ClassWithin ! = Class - > GetSuperClass ( ) - > ClassWithin )
{
2015-09-21 07:53:49 -04:00
UInterfaceBoilerplate . Logf ( TEXT ( " \t DECLARE_WITHIN(%s) \r \n " ) , NameLookupCPP . GetNameCPP ( Class - > GetClassWithin ( ) ) ) ;
2015-01-20 09:33:54 -05:00
}
ExportConstructorsMacros ( SourceFile . GetGeneratedMacroName ( ClassData ) , Class ) ;
ExportInterfaceBodyMacros ( GeneratedHeaderText , SourceFile , ClassData - > GetGeneratedBodyLine ( ) , Class , StandardUObjectConstructorsMacroCall , EnhancedUObjectConstructorsMacroCall , UInterfaceBoilerplate ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
// =============================================
// Export the pure interface version of the class
// the name of the pure interface class
FString InterfaceCPPName = FString : : Printf ( TEXT ( " I%s " ) , * Class - > GetName ( ) ) ;
FString SuperInterfaceCPPName ;
if ( SuperClass ! = NULL )
{
SuperInterfaceCPPName = FString : : Printf ( TEXT ( " I%s " ) , * SuperClass - > GetName ( ) ) ;
}
// Thunk functions
2015-03-27 18:10:52 -04:00
FUHTStringBuilder InterfaceBoilerplate ;
2015-01-20 09:33:54 -05:00
InterfaceBoilerplate . Logf ( TEXT ( " protected: \r \n \t virtual ~%s() {} \r \n public: \r \n " ) , * InterfaceCPPName ) ;
InterfaceBoilerplate . Logf ( TEXT ( " \t typedef %s UClassType; \r \n " ) , ClassCPPName ) ;
2015-11-18 16:20:49 -05:00
ExportInterfaceCallFunctions ( CallbackFunctions , Class , InterfaceBoilerplate ) ;
2015-01-20 09:33:54 -05:00
// we'll need a way to get to the UObject portion of a native interface, so that we can safely pass native interfaces
// to script VM functions
if ( SuperClass - > IsChildOf ( UInterface : : StaticClass ( ) ) )
{
InterfaceBoilerplate . Logf ( TEXT ( " \t virtual UObject* _getUObject() const = 0; \r \n " ) ) ;
}
// Replication, add in the declaration for GetLifetimeReplicatedProps() automatically if there are any net flagged properties
bool bNeedsRep = false ;
auto ClassName = FString ( NameLookupCPP . GetNameCPP ( Class ) ) ;
for ( TFieldIterator < UProperty > It ( Class , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
{
if ( ( It - > PropertyFlags & CPF_Net ) ! = 0 )
{
bNeedsRep = true ;
break ;
}
}
auto ClassRange = ClassDefinitionRange ( ) ;
if ( ClassDefinitionRanges . Contains ( Class ) )
{
ClassRange = ClassDefinitionRanges [ Class ] ;
2015-07-15 13:24:05 -04:00
ClassRange . Validate ( ) ;
2015-01-20 09:33:54 -05:00
}
auto ClassStart = ClassRange . Start ;
auto ClassEnd = ClassRange . End ;
auto ClassDefinition = FString ( ClassEnd - ClassStart , ClassStart ) ;
2015-04-10 06:02:22 -04:00
bool bHasGetLifetimeReplicatedProps = HasIdentifierExactMatch ( ClassDefinition , TEXT ( " GetLifetimeReplicatedProps " ) ) ;
2015-01-20 09:33:54 -05:00
if ( bNeedsRep & & ! bHasGetLifetimeReplicatedProps )
{
2015-04-10 06:02:22 -04:00
if ( SourceFile . GetGeneratedCodeVersionForStruct ( Class ) = = EGeneratedCodeVersion : : V1 )
{
InterfaceBoilerplate . Logf ( TEXT ( " \v oid GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const; \r \n " ) ) ;
}
else
{
FError : : Throwf ( TEXT ( " Class %s has Net flagged properties and should declare member function: void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override " ) , ClassCPPName ) ;
}
2015-01-20 09:33:54 -05:00
}
auto NoPureDeclsMacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _INCLASS_IINTERFACE_NO_PURE_DECLS " ) ) ;
WriteMacro ( GeneratedHeaderText , NoPureDeclsMacroName , InterfaceBoilerplate ) ;
2015-03-27 18:10:52 -04:00
InClassNoPureDeclsMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * NoPureDeclsMacroName ) ;
2015-01-20 09:33:54 -05:00
auto MacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _INCLASS_IINTERFACE " ) ) ;
2015-04-10 06:02:22 -04:00
WriteMacro ( GeneratedHeaderText , MacroName , InterfaceBoilerplate ) ;
2015-03-27 18:10:52 -04:00
InClassMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * MacroName ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
else
2014-12-11 11:49:41 -05:00
{
2015-04-22 14:15:56 -04:00
FUHTStringBuilder ClassBoilerplate ;
2014-03-14 14:13:41 -04:00
2015-04-22 14:15:56 -04:00
// Export the class's native function registration.
2015-09-21 07:53:49 -04:00
ClassBoilerplate . Logf ( TEXT ( " \t private: \r \n " ) ) ;
ClassBoilerplate . Logf ( TEXT ( " \t static void StaticRegisterNatives%s(); \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2015-04-22 14:15:56 -04:00
ClassBoilerplate . Log ( * FriendText ) ;
2015-09-21 07:53:49 -04:00
ClassBoilerplate . Logf ( TEXT ( " \t public: \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
2015-04-22 14:15:56 -04:00
// Build the DECLARE_CLASS line
FString APIArg ( API ) ;
if ( ! Class - > HasAnyClassFlags ( CLASS_MinimalAPI ) )
2014-03-14 14:13:41 -04:00
{
2015-04-22 14:15:56 -04:00
APIArg = TEXT ( " NO " ) ;
}
const bool bCastedClass = Class - > HasAnyCastFlag ( CASTCLASS_AllFlags ) & & SuperClass & & Class - > ClassCastFlags ! = SuperClass - > ClassCastFlags ;
2015-11-18 16:20:49 -05:00
ClassBoilerplate . Logf ( TEXT ( " \t DECLARE_CLASS(%s, %s, COMPILED_IN_FLAGS(%s%s), %s, TEXT( \" %s \" ), %s_API) \r \n " ) ,
2015-04-22 14:15:56 -04:00
ClassCPPName ,
SuperClassCPPName ? SuperClassCPPName : TEXT ( " None " ) ,
Class - > HasAnyClassFlags ( CLASS_Abstract ) ? TEXT ( " CLASS_Abstract " ) : TEXT ( " 0 " ) ,
* GetClassFlagExportText ( Class ) ,
bCastedClass ? * FString : : Printf ( TEXT ( " CASTCLASS_%s " ) , ClassCPPName ) : TEXT ( " 0 " ) ,
2015-11-18 16:20:49 -05:00
* FClass : : GetTypePackageName ( Class ) ,
2015-04-22 14:15:56 -04:00
* APIArg ) ;
2014-03-14 14:13:41 -04:00
2015-09-21 07:53:49 -04:00
ClassBoilerplate . Logf ( TEXT ( " \t DECLARE_SERIALIZER(%s) \r \n " ) , ClassCPPName ) ;
ClassBoilerplate . Log ( TEXT ( " \t /** Indicates whether the class is compiled into the engine */ \r \n " ) ) ;
ClassBoilerplate . Log ( TEXT ( " \t enum {IsIntrinsic=COMPILED_IN_INTRINSIC}; \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
2015-04-22 14:15:56 -04:00
if ( SuperClass & & Class - > ClassWithin ! = SuperClass - > ClassWithin )
{
2015-09-21 07:53:49 -04:00
ClassBoilerplate . Logf ( TEXT ( " \t DECLARE_WITHIN(%s) \r \n " ) , NameLookupCPP . GetNameCPP ( Class - > GetClassWithin ( ) ) ) ;
2015-04-22 14:15:56 -04:00
}
// export the class's config name
if ( SuperClass & & Class - > ClassConfigName ! = NAME_None & & Class - > ClassConfigName ! = SuperClass - > ClassConfigName )
{
2015-09-21 07:53:49 -04:00
ClassBoilerplate . Logf ( TEXT ( " \t static const TCHAR* StaticConfigName() {return TEXT( \" %s \" );} \r \n \r \n " ) , * Class - > ClassConfigName . ToString ( ) ) ;
2015-04-22 14:15:56 -04:00
}
2015-08-21 07:27:28 -04:00
// export implementation of _getUObject for classes that implement interfaces
if ( Class - > Interfaces . Num ( ) > 0 )
2015-04-22 14:15:56 -04:00
{
ClassBoilerplate . Logf ( TEXT ( " \t virtual UObject* _getUObject() const override { return const_cast<%s*>(this); } \r \n " ) , ClassCPPName ) ;
}
// Replication, add in the declaration for GetLifetimeReplicatedProps() automatically if there are any net flagged properties
bool bHasNetFlaggedProperties = false ;
for ( TFieldIterator < UProperty > It ( Class , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
{
if ( ( It - > PropertyFlags & CPF_Net ) ! = 0 )
2014-03-14 14:13:41 -04:00
{
2015-04-22 14:15:56 -04:00
bHasNetFlaggedProperties = true ;
break ;
2014-03-14 14:13:41 -04:00
}
2015-04-22 14:15:56 -04:00
}
2014-10-10 04:34:56 -04:00
2015-04-22 14:15:56 -04:00
auto ClassRange = ClassDefinitionRange ( ) ;
if ( ClassDefinitionRanges . Contains ( Class ) )
{
ClassRange = ClassDefinitionRanges [ Class ] ;
2015-07-15 13:24:05 -04:00
ClassRange . Validate ( ) ;
2015-04-22 14:15:56 -04:00
}
2014-03-14 14:13:41 -04:00
2015-04-22 14:15:56 -04:00
auto ClassStart = ClassRange . Start ;
auto ClassEnd = ClassRange . End ;
auto ClassDefinition = FString ( ClassEnd - ClassStart , ClassStart ) ;
bool bHasGetLifetimeReplicatedProps = HasIdentifierExactMatch ( ClassDefinition , TEXT ( " GetLifetimeReplicatedProps " ) ) ;
if ( bHasNetFlaggedProperties & & ! bHasGetLifetimeReplicatedProps )
{
// Default version autogenerates declarations.
if ( SourceFile . GetGeneratedCodeVersionForStruct ( Class ) = = EGeneratedCodeVersion : : V1 )
2014-03-14 14:13:41 -04:00
{
2015-04-22 14:15:56 -04:00
ClassBoilerplate . Logf ( TEXT ( " \t void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override; \r \n " ) ) ;
2015-03-26 18:31:15 -04:00
}
else
{
2015-04-22 14:15:56 -04:00
FError : : Throwf ( TEXT ( " Class %s has Net flagged properties and should declare member function: void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override " ) , ClassCPPName ) ;
2015-03-26 18:31:15 -04:00
}
2014-03-14 14:13:41 -04:00
}
2015-04-22 14:15:56 -04:00
auto NoPureDeclsMacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _INCLASS_NO_PURE_DECLS " ) ) ;
WriteMacro ( GeneratedHeaderText , NoPureDeclsMacroName , ClassBoilerplate ) ;
InClassNoPureDeclsMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * NoPureDeclsMacroName ) ;
FString MacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _INCLASS " ) ) ;
WriteMacro ( GeneratedHeaderText , MacroName , ClassBoilerplate ) ;
InClassMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * MacroName ) ;
ExportConstructorsMacros ( SourceFile . GetGeneratedMacroName ( ClassData ) , Class ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
{
FString MacroName = SourceFile . GetGeneratedMacroName ( ClassData - > GetPrologLine ( ) , TEXT ( " _PROLOG " ) ) ;
WriteMacro ( GeneratedHeaderText , MacroName , PrologMacroCalls ) ;
}
{
bool bIsIInterface = Class - > HasAnyClassFlags ( CLASS_Interface ) ;
2015-03-17 05:19:11 -04:00
auto MacroName = FString : : Printf ( TEXT ( " GENERATED_%s_BODY() " ) , bIsIInterface ? TEXT ( " IINTERFACE " ) : TEXT ( " UCLASS " ) ) ;
2015-01-20 09:33:54 -05:00
auto DeprecationWarning = bIsIInterface ? FString ( TEXT ( " " ) ) : GetGeneratedMacroDeprecationWarning ( * MacroName ) ;
auto DeprecationPushString = TEXT ( " PRAGMA_DISABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ;
2015-05-12 17:44:46 -04:00
auto DeprecationPopString = TEXT ( " PRAGMA_ENABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ;
2015-01-20 09:33:54 -05:00
auto Public = TEXT ( " public: " LINE_TERMINATOR ) ;
2015-03-17 05:19:11 -04:00
auto GeneratedBodyLine = bIsIInterface ? ClassData - > GetInterfaceGeneratedBodyLine ( ) : ClassData - > GetGeneratedBodyLine ( ) ;
auto LegacyGeneratedBody = InClassMacroCalls + ( bIsIInterface ? TEXT ( " " ) : StandardUObjectConstructorsMacroCall ) ;
auto GeneratedBody = InClassNoPureDeclsMacroCalls + ( bIsIInterface ? TEXT ( " " ) : EnhancedUObjectConstructorsMacroCall ) ;
2015-01-20 09:33:54 -05:00
2015-03-17 05:19:11 -04:00
auto WrappedLegacyGeneratedBody = DeprecationWarning + DeprecationPushString + Public + LegacyGeneratedBody + Public + DeprecationPopString ;
auto WrappedGeneratedBody = FString ( DeprecationPushString ) + Public + GeneratedBody + GetPreservedAccessSpecifierString ( Class ) + DeprecationPopString ;
2015-01-20 09:33:54 -05:00
2015-03-17 05:19:11 -04:00
auto BodyMacros = Macroize ( * SourceFile . GetGeneratedBodyMacroName ( GeneratedBodyLine , true ) , * WrappedLegacyGeneratedBody ) +
Macroize ( * SourceFile . GetGeneratedBodyMacroName ( GeneratedBodyLine , false ) , * WrappedGeneratedBody ) ;
2015-01-20 09:33:54 -05:00
GeneratedHeaderText . Log ( * BodyMacros ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
if ( GPublicSourceFileSet . Contains ( & SourceFile ) & & ! ListOfPublicHeaderGroupIncludes . Contains ( & SourceFile ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
ListOfPublicHeaderGroupIncludes . Add ( & SourceFile ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-10-31 04:01:12 -04:00
/**
* Generates private copy - constructor declaration .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor for .
* @ param API API string for this constructor .
*/
2015-03-27 18:10:52 -04:00
void ExportCopyConstructorDefinition ( FUHTStringBuilder & Out , FClass * Class , const FString & API )
2014-10-31 04:01:12 -04:00
{
auto ClassNameCPP = NameLookupCPP . GetNameCPP ( Class ) ;
Out . Logf ( TEXT ( " private: \r \n " ) ) ;
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t /** Private copy-constructor, should never be used */ \r \n " ) ) ;
Out . Logf ( TEXT ( " \t %s_API %s(const %s& InCopy); \r \n " ) , * API , ClassNameCPP , ClassNameCPP ) ;
2014-10-31 04:01:12 -04:00
Out . Logf ( TEXT ( " public: \r \n " ) ) ;
}
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
/**
* Generates vtable helper constructor declaration .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor for .
* @ param API API string for this constructor .
*/
void ExportVTableHelperConstructorDecl ( FStringOutputDevice & Out , FClass * Class , const FString & API )
{
auto * ClassData = GScriptHelper . FindClassData ( Class ) ;
2015-04-30 10:25:31 -04:00
check ( ClassData ) ;
2015-03-02 06:44:04 -05:00
if ( ! ClassData - > bCustomVTableHelperConstructorDeclared )
{
2015-09-21 07:53:49 -04:00
Out . Logf ( TEXT ( " \t DECLARE_VTABLE_PTR_HELPER_CTOR(%s_API, %s); " LINE_TERMINATOR ) , * API , NameLookupCPP . GetNameCPP ( Class ) ) ;
2015-03-02 06:44:04 -05:00
}
}
/**
* Generates vtable helper ctor caller .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate for .
*/
void ExportVTableHelperCtorCaller ( FStringOutputDevice & Out , FClass * Class )
{
Out . Logf ( TEXT ( " DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(%s); " LINE_TERMINATOR ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
}
/**
* Generates vtable helper ctor caller dummy .
*
* @ param Out Output device to generate to .
*/
void ExportVTableHelperCtorCallerDummy ( FStringOutputDevice & Out )
{
Out . Logf ( TEXT ( " DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER_DUMMY(); " LINE_TERMINATOR ) ) ;
}
/**
* Generates vtable helper constructor body .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor for .
* @ param API API string for this constructor .
*/
void ExportVTableHelperConstructorBody ( FStringOutputDevice & Out , FClass * Class )
{
auto * ClassData = GScriptHelper . FindClassData ( Class ) ;
2015-04-30 10:25:31 -04:00
check ( ClassData ) ;
2015-03-02 06:44:04 -05:00
if ( ! ClassData - > bCustomVTableHelperConstructorDeclared )
{
2015-09-21 07:53:49 -04:00
Out . Logf ( TEXT ( " \t DEFINE_VTABLE_PTR_HELPER_CTOR(%s); " LINE_TERMINATOR ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2015-03-02 06:44:04 -05:00
}
}
/**
* Generates vtable helper caller and eventual constructor body .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate for .
* @ param API API string .
* @ param bExportVTableConstructors Tells if we are going to export constructors as well .
*/
void ExportVTableHelperCtorAndCaller ( FStringOutputDevice & Out , FClass * Class , const FString & API , bool bExportVTableConstructors )
{
if ( bExportVTableConstructors )
{
ExportVTableHelperConstructorDecl ( Out , Class , API ) ;
ExportVTableHelperCtorCaller ( Out , Class ) ;
}
else
{
ExportVTableHelperCtorCallerDummy ( Out ) ;
}
}
# endif // WITH_HOT_RELOAD_CTORS
2014-10-10 04:34:56 -04:00
/**
* Generates standard constructor declaration .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor for .
* @ param API API string for this constructor .
2015-03-02 06:44:04 -05:00
* @ param bExportVTableConstructors Export VTable constructors .
2014-10-10 04:34:56 -04:00
*/
2015-03-27 18:10:52 -04:00
void ExportStandardConstructorsMacro ( FUHTStringBuilder & Out , FClass * Class , const FString & API
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
, bool bExportVTableConstructors
# endif // WITH_HOT_RELOAD_CTORS
)
2014-10-10 04:34:56 -04:00
{
if ( ! Class - > HasAnyClassFlags ( CLASS_CustomConstructor ) )
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t /** Standard constructor, called after all reflected properties have been initialized */ \r \n " ) ) ;
2015-04-21 04:37:32 -04:00
auto * ClassData = GScriptHelper . FindClassData ( Class ) ;
2015-04-30 10:25:31 -04:00
check ( ClassData ) ;
2015-04-21 04:37:32 -04:00
Out . Logf ( TEXT ( " \t %s_API %s(const FObjectInitializer& ObjectInitializer%s); \r \n " ) , * API , NameLookupCPP . GetNameCPP ( Class ) ,
ClassData - > bDefaultConstructorDeclared ? TEXT ( " " ) : TEXT ( " = FObjectInitializer::Get() " ) ) ;
2014-10-10 04:34:56 -04:00
}
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(%s) \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
ExportVTableHelperCtorAndCaller ( Out , Class , API , bExportVTableConstructors ) ;
# endif // WITH_HOT_RELOAD_CTORS
2014-10-31 04:01:12 -04:00
ExportCopyConstructorDefinition ( Out , Class , API ) ;
2014-10-10 04:34:56 -04:00
}
/**
* Generates constructor definition .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor for .
* @ param API API string for this constructor .
*/
2015-03-27 18:10:52 -04:00
void ExportConstructorDefinition ( FUHTStringBuilder & Out , FClass * Class , const FString & API )
2014-10-10 04:34:56 -04:00
{
auto * ClassData = GScriptHelper . FindClassData ( Class ) ;
2015-04-30 10:25:31 -04:00
check ( ClassData ) ;
2014-10-10 04:34:56 -04:00
if ( ! ClassData - > bConstructorDeclared )
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t /** Standard constructor, called after all reflected properties have been initialized */ \r \n " ) ) ;
2015-02-14 17:40:09 -05:00
// Assume super class has OI constructor, this may not always be true but we should always be able to check this.
// In any case, it will default to old behaviour before we even checked this.
bool bSuperClassObjectInitializerConstructorDeclared = true ;
auto * SuperClass = Class - > GetSuperClass ( ) ;
if ( SuperClass ! = nullptr )
{
auto * SuperClassData = GScriptHelper . FindClassData ( SuperClass ) ;
if ( SuperClassData )
{
bSuperClassObjectInitializerConstructorDeclared = SuperClassData - > bObjectInitializerConstructorDeclared ;
}
}
if ( bSuperClassObjectInitializerConstructorDeclared )
{
2015-04-21 04:37:32 -04:00
Out . Logf ( TEXT ( " \t %s_API %s(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { }; \r \n " ) , * API , NameLookupCPP . GetNameCPP ( Class ) ) ;
2015-02-14 17:40:09 -05:00
ClassData - > bObjectInitializerConstructorDeclared = true ;
}
else
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t %s_API %s() { }; \r \n " ) , * API , NameLookupCPP . GetNameCPP ( Class ) ) ;
2015-02-14 17:40:09 -05:00
ClassData - > bDefaultConstructorDeclared = true ;
}
2014-10-10 04:34:56 -04:00
ClassData - > bConstructorDeclared = true ;
}
2014-10-31 04:01:12 -04:00
ExportCopyConstructorDefinition ( Out , Class , API ) ;
2014-10-10 04:34:56 -04:00
}
/**
* Generates constructor call definition .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor call definition for .
*/
2015-03-27 18:10:52 -04:00
void ExportDefaultConstructorCallDefinition ( FUHTStringBuilder & Out , FClass * Class )
2014-10-10 04:34:56 -04:00
{
auto * ClassData = GScriptHelper . FindClassData ( Class ) ;
2015-04-30 10:25:31 -04:00
check ( ClassData ) ;
2014-10-10 04:34:56 -04:00
2014-10-14 10:29:11 -04:00
if ( ClassData - > bObjectInitializerConstructorDeclared )
2014-10-10 04:34:56 -04:00
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(%s) \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2014-10-10 04:34:56 -04:00
}
else if ( ClassData - > bDefaultConstructorDeclared )
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t DEFINE_DEFAULT_CONSTRUCTOR_CALL(%s) \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2014-10-10 04:34:56 -04:00
}
else
{
2015-03-27 18:10:52 -04:00
Out . Logf ( TEXT ( " \t DEFINE_FORBIDDEN_DEFAULT_CONSTRUCTOR_CALL(%s) \r \n " ) , NameLookupCPP . GetNameCPP ( Class ) ) ;
2014-10-10 04:34:56 -04:00
}
}
/**
* Generates enhanced constructor declaration .
*
* @ param Out Output device to generate to .
* @ param Class Class to generate constructor for .
* @ param API API string for this constructor .
2015-03-02 06:44:04 -05:00
* @ param bExportVTableConstructors Export VTable constructors .
2014-10-10 04:34:56 -04:00
*/
2015-03-27 18:10:52 -04:00
void ExportEnhancedConstructorsMacro ( FUHTStringBuilder & Out , FClass * Class , const FString & API
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
, bool bExportVTableConstructors
# endif // WITH_HOT_RELOAD_CTORS
)
2014-10-10 04:34:56 -04:00
{
ExportConstructorDefinition ( Out , Class , API ) ;
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
ExportVTableHelperCtorAndCaller ( Out , Class , API , bExportVTableConstructors ) ;
# endif // WITH_HOT_RELOAD_CTORS
2014-10-10 04:34:56 -04:00
ExportDefaultConstructorCallDefinition ( Out , Class ) ;
}
2015-01-21 12:32:28 -05:00
/**
* Gets a package relative inclusion path of the given source file for build .
*
* @ param SourceFile Given source file .
*
* @ returns Inclusion path .
*/
FString GetBuildPath ( FUnrealSourceFile & SourceFile )
{
FString Out = SourceFile . GetFilename ( ) ;
ConvertToBuildIncludePath ( SourceFile . GetPackage ( ) , Out ) ;
return Out ;
}
2015-11-18 16:20:49 -05:00
FString FNativeClassHeaderGenerator : : GetListOfPublicHeaderGroupIncludesString ( const UPackage * InPackage )
2015-01-20 09:33:54 -05:00
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder Out ;
2015-01-20 09:33:54 -05:00
// Fill with the rest source files from this package.
for ( auto * SourceFile : GPublicSourceFileSet )
{
2015-04-22 14:15:56 -04:00
if ( SourceFile - > GetPackage ( ) = = InPackage & & ! ListOfPublicHeaderGroupIncludes . Contains ( SourceFile ) )
2015-01-20 09:33:54 -05:00
{
ListOfPublicHeaderGroupIncludes . Add ( SourceFile ) ;
}
}
for ( auto * SourceFile : ListOfPublicHeaderGroupIncludes )
{
2015-01-21 12:32:28 -05:00
Out . Logf ( TEXT ( " #include \" %s \" " ) LINE_TERMINATOR , * GetBuildPath ( * SourceFile ) ) ;
2015-01-20 09:33:54 -05:00
}
Out . Log ( LINE_TERMINATOR ) ;
return Out ;
}
void FNativeClassHeaderGenerator : : ExportConstructorsMacros ( const FString & ConstructorsMacroPrefix , FClass * Class )
2014-10-10 04:34:56 -04:00
{
FString APIArg ( API ) ;
if ( ! Class - > HasAnyClassFlags ( CLASS_MinimalAPI ) )
{
APIArg = TEXT ( " NO " ) ;
}
2015-03-27 18:10:52 -04:00
FUHTStringBuilder StdMacro ;
FUHTStringBuilder EnhMacro ;
2015-01-20 09:33:54 -05:00
FString StdMacroName = ConstructorsMacroPrefix + TEXT ( " _STANDARD_CONSTRUCTORS " ) ;
FString EnhMacroName = ConstructorsMacroPrefix + TEXT ( " _ENHANCED_CONSTRUCTORS " ) ;
2014-10-10 04:34:56 -04:00
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
ExportStandardConstructorsMacro ( StdMacro , Class , APIArg , bExportVTableConstructors ) ;
ExportEnhancedConstructorsMacro ( EnhMacro , Class , APIArg , bExportVTableConstructors ) ;
if ( bExportVTableConstructors )
{
ExportVTableHelperConstructorBody ( GetGeneratedFunctionTextDevice ( ) , Class ) ;
}
# else // WITH_HOT_RELOAD_CTORS
2014-10-10 04:34:56 -04:00
ExportStandardConstructorsMacro ( StdMacro , Class , APIArg ) ;
ExportEnhancedConstructorsMacro ( EnhMacro , Class , APIArg ) ;
2015-03-02 06:44:04 -05:00
# endif // WITH_HOT_RELOAD_CTORS
2014-10-10 04:34:56 -04:00
GeneratedHeaderText . Log ( * Macroize ( * StdMacroName , * StdMacro ) ) ;
GeneratedHeaderText . Log ( * Macroize ( * EnhMacroName , * EnhMacro ) ) ;
2015-03-27 18:10:52 -04:00
StandardUObjectConstructorsMacroCall . Logf ( TEXT ( " \t %s \r \n " ) , * StdMacroName ) ;
EnhancedUObjectConstructorsMacroCall . Logf ( TEXT ( " \t %s \r \n " ) , * EnhMacroName ) ;
2014-10-10 04:34:56 -04:00
}
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportClassesFromSourceFileWrapper ( FUnrealSourceFile & SourceFile )
2014-03-14 14:13:41 -04:00
{
2015-11-18 16:20:49 -05:00
CurrentSourceFile . Push ( & SourceFile ) ;
ON_SCOPE_EXIT
{
CurrentSourceFile . Pop ( ) ;
} ;
2014-03-14 14:13:41 -04:00
check ( ! GeneratedHeaderText . Len ( ) ) ;
2015-01-20 09:33:54 -05:00
ExportClassesFromSourceFileInner ( SourceFile ) ;
2014-03-14 14:13:41 -04:00
if ( ! GeneratedHeaderText . Len ( ) & & ! EnumForeachText . Len ( ) )
{
// Nothing to export
return ;
}
2015-01-20 09:33:54 -05:00
GeneratedHeaderText . Logf ( TEXT ( " #undef CURRENT_FILE_ID \r \n " ) ) ;
GeneratedHeaderText . Logf ( TEXT ( " #define CURRENT_FILE_ID %s \r \n \r \n \r \n " ) , * SourceFile . GetFileId ( ) ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
const FString SourceFilename = SourceFile . GetFilename ( ) ;
const FString PkgName = FPackageName : : GetShortName ( Package ) ;
2014-03-14 14:13:41 -04:00
FString NewFileName = SourceFilename . EndsWith ( TEXT ( " .h " ) ) ? SourceFilename : ( SourceFilename + TEXT ( " .h " ) ) ;
FString PkgDir ;
FString GeneratedIncludeDirectory ;
2014-09-18 04:05:01 -04:00
if ( FindPackageLocation ( * PkgName , PkgDir , GeneratedIncludeDirectory ) = = false )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Error , TEXT ( " Failed to find path for package %s " ) , * PkgName ) ;
}
2015-01-20 09:33:54 -05:00
const FString ClassHeaderPath ( GeneratedIncludeDirectory / FPaths : : GetBaseFilename ( SourceFile . GetFilename ( ) ) + TEXT ( " .generated.h " ) ) ;
GeneratedHeaderText + = EnumForeachText ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder GeneratedHeaderTextWithCopyright ;
2015-01-20 09:33:54 -05:00
GeneratedHeaderTextWithCopyright . Log (
TEXT ( " // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. \r \n " )
TEXT ( " /*=========================================================================== \r \n " )
2015-09-21 07:53:49 -04:00
TEXT ( " \t C++ class header boilerplate exported from UnrealHeaderTool. \r \n " )
TEXT ( " \t This is automatically generated by the tools. \r \n " )
TEXT ( " \t DO NOT modify this manually! Edit the corresponding .h files instead! \r \n " )
2015-01-20 09:33:54 -05:00
TEXT ( " ===========================================================================*/ \r \n " ) ) ;
GeneratedHeaderTextWithCopyright . Log (
LINE_TERMINATOR
TEXT ( " #include \" ObjectBase.h \" " ) LINE_TERMINATOR
LINE_TERMINATOR ) ;
2015-03-10 08:24:59 -04:00
GeneratedHeaderTextWithCopyright . Logf ( TEXT ( " PRAGMA_DISABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ) ;
2015-01-20 09:33:54 -05:00
GeneratedHeaderTextWithCopyright . Log ( * GeneratedHeaderTextBeforeForwardDeclarations ) ;
TSet < FString > ForwardDeclarationStrings ;
for ( auto Property : ForwardDeclarations )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
auto FWDecl = Property - > GetCPPTypeForwardDeclaration ( ) ;
if ( FWDecl . Len ( ) > 0 )
2014-12-11 11:49:41 -05:00
{
2015-01-20 09:33:54 -05:00
ForwardDeclarationStrings . Add ( FWDecl ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-01-20 09:33:54 -05:00
for ( auto FWDeclString : ForwardDeclarationStrings )
{
GeneratedForwardDeclarations . Logf ( TEXT ( " %s \r \n " ) , * FWDeclString ) ;
}
GeneratedHeaderTextWithCopyright . Log ( * GeneratedForwardDeclarations ) ;
GeneratedHeaderTextWithCopyright . Log ( * GeneratedHeaderText ) ;
2015-03-10 08:24:59 -04:00
GeneratedHeaderTextWithCopyright . Logf ( TEXT ( " PRAGMA_ENABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ) ;
2015-01-20 09:33:54 -05:00
SourceFile . SetGeneratedFilename ( ClassHeaderPath ) ;
SourceFile . SetHasChanged ( SaveHeaderIfChanged ( * ClassHeaderPath , * GeneratedHeaderTextWithCopyright ) ) ;
check ( SourceFilename . EndsWith ( TEXT ( " .h " ) ) ) ;
ConvertToBuildIncludePath ( Package , NewFileName ) ;
auto IncludeStr = FString : : Printf (
2015-03-17 09:34:18 -04:00
TEXT ( " #ifndef %s " ) LINE_TERMINATOR
2015-09-21 07:53:49 -04:00
TEXT ( " \t #include \" %s \" " ) LINE_TERMINATOR
2015-03-17 09:34:18 -04:00
TEXT ( " #endif " ) LINE_TERMINATOR ,
* SourceFile . GetFileDefineName ( ) , * NewFileName ) ;
2015-01-20 09:33:54 -05:00
// Keep track of all of the UObject headers for this module, in the same order that we digest them in
// @todo uht: We're wrapping these includes in checks for header guards, ONLY because most existing UObject headers are missing '#pragma once'
ListOfAllUObjectHeaderIncludes . Logf ( TEXT ( " %s " ) , * IncludeStr ) ;
ListOfPublicClassesUObjectHeaderModuleIncludes . Logf ( TEXT ( " %s " ) , * IncludeStr ) ;
2015-03-27 18:10:52 -04:00
ForwardDeclarations . Reset ( ) ;
GeneratedHeaderTextBeforeForwardDeclarations . Reset ( ) ;
GeneratedForwardDeclarations . Reset ( ) ;
GeneratedHeaderText . Reset ( ) ;
EnumForeachText . Reset ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportSourceFileHeaderRecursive ( FClasses & AllClasses , FUnrealSourceFile * SourceFile , TSet < const FUnrealSourceFile * > & VisitedSet , bool bCheckDependenciesOnly )
2014-03-14 14:13:41 -04:00
{
2015-11-18 16:20:49 -05:00
CurrentSourceFile . Push ( SourceFile ) ;
ON_SCOPE_EXIT
{
CurrentSourceFile . Pop ( ) ;
} ;
2015-01-20 09:33:54 -05:00
bool bIsCorrectHeader = SourceFile - > GetPackage ( ) = = Package ;
2014-03-14 14:13:41 -04:00
// Check for circular header dependencies between export classes.
2015-01-20 09:33:54 -05:00
if ( ! bIsCorrectHeader )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
if ( VisitedSet . Num ( ) = = 0 )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
// The first export class we found doesn't belong in this header: No need to keep exporting along this dependency path.
return ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
// From now on, we're not going to export anything. Instead, we're going to check that no deeper dependency tries to export to this header file.
bCheckDependenciesOnly = true ;
2014-03-14 14:13:41 -04:00
}
// Check if the Class has already been exported, after we've checked for circular header dependencies.
2015-01-20 09:33:54 -05:00
if ( GExportedSourceFiles . Contains ( SourceFile ) )
2014-03-14 14:13:41 -04:00
{
return ;
}
// Check for circular dependencies.
2015-01-20 09:33:54 -05:00
if ( VisitedSet . Contains ( SourceFile ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
UE_LOG ( LogCompile , Error , TEXT ( " Circular dependency detected for filename %s! " ) , * SourceFile - > GetFilename ( ) ) ;
2014-03-14 14:13:41 -04:00
return ;
}
2014-04-23 20:18:55 -04:00
2014-03-14 14:13:41 -04:00
// Temporarily mark the Class as VISITED. Make sure to clear this flag before returning!
2015-01-20 09:33:54 -05:00
VisitedSet . Add ( SourceFile ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
TArray < FUnrealSourceFile * > DependOnList ;
for ( auto & Include : SourceFile - > GetIncludes ( ) )
2014-03-14 14:13:41 -04:00
{
2015-04-22 14:15:56 -04:00
auto * OtherSourceFile = Include . Resolve ( ) ;
if ( OtherSourceFile & & ! DependOnList . Contains ( OtherSourceFile ) )
2014-03-14 14:13:41 -04:00
{
2015-04-22 14:15:56 -04:00
DependOnList . Add ( OtherSourceFile ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
}
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
for ( auto * DependOn : DependOnList )
{
ExportSourceFileHeaderRecursive ( AllClasses , DependOn , VisitedSet , bCheckDependenciesOnly ) ;
2014-03-14 14:13:41 -04:00
}
// Export class header.
2015-01-20 09:33:54 -05:00
if ( bIsCorrectHeader & & ! bCheckDependenciesOnly )
2014-03-14 14:13:41 -04:00
{
// Mark class as exported.
2015-01-20 09:33:54 -05:00
GExportedSourceFiles . Add ( SourceFile ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
ExportClassesFromSourceFileWrapper ( * SourceFile ) ;
2014-03-14 14:13:41 -04:00
}
// We're done visiting this Class.
2015-01-20 09:33:54 -05:00
VisitedSet . Remove ( SourceFile ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Returns a string in the format CLASS_Something | CLASS_Something which represents all class flags that are set for the specified
* class which need to be exported as part of the DECLARE_CLASS macro
*/
FString FNativeClassHeaderGenerator : : GetClassFlagExportText ( UClass * Class )
{
FString StaticClassFlagText ;
check ( Class ) ;
if ( Class - > HasAnyClassFlags ( CLASS_Transient ) )
{
StaticClassFlagText + = TEXT ( " | CLASS_Transient " ) ;
}
if ( Class - > HasAnyClassFlags ( CLASS_DefaultConfig ) )
{
StaticClassFlagText + = TEXT ( " | CLASS_DefaultConfig " ) ;
}
- Generate AndroidManifest.xml from ProjectSettings
- Moved some Android settings to ProjectSettings, re-enabled SDK settings
- Removed SigningConfig.xml, and moved those settings into project settings
- Added concept of NotForLicensees and NoRedist engine and project config settings
- Removed BaseInternalGame.ini, replaced with NotForLicensees/BaseGame.ini
- Moved User*.ini to end of .ini hierarchy
- Added support for CLASS_GlobalUserConfig, so their settings will be saved to <AppData>/.../User*.ini (useful for SDK paths, etc)
- Enabled AndroidPlatformEditor module on Mac
- Changed Mac Build.sh to allow for Android on the commandline (just pass through if it's not an Xcode platform name)
- Iterative Android packaging now looks at just the important .ini sections, NOT entire .ini files
#codereview jamie.dale,james.moran,michael.trepka,robert.jones,chris.babcock
[CL 2413870 by Josh Adams in Main branch]
2015-01-21 11:17:55 -05:00
if ( Class - > HasAnyClassFlags ( CLASS_GlobalUserConfig ) )
{
StaticClassFlagText + = TEXT ( " | CLASS_GlobalUserConfig " ) ;
}
2014-03-14 14:13:41 -04:00
if ( Class - > HasAnyClassFlags ( CLASS_Config ) )
{
StaticClassFlagText + = TEXT ( " | CLASS_Config " ) ;
}
if ( Class - > HasAnyClassFlags ( CLASS_Interface ) )
{
StaticClassFlagText + = TEXT ( " | CLASS_Interface " ) ;
}
if ( Class - > HasAnyClassFlags ( CLASS_Deprecated ) )
{
StaticClassFlagText + = TEXT ( " | CLASS_Deprecated " ) ;
}
return StaticClassFlagText ;
}
/**
* Exports the header text for the list of enums specified
*
* @ param Enums the enums to export
*/
void FNativeClassHeaderGenerator : : ExportEnums ( const TArray < UEnum * > & Enums )
{
// Enum definitions.
for ( int32 EnumIdx = Enums . Num ( ) - 1 ; EnumIdx > = 0 ; EnumIdx - - )
{
UEnum * Enum = Enums [ EnumIdx ] ;
// Export FOREACH macro
EnumForeachText . Logf ( TEXT ( " #define FOREACH_ENUM_%s(op) " ) , * Enum - > GetName ( ) . ToUpper ( ) ) ;
for ( int32 i = 0 ; i < Enum - > NumEnums ( ) - 1 ; i + + )
{
2015-05-26 03:36:08 -04:00
const FString QualifiedEnumValue = Enum - > GetNameByIndex ( i ) . ToString ( ) ;
2015-09-21 07:53:49 -04:00
EnumForeachText . Logf ( TEXT ( " \\ \r \n \t op(%s) " ) , * QualifiedEnumValue ) ;
2014-03-14 14:13:41 -04:00
}
EnumForeachText . Logf ( TEXT ( " \r \n " ) ) ;
}
}
2015-03-17 05:19:11 -04:00
// Exports the header text for the list of structs specified (GENERATED_BODY impls)
2015-11-18 16:20:49 -05:00
void FNativeClassHeaderGenerator : : ExportGeneratedStructBodyMacros ( const TArray < UScriptStruct * > & NativeStructs )
2014-03-14 14:13:41 -04:00
{
// reverse the order.
for ( int32 i = NativeStructs . Num ( ) - 1 ; i > = 0 ; - - i )
{
UScriptStruct * Struct = NativeStructs [ i ] ;
2015-09-08 09:23:57 -04:00
const bool bIsDynamic = FClass : : IsDynamic ( Struct ) ;
2014-03-14 14:13:41 -04:00
// Export struct.
if ( Struct - > StructFlags & STRUCT_Native )
{
check ( Struct - > StructMacroDeclaredLineNumber ! = INDEX_NONE ) ;
2015-01-20 09:33:54 -05:00
const FString FriendApiString = GetAPIString ( ) ;
2014-03-14 14:13:41 -04:00
const FString StaticConstructionString = GetSingletonName ( Struct ) ;
FString RequiredAPI ;
if ( ! ( Struct - > StructFlags & STRUCT_RequiredAPI ) )
{
RequiredAPI = FriendApiString ;
}
2015-09-21 07:53:49 -04:00
const FString FriendLine = FString : : Printf ( TEXT ( " \t friend %sclass UScriptStruct* %s; \r \n " ) , * FriendApiString , * StaticConstructionString ) ;
const FString StaticClassLine = FString : : Printf ( TEXT ( " \t %sstatic class UScriptStruct* StaticStruct(); \r \n " ) , * RequiredAPI ) ;
2014-03-14 14:13:41 -04:00
const FString CombinedLine = FriendLine + StaticClassLine ;
2015-11-18 16:20:49 -05:00
const FString MacroName = CurrentSourceFile . Top ( ) - > GetGeneratedBodyMacroName ( Struct - > StructMacroDeclaredLineNumber ) ;
2014-03-14 14:13:41 -04:00
const FString Macroized = Macroize ( * MacroName , * CombinedLine ) ;
GeneratedHeaderText . Log ( * Macroized ) ;
2014-07-29 02:43:48 -04:00
const TCHAR * StructNameCPP = NameLookupCPP . GetNameCPP ( Struct ) ;
2015-03-27 18:10:52 -04:00
FString SingletonName = StaticConstructionString . Replace ( TEXT ( " () " ) , TEXT ( " " ) , ESearchCase : : CaseSensitive ) ; // function address
2014-07-29 02:43:48 -04:00
FString GetCRCName = FString : : Printf ( TEXT ( " Get_%s_CRC " ) , * SingletonName ) ;
2015-09-08 09:23:57 -04:00
2014-07-29 02:43:48 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " class UScriptStruct* %s::StaticStruct() \r \n " ) , StructNameCPP ) ;
2014-03-14 14:13:41 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " { \r \n " ) ) ;
2015-09-08 09:23:57 -04:00
// UStructs can have UClass or UPackage outer (if declared in non-UClass headers).
FString OuterName ;
if ( Struct - > GetOuter ( ) - > IsA ( UStruct : : StaticClass ( ) ) )
{
OuterName = NameLookupCPP . GetNameCPP ( CastChecked < UStruct > ( Struct - > GetOuter ( ) ) ) ;
OuterName + = TEXT ( " ::StaticClass() " ) ;
}
2015-11-18 16:20:49 -05:00
else if ( ! bIsDynamic )
2015-09-08 09:23:57 -04:00
{
OuterName = GetPackageSingletonName ( CastChecked < UPackage > ( Struct - > GetOuter ( ) ) ) ;
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t extern %sclass UPackage* %s; \r \n " ) , * FriendApiString , * OuterName ) ;
2015-09-08 09:23:57 -04:00
}
2015-11-18 16:20:49 -05:00
else
{
OuterName = TEXT ( " StructPackage " ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t class UPackage* %s = FindOrConstructDynamicTypePackage(TEXT( \" %s \" )); \r \n " ) , * OuterName , * FClass : : GetTypePackageName ( Struct ) ) ;
}
2015-09-08 09:23:57 -04:00
if ( ! bIsDynamic )
{
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t static class UScriptStruct* Singleton = NULL; \r \n " ) ) ;
2015-09-08 09:23:57 -04:00
}
else
{
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t class UScriptStruct* Singleton = Cast<UScriptStruct>(StaticFindObjectFast(UScriptStruct::StaticClass(), %s, TEXT( \" %s \" ))); \r \n " ) ,
2015-09-08 09:23:57 -04:00
* OuterName , * Struct - > GetName ( ) ) ;
}
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t if (!Singleton) \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t { \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t \t extern %sclass UScriptStruct* %s; \r \n " ) , * FriendApiString , * StaticConstructionString ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t \t extern %suint32 %s(); \r \n " ) , * FriendApiString , * GetCRCName ) ;
2015-01-20 09:33:54 -05:00
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t Singleton = GetStaticStruct(%s, %s, TEXT( \" %s \" ), sizeof(%s), %s()); \r \n " ) ,
2015-09-08 09:23:57 -04:00
* SingletonName , * OuterName , * Struct - > GetName ( ) , StructNameCPP , * GetCRCName ) ;
2015-01-20 09:33:54 -05:00
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t } \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t return Singleton; \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " } \r \n " ) ) ;
2015-09-08 09:23:57 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " static FCompiledInDeferStruct Z_CompiledInDeferStruct_UScriptStruct_%s(%s::StaticStruct, TEXT( \" %s \" ), TEXT( \" %s \" ), %s); \r \n " ) ,
StructNameCPP , StructNameCPP , * Struct - > GetOutermost ( ) - > GetName ( ) , * Struct - > GetName ( ) ,
bIsDynamic ? TEXT ( " true " ) : TEXT ( " false " ) ) ;
2014-03-14 14:13:41 -04:00
// Generate StaticRegisterNatives equivalent for structs without classes.
if ( ! Struct - > GetOuter ( ) - > IsA ( UStruct : : StaticClass ( ) ) )
{
const FString ShortPackageName = FPackageName : : GetShortName ( Struct - > GetOuter ( ) - > GetName ( ) ) ;
2014-07-29 02:43:48 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " static struct FScriptStruct_%s_StaticRegisterNatives%s \r \n " ) , * ShortPackageName , StructNameCPP ) ;
2014-03-14 14:13:41 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " { \r \n " ) ) ;
2014-07-29 02:43:48 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t FScriptStruct_%s_StaticRegisterNatives%s() \r \n " ) , * ShortPackageName , StructNameCPP ) ;
2014-03-14 14:13:41 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t { \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t UScriptStruct::DeferCppStructOps(FName(TEXT( \" %s \" )),new UScriptStruct::TCppStructOps<%s%s>); \r \n " ) , * Struct - > GetName ( ) , Struct - > GetPrefixCPP ( ) , * Struct - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t } \r \n " ) ) ;
2014-07-29 02:43:48 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " } ScriptStruct_%s_StaticRegisterNatives%s; \r \n " ) , * ShortPackageName , StructNameCPP ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-01-20 09:33:54 -05:00
{
UScriptStruct * ScriptStruct = Struct ;
UStruct * BaseStruct = ScriptStruct - > GetSuperStruct ( ) ;
const FString SingletonName ( GetSingletonName ( ScriptStruct ) ) ;
2015-05-22 02:54:27 -04:00
GeneratedFunctionDeclarations . Log ( FTypeSingletonCache : : Get ( ScriptStruct ) . GetExternDecl ( ) ) ;
2015-01-20 09:33:54 -05:00
2015-03-27 18:10:52 -04:00
FUHTStringBuilder GeneratedStructRegisterFunctionText ;
2015-01-20 09:33:54 -05:00
2015-09-21 07:53:49 -04:00
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t UScriptStruct* %s \r \n " ) , * SingletonName ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t { \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
// if this is a no export struct, we will put a local struct here for offset determination
TArray < UScriptStruct * > Structs ;
FindNoExportStructs ( Structs , ScriptStruct ) ;
if ( Structs . Num ( ) )
{
TGuardValue < bool > Guard ( bIsExportingForOffsetDeterminationOnly , true ) ;
2015-03-27 18:10:52 -04:00
ExportMirrorsForNoexportStructs ( Structs , /*Indent=*/ 2 , GeneratedStructRegisterFunctionText ) ;
2015-01-20 09:33:54 -05:00
}
2015-09-30 05:26:51 -04:00
FString CRCFuncName = FString : : Printf ( TEXT ( " Get_%s_CRC " ) , * SingletonName . Replace ( TEXT ( " () " ) , TEXT ( " " ) , ESearchCase : : CaseSensitive ) ) ;
2015-01-20 09:33:54 -05:00
// Structs can either have a UClass or UPackage as outer (if delcared in non-UClass header).
if ( ScriptStruct - > GetOuter ( ) - > IsA ( UStruct : : StaticClass ( ) ) )
{
2015-11-18 16:20:49 -05:00
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t \t UStruct* Outer = %s; \r \n " ) , * GetSingletonName ( CastChecked < UStruct > ( ScriptStruct - > GetOuter ( ) ) ) ) ;
}
else if ( ! bIsDynamic )
{
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t \t UPackage* Outer = %s; \r \n " ) , * GetPackageSingletonName ( CastChecked < UPackage > ( ScriptStruct - > GetOuter ( ) ) ) ) ;
2015-01-20 09:33:54 -05:00
}
else
{
2015-11-18 16:20:49 -05:00
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t \t UPackage* Outer = FindOrConstructDynamicTypePackage(TEXT( \" %s \" )); \r \n " ) , * FClass : : GetTypePackageName ( ScriptStruct ) ) ;
2015-01-20 09:33:54 -05:00
}
2015-11-18 16:20:49 -05:00
2015-09-30 05:26:51 -04:00
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t \t extern uint32 %s(); \r \n " ) , * CRCFuncName ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t \t static UScriptStruct* ReturnStruct = FindExistingStructIfHotReloadOrDynamic(Outer, TEXT( \" %s \" ), sizeof(%s), %s(), %s); \r \n " ) , * ScriptStruct - > GetName ( ) , NameLookupCPP . GetNameCPP ( Struct ) , * CRCFuncName , bIsDynamic ? TEXT ( " true " ) : TEXT ( " false " ) ) ;
2015-09-21 07:53:49 -04:00
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t \t if (!ReturnStruct) \r \n " ) ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t \t { \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
FString BaseStructString ( TEXT ( " NULL " ) ) ;
if ( BaseStruct )
{
CastChecked < UScriptStruct > ( BaseStruct ) ; // this better actually be a script struct
BaseStructString = GetSingletonName ( BaseStruct ) ;
}
FString CppStructOpsString ( TEXT ( " NULL " ) ) ;
FString ExplicitSizeString ;
FString ExplicitAlignmentString ;
if ( ( ScriptStruct - > StructFlags & STRUCT_Native ) ! = 0 )
{
//@todo .u we don't need the auto register versions of these (except for hotreload, which should be fixed)
CppStructOpsString = FString : : Printf ( TEXT ( " new UScriptStruct::TCppStructOps<%s> " ) , NameLookupCPP . GetNameCPP ( ScriptStruct ) ) ;
}
else
{
ExplicitSizeString = FString : : Printf ( TEXT ( " , sizeof(%s), ALIGNOF(%s) " ) , NameLookupCPP . GetNameCPP ( ScriptStruct ) , NameLookupCPP . GetNameCPP ( ScriptStruct ) ) ;
}
2015-11-18 16:20:49 -05:00
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t \t \t ReturnStruct = new(EC_InternalUseOnlyConstructor, Outer, TEXT( \" %s \" ), RF_Public|RF_Transient|RF_MarkAsNative) UScriptStruct(FObjectInitializer(), %s, %s, EStructFlags(0x%08X)%s); \r \n " ) ,
2015-01-20 09:33:54 -05:00
* ScriptStruct - > GetName ( ) ,
* BaseStructString ,
* CppStructOpsString ,
( uint32 ) ( ScriptStruct - > StructFlags & ~ STRUCT_ComputedFlags ) ,
* ExplicitSizeString
) ;
TheFlagAudit . Add ( ScriptStruct , TEXT ( " StructFlags " ) , ( uint64 ) ( ScriptStruct - > StructFlags & ~ STRUCT_ComputedFlags ) ) ;
TArray < UProperty * > Props ;
for ( TFieldIterator < UProperty > ItInner ( ScriptStruct , EFieldIteratorFlags : : ExcludeSuper ) ; ItInner ; + + ItInner )
{
Props . Add ( * ItInner ) ;
}
FString OuterString = FString ( TEXT ( " ReturnStruct " ) ) ;
2015-09-21 07:53:49 -04:00
FString Meta = GetMetaDataCodeForObject ( ScriptStruct , * OuterString , TEXT ( " \t \t \t " ) ) ;
OutputProperties ( Meta , GeneratedStructRegisterFunctionText , OuterString , Props , TEXT ( " \t \t \t " ) ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t \t \t ReturnStruct->StaticLink(); \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
if ( Meta . Len ( ) )
{
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " #if WITH_METADATA \r \n " ) ) ;
2015-09-21 07:53:49 -04:00
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t \t \t UMetaData* MetaData = ReturnStruct->GetOutermost()->GetMetaData(); \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
GeneratedStructRegisterFunctionText . Log ( * Meta ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " #endif \r \n " ) ) ;
}
2015-09-21 07:53:49 -04:00
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t \t } \r \n " ) ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t \t return ReturnStruct; \r \n " ) ) ;
GeneratedStructRegisterFunctionText . Logf ( TEXT ( " \t } \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
uint32 StructCrc = GenerateTextCRC ( * GeneratedStructRegisterFunctionText ) ;
GGeneratedCodeCRCs . Add ( ScriptStruct , StructCrc ) ;
2015-11-18 16:20:49 -05:00
UHTMakefile . AddGeneratedCodeCRC ( CurrentSourceFile . Top ( ) , ScriptStruct , StructCrc ) ;
2015-01-20 09:33:54 -05:00
auto & GeneratedFunctionText = GetGeneratedFunctionTextDevice ( ) ;
GeneratedFunctionText + = GeneratedStructRegisterFunctionText ;
2015-09-30 05:26:51 -04:00
GeneratedFunctionText . Logf ( TEXT ( " \t uint32 %s() { return %uU; } \r \n " ) , * CRCFuncName , StructCrc ) ;
2015-01-20 09:33:54 -05:00
2015-09-21 07:53:49 -04:00
//CallSingletons.Logf(TEXT("\t\t\t\tOuterClass->LinkChild(%s); // %u\r\n"), *SingletonName, StructCrc);
2015-01-20 09:33:54 -05:00
}
2014-03-14 14:13:41 -04:00
}
}
void FNativeClassHeaderGenerator : : ExportGeneratedEnumsInitCode ( const TArray < UEnum * > & Enums )
{
// reverse the order.
for ( int32 i = Enums . Num ( ) - 1 ; i > = 0 ; - - i )
{
UEnum * Enum = Enums [ i ] ;
// Export Enum.
2015-01-20 09:33:54 -05:00
if ( ! Enum - > GetOuter ( ) - > IsA ( UPackage : : StaticClass ( ) ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
continue ;
}
2014-03-14 14:13:41 -04:00
2015-09-08 09:23:57 -04:00
const bool bIsDynamic = FClass : : IsDynamic ( Enum ) ;
2015-01-20 09:33:54 -05:00
const FString FriendApiString = GetAPIString ( ) ;
const FString StaticConstructionString = GetSingletonName ( Enum ) ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
FString SingletonName = StaticConstructionString . Replace ( TEXT ( " () " ) , TEXT ( " " ) , ESearchCase : : CaseSensitive ) ; // function address
2015-09-08 09:23:57 -04:00
FString PackageSingletonName = GetPackageSingletonName ( CastChecked < UPackage > ( Enum - > GetOuter ( ) ) ) ;
2015-11-18 16:20:49 -05:00
if ( ! bIsDynamic )
{
PackageSingletonName = GetPackageSingletonName ( CastChecked < UPackage > ( Enum - > GetOuter ( ) ) ) ;
}
else
{
PackageSingletonName = FClass : : GetTypePackageName ( Enum ) ;
}
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
GeneratedPackageCPP . Logf ( TEXT ( " static class UEnum* %s_StaticEnum() \r \n " ) , * Enum - > GetName ( ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " { \r \n " ) ) ;
2015-11-18 16:20:49 -05:00
2015-09-08 09:23:57 -04:00
if ( ! bIsDynamic )
{
2015-11-18 16:20:49 -05:00
GeneratedPackageCPP . Logf ( TEXT ( " \t extern %sclass UPackage* %s; \r \n " ) , * FriendApiString , * PackageSingletonName ) ;
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t static class UEnum* Singleton = NULL; \r \n " ) ) ;
2015-09-08 09:23:57 -04:00
}
else
{
2015-11-18 16:20:49 -05:00
GeneratedPackageCPP . Logf ( TEXT ( " \t class UPackage* EnumPackage = FindOrConstructDynamicTypePackage(TEXT( \" %s \" )); \r \n " ) , * PackageSingletonName ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t class UEnum* Singleton = Cast<UEnum>(StaticFindObjectFast(UEnum::StaticClass(), EnumPackage, TEXT( \" %s \" ))); \r \n " ) , * Enum - > GetName ( ) ) ;
2015-09-08 09:23:57 -04:00
}
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t if (!Singleton) \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t { \r \n " ) ) ;
2015-11-18 16:20:49 -05:00
GeneratedPackageCPP . Logf ( TEXT ( " \t \t extern %sclass UEnum* %s; \r \n " ) , * FriendApiString , * StaticConstructionString ) ;
if ( ! bIsDynamic )
{
GeneratedPackageCPP . Logf ( TEXT ( " \t \t Singleton = GetStaticEnum(%s, %s, TEXT( \" %s \" )); \r \n " ) , * SingletonName , * PackageSingletonName , * Enum - > GetName ( ) ) ;
}
else
{
GeneratedPackageCPP . Logf ( TEXT ( " \t \t Singleton = GetStaticEnum(%s, EnumPackage, TEXT( \" %s \" )); \r \n " ) , * SingletonName , * Enum - > GetName ( ) ) ;
}
2014-03-14 14:13:41 -04:00
2015-09-21 07:53:49 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " \t } \r \n " ) ) ;
GeneratedPackageCPP . Logf ( TEXT ( " \t return Singleton; \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
GeneratedPackageCPP . Logf ( TEXT ( " } \r \n " ) ) ;
2015-09-08 09:23:57 -04:00
GeneratedPackageCPP . Logf ( TEXT ( " static FCompiledInDeferEnum Z_CompiledInDeferEnum_UEnum_%s(%s_StaticEnum, TEXT( \" %s \" ), TEXT( \" %s \" ), %s); \r \n " ) ,
* Enum - > GetName ( ) , * Enum - > GetName ( ) , * Enum - > GetOutermost ( ) - > GetName ( ) , * Enum - > GetName ( ) ,
bIsDynamic ? TEXT ( " true " ) : TEXT ( " false " ) ) ;
2015-01-20 09:33:54 -05:00
{
2015-04-22 14:15:56 -04:00
const FString EnumSingletonName = GetSingletonName ( Enum ) ;
2015-05-22 02:54:27 -04:00
GeneratedFunctionDeclarations . Log ( FTypeSingletonCache : : Get ( Enum ) . GetExternDecl ( ) ) ;
2015-01-20 09:33:54 -05:00
2015-03-27 18:10:52 -04:00
FUHTStringBuilder GeneratedEnumRegisterFunctionText ;
2015-01-20 09:33:54 -05:00
2015-09-30 05:26:51 -04:00
FString CRCFuncName = FString : : Printf ( TEXT ( " Get_%s_CRC " ) , * SingletonName . Replace ( TEXT ( " () " ) , TEXT ( " " ) , ESearchCase : : CaseSensitive ) ) ;
2015-09-21 07:53:49 -04:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t UEnum* %s \r \n " ) , * EnumSingletonName ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t { \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
// Enums can either have a UClass or UPackage as outer (if declared in non-UClass header).
if ( Enum - > GetOuter ( ) - > IsA ( UStruct : : StaticClass ( ) ) )
{
2015-09-21 07:53:49 -04:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t UClass* Outer=%s; \r \n " ) , * GetSingletonName ( CastChecked < UStruct > ( Enum - > GetOuter ( ) ) ) ) ;
2015-01-20 09:33:54 -05:00
}
2015-11-18 16:20:49 -05:00
else if ( ! bIsDynamic )
2015-01-20 09:33:54 -05:00
{
2015-09-21 07:53:49 -04:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t UPackage* Outer=%s; \r \n " ) , * GetPackageSingletonName ( CastChecked < UPackage > ( Enum - > GetOuter ( ) ) ) ) ;
2015-01-20 09:33:54 -05:00
}
2015-11-18 16:20:49 -05:00
else
{
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t UPackage* Outer = FindOrConstructDynamicTypePackage(TEXT( \" %s \" )); \r \n " ) , * PackageSingletonName ) ;
}
2015-09-30 05:26:51 -04:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t extern uint32 %s(); \r \n " ) , * CRCFuncName ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t static UEnum* ReturnEnum = FindExistingEnumIfHotReload(Outer, TEXT( \" %s \" ), 0, %s()); \r \n " ) , * Enum - > GetName ( ) , * CRCFuncName ) ;
2015-09-21 07:53:49 -04:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t if (!ReturnEnum) \r \n " ) ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t { \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
2015-11-18 16:20:49 -05:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t \t ReturnEnum = new(EC_InternalUseOnlyConstructor, Outer, TEXT( \" %s \" ), RF_Public|RF_Transient|RF_MarkAsNative) UEnum(FObjectInitializer()); \r \n " ) , * Enum - > GetName ( ) ) ;
2015-09-21 07:53:49 -04:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t \t TArray<TPair<FName, uint8>> EnumNames; \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
for ( int32 Index = 0 ; Index < Enum - > NumEnums ( ) ; Index + + )
{
2015-09-21 07:53:49 -04:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t \t EnumNames.Add(TPairInitializer<FName, uint8>(FName(TEXT( \" %s \" )), %d)); \r \n " ) , * Enum - > GetNameByIndex ( Index ) . ToString ( ) , Enum - > GetValueByIndex ( Index ) ) ;
2015-01-20 09:33:54 -05:00
}
FString EnumTypeStr ;
switch ( Enum - > GetCppForm ( ) )
{
case UEnum : : ECppForm : : Regular : EnumTypeStr = TEXT ( " UEnum::ECppForm::Regular " ) ; break ;
case UEnum : : ECppForm : : Namespaced : EnumTypeStr = TEXT ( " UEnum::ECppForm::Namespaced " ) ; break ;
case UEnum : : ECppForm : : EnumClass : EnumTypeStr = TEXT ( " UEnum::ECppForm::EnumClass " ) ; break ;
}
2015-09-21 07:53:49 -04:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t \t ReturnEnum->SetEnums(EnumNames, %s); \r \n " ) , * EnumTypeStr ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t \t ReturnEnum->CppType = TEXT( \" %s \" ); \r \n " ) , * Enum - > CppType ) ;
2015-01-20 09:33:54 -05:00
2015-09-21 07:53:49 -04:00
FString Meta = GetMetaDataCodeForObject ( Enum , TEXT ( " ReturnEnum " ) , TEXT ( " \t \t \t " ) ) ;
2015-01-20 09:33:54 -05:00
if ( Meta . Len ( ) )
{
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " #if WITH_METADATA \r \n " ) ) ;
2015-09-21 07:53:49 -04:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t \t UMetaData* MetaData = ReturnEnum->GetOutermost()->GetMetaData(); \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
GeneratedEnumRegisterFunctionText . Log ( * Meta ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " #endif \r \n " ) ) ;
}
2015-09-21 07:53:49 -04:00
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t } \r \n " ) ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t \t return ReturnEnum; \r \n " ) ) ;
GeneratedEnumRegisterFunctionText . Logf ( TEXT ( " \t } \r \n " ) ) ;
2015-01-20 09:33:54 -05:00
auto & GeneratedFunctionText = GetGeneratedFunctionTextDevice ( ) ;
GeneratedFunctionText + = GeneratedEnumRegisterFunctionText ;
uint32 EnumCrc = GenerateTextCRC ( * GeneratedEnumRegisterFunctionText ) ;
GGeneratedCodeCRCs . Add ( Enum , EnumCrc ) ;
2015-11-18 16:20:49 -05:00
UHTMakefile . AddGeneratedCodeCRC ( CurrentSourceFile . Top ( ) , Enum , EnumCrc ) ;
2015-09-30 05:26:51 -04:00
GeneratedFunctionText . Logf ( TEXT ( " \t uint32 %s() { return %uU; } \r \n " ) , * CRCFuncName , EnumCrc ) ;
2015-09-21 07:53:49 -04:00
// CallSingletons.Logf(TEXT("\t\t\t\tOuterClass->LinkChild(%s); // %u\r\n"), *EnumSingletonName, EnumCrc);
2014-03-14 14:13:41 -04:00
}
}
}
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportMirrorsForNoexportStructs ( const TArray < UScriptStruct * > & NativeStructs , int32 TextIndent , FUHTStringBuilder & HeaderOutput )
2014-03-14 14:13:41 -04:00
{
// reverse the order.
for ( int32 i = NativeStructs . Num ( ) - 1 ; i > = 0 ; - - i )
{
UScriptStruct * Struct = NativeStructs [ i ] ;
// Export struct.
2015-09-21 07:53:49 -04:00
HeaderOutput . Logf ( TEXT ( " %sstruct %s " ) , FCString : : Tab ( TextIndent ) , NameLookupCPP . GetNameCPP ( Struct ) ) ;
2014-03-14 14:13:41 -04:00
if ( Struct - > GetSuperStruct ( ) ! = NULL )
{
2014-06-02 07:02:29 -04:00
HeaderOutput . Logf ( TEXT ( " : public %s " ) , NameLookupCPP . GetNameCPP ( Struct - > GetSuperStruct ( ) ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-09-21 07:53:49 -04:00
HeaderOutput . Logf ( TEXT ( " \r \n %s{ \r \n " ) , FCString : : Tab ( TextIndent ) ) ;
2014-03-14 14:13:41 -04:00
// Export the struct's CPP properties.
ExportProperties ( Struct , TextIndent , /*bAccessSpecifiers=*/ false , & HeaderOutput ) ;
2015-09-21 07:53:49 -04:00
HeaderOutput . Logf ( TEXT ( " %s}; \r \n \r \n " ) , FCString : : Tab ( TextIndent ) ) ;
2014-03-14 14:13:41 -04:00
}
}
bool FNativeClassHeaderGenerator : : WillExportEventParms ( UFunction * Function )
{
2015-04-02 16:31:18 -04:00
TFieldIterator < UProperty > It ( Function ) ;
return It & & ( It - > PropertyFlags & CPF_Parm ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
void WriteEventFunctionPrologue ( FUHTStringBuilder & Output , int32 Indent , const FParmsAndReturnProperties & Parameters , UObject * FunctionOuter , const TCHAR * FunctionName )
2014-03-14 14:13:41 -04:00
{
// now the body - first we need to declare a struct which will hold the parameters for the event/delegate call
2015-09-21 07:53:49 -04:00
Output . Logf ( TEXT ( " \r \n %s{ \r \n " ) , FCString : : Tab ( Indent ) ) ;
2014-03-14 14:13:41 -04:00
// declare and zero-initialize the parameters and return value, if applicable
if ( ! Parameters . HasParms ( ) )
return ;
2015-01-20 09:33:54 -05:00
FString EventStructName = GetEventStructParamsName ( FunctionOuter , FunctionName ) ;
2014-03-14 14:13:41 -04:00
2015-09-21 07:53:49 -04:00
Output . Logf ( TEXT ( " %s%s Parms; \r \n " ) , FCString : : Tab ( Indent + 1 ) , * EventStructName ) ;
2014-03-14 14:13:41 -04:00
// Declare a parameter struct for this event/delegate and assign the struct members using the values passed into the event/delegate call.
for ( auto It = Parameters . Parms . CreateConstIterator ( ) ; It ; + + It )
{
UProperty * Prop = * It ;
const FString PropertyName = Prop - > GetName ( ) ;
2015-03-27 18:10:52 -04:00
if ( Prop - > ArrayDim > 1 )
2014-03-14 14:13:41 -04:00
{
2015-09-21 07:53:49 -04:00
Output . Logf ( TEXT ( " %sFMemory::Memcpy(Parms.%s,%s,sizeof(Parms.%s)); \r \n " ) , FCString : : Tab ( Indent + 1 ) , * PropertyName , * PropertyName , * PropertyName ) ;
2014-03-14 14:13:41 -04:00
}
else
{
FString ValueAssignmentText = PropertyName ;
if ( Prop - > IsA < UBoolProperty > ( ) )
{
ValueAssignmentText + = TEXT ( " ? true : false " ) ;
}
2015-09-21 07:53:49 -04:00
Output . Logf ( TEXT ( " %sParms.%s=%s; \r \n " ) , FCString : : Tab ( Indent + 1 ) , * PropertyName , * ValueAssignmentText ) ;
2014-03-14 14:13:41 -04:00
}
}
}
2015-03-27 18:10:52 -04:00
void WriteEventFunctionEpilogue ( FUHTStringBuilder & Output , int32 Indent , const FParmsAndReturnProperties & Parameters , const TCHAR * FunctionName )
2014-03-14 14:13:41 -04:00
{
// Out parm copying.
for ( auto It = Parameters . Parms . CreateConstIterator ( ) ; It ; + + It )
{
UProperty * Prop = * It ;
if ( Prop - > HasAnyPropertyFlags ( CPF_OutParm ) & & ( ! Prop - > HasAnyPropertyFlags ( CPF_ConstParm ) | | Prop - > IsA < UObjectPropertyBase > ( ) ) )
{
const FString PropertyName = Prop - > GetName ( ) ;
if ( Prop - > ArrayDim > 1 )
{
2015-09-21 07:53:49 -04:00
Output . Logf ( TEXT ( " %sFMemory::Memcpy(&%s,&Parms.%s,sizeof(%s)); \r \n " ) , FCString : : Tab ( Indent + 1 ) , * PropertyName , * PropertyName , * PropertyName ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-09-21 07:53:49 -04:00
Output . Logf ( TEXT ( " %s%s=Parms.%s; \r \n " ) , FCString : : Tab ( Indent + 1 ) , * PropertyName , * PropertyName ) ;
2014-03-14 14:13:41 -04:00
}
}
}
// Return value.
if ( Parameters . Return )
{
// Make sure uint32 -> bool is supported
bool bBoolProperty = Parameters . Return - > IsA ( UBoolProperty : : StaticClass ( ) ) ;
2015-09-21 07:53:49 -04:00
Output . Logf ( TEXT ( " %sreturn %sParms.%s; \r \n " ) , FCString : : Tab ( Indent + 1 ) , bBoolProperty ? TEXT ( " !! " ) : TEXT ( " " ) , * Parameters . Return - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-09-21 07:53:49 -04:00
Output . Logf ( TEXT ( " %s} \r \n " ) , FCString : : Tab ( Indent ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportDelegateDefinitions ( FUnrealSourceFile & SourceFile , const TArray < UDelegateFunction * > & DelegateFunctions , const bool bWrapperImplementationsOnly )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder HeaderOutput ;
2014-03-14 14:13:41 -04:00
for ( int32 i = DelegateFunctions . Num ( ) - 1 ; i > = 0 ; i - - )
{
UFunction * Function = DelegateFunctions [ i ] ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder DelegateOutput ;
2014-03-14 14:13:41 -04:00
check ( Function - > HasAnyFunctionFlags ( FUNC_Delegate ) ) ;
2015-01-20 09:33:54 -05:00
if ( bWrapperImplementationsOnly )
{
// Export parameters structs for all delegates. We'll need these to declare our delegate execution function.
ExportEventParm ( Function , DelegateOutput ) ;
}
2014-03-14 14:13:41 -04:00
const bool bIsMulticastDelegate = Function - > HasAnyFunctionFlags ( FUNC_MulticastDelegate ) ;
// Unmangle the function name
const FString DelegateName = Function - > GetName ( ) . LeftChop ( FString ( HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX ) . Len ( ) ) ;
2015-01-20 09:33:54 -05:00
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
2014-03-14 14:13:41 -04:00
FFuncInfo FunctionData = CompilerInfo - > GetFunctionData ( ) ;
if ( bWrapperImplementationsOnly )
{
// Always export delegate wrapper functions as inline
FunctionData . FunctionExportFlags | = FUNCEXPORT_Inline ;
}
// Add class name to beginning of function, to avoid collisions with other classes with the same delegate name in this scope
FString Delegate ( TEXT ( " delegate " ) ) ;
check ( FunctionData . MarshallAndCallName . StartsWith ( Delegate ) ) ;
FString ShortName = * FunctionData . MarshallAndCallName + Delegate . Len ( ) ;
FunctionData . MarshallAndCallName = FString : : Printf ( TEXT ( " F%s_DelegateWrapper " ) , * ShortName ) ;
// Setup delegate parameter
const FString ExtraParam ( FString : : Printf ( TEXT ( " const %s& %s " ) ,
bIsMulticastDelegate ? TEXT ( " FMulticastScriptDelegate " ) : TEXT ( " FScriptDelegate " ) ,
* DelegateName ) ) ;
2015-01-20 09:33:54 -05:00
DelegateOutput . Log ( TEXT ( " static " ) ) ;
2014-03-14 14:13:41 -04:00
// export the line that looks like: int32 Main(const FString& Parms)
2015-01-20 09:33:54 -05:00
ExportNativeFunctionHeader ( FunctionData , DelegateOutput , EExportFunctionType : : Event , EExportFunctionHeaderStyle : : Declaration , * ExtraParam ) ;
2014-03-14 14:13:41 -04:00
if ( ! bWrapperImplementationsOnly )
{
// Only exporting function prototype
2015-01-20 09:33:54 -05:00
DelegateOutput . Logf ( TEXT ( " ; \r \n " ) ) ;
2015-11-18 16:20:49 -05:00
ExportFunction ( Function , & CurrentSourceFile . Top ( ) - > GetScope ( ) . Get ( ) , false ) ;
2014-03-14 14:13:41 -04:00
}
else
{
auto Parameters = GetFunctionParmsAndReturn ( FunctionData . FunctionReference ) ;
2015-01-20 09:33:54 -05:00
WriteEventFunctionPrologue ( DelegateOutput , 0 , Parameters , Function - > GetOuter ( ) , * DelegateName ) ;
2014-03-14 14:13:41 -04:00
{
const TCHAR * DelegateType = bIsMulticastDelegate ? TEXT ( " ProcessMulticastDelegate " ) : TEXT ( " ProcessDelegate " ) ;
const TCHAR * DelegateArg = Parameters . HasParms ( ) ? TEXT ( " &Parms " ) : TEXT ( " NULL " ) ;
2015-03-27 18:10:52 -04:00
DelegateOutput . Logf ( TEXT ( " \t %s.%s<UObject>(%s); \r \n " ) , * DelegateName , DelegateType , DelegateArg ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
WriteEventFunctionEpilogue ( DelegateOutput , 0 , Parameters , * DelegateName ) ;
}
2015-06-15 14:06:46 -04:00
if ( bWrapperImplementationsOnly )
2015-01-20 09:33:54 -05:00
{
2015-03-17 05:19:11 -04:00
FString MacroName = SourceFile . GetGeneratedMacroName ( FunctionData . MacroLine , TEXT ( " _DELEGATE " ) ) ;
2015-01-20 09:33:54 -05:00
WriteMacro ( HeaderOutput , MacroName , DelegateOutput ) ;
2014-03-14 14:13:41 -04:00
}
}
if ( HeaderOutput . Len ( ) )
{
2015-01-20 09:33:54 -05:00
GeneratedHeaderText . Log ( * HeaderOutput ) ;
GeneratedHeaderText . Log ( TEXT ( " \r \n \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
}
}
/**
* Export a single . proto declaration , recursing as necessary for sub declarations
*
* @ param Out output device
* @ param MessageName name of the message in the declaration
* @ param Properties array of parameters in the function definition
* @ param PropertyFlags flags to filter property array against
* @ param Ident starting indentation level
*/
void ExportProtoDeclaration ( FOutputDevice & Out , const FString & MessageName , TFieldIterator < UProperty > & Properties , uint64 PropertyFlags , int32 Indent )
{
2015-09-21 07:53:49 -04:00
Out . Logf ( TEXT ( " %smessage CMsg%sMessage \r \n " ) , FCString : : Tab ( Indent ) , * MessageName ) ;
Out . Logf ( TEXT ( " %s{ \r \n " ) , FCString : : Tab ( Indent ) ) ;
2014-03-14 14:13:41 -04:00
static TMap < FString , FString > ToProtoTypeMappings ;
static bool bInitMapping = false ;
if ( ! bInitMapping )
{
// Explicit type mappings
ToProtoTypeMappings . Add ( TEXT ( " FString " ) , TEXT ( " string " ) ) ;
ToProtoTypeMappings . Add ( TEXT ( " int32 " ) , TEXT ( " int32 " ) ) ;
ToProtoTypeMappings . Add ( TEXT ( " int64 " ) , TEXT ( " int64 " ) ) ;
ToProtoTypeMappings . Add ( TEXT ( " uint8 " ) , TEXT ( " bytes " ) ) ;
ToProtoTypeMappings . Add ( TEXT ( " bool " ) , TEXT ( " bool " ) ) ;
ToProtoTypeMappings . Add ( TEXT ( " double " ) , TEXT ( " double " ) ) ;
ToProtoTypeMappings . Add ( TEXT ( " float " ) , TEXT ( " float " ) ) ;
bInitMapping = true ;
}
int32 FieldIdx = 1 ;
for ( ; Properties & & ( Properties - > PropertyFlags & PropertyFlags ) ; + + Properties )
{
UProperty * Property = * Properties ;
UClass * PropClass = Property - > GetClass ( ) ;
// Skip out and return paramaters
if ( ( Property - > PropertyFlags & CPF_RepSkip ) | | ( Property - > PropertyFlags & CPF_ReturnParm ) )
{
continue ;
}
// export the property type text (e.g. FString; int32; TArray, etc.)
FString TypeText , ExtendedTypeText ;
TypeText = Property - > GetCPPType ( & ExtendedTypeText , CPPF_None ) ;
if ( PropClass ! = UInterfaceProperty : : StaticClass ( ) & & PropClass ! = UObjectProperty : : StaticClass ( ) )
{
bool bIsRepeated = false ;
2015-04-21 10:25:59 -04:00
if ( UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( Property ) )
2014-03-14 14:13:41 -04:00
{
2014-06-02 14:20:58 -04:00
UClass * InnerPropClass = ArrayProperty - > Inner - > GetClass ( ) ;
2014-03-14 14:13:41 -04:00
if ( InnerPropClass ! = UInterfaceProperty : : StaticClass ( ) & & InnerPropClass ! = UObjectProperty : : StaticClass ( ) )
{
FString InnerExtendedTypeText ;
2014-06-02 14:20:58 -04:00
FString InnerTypeText = ArrayProperty - > Inner - > GetCPPType ( & InnerExtendedTypeText , CPPF_None ) ;
2014-03-14 14:13:41 -04:00
TypeText = InnerTypeText ;
ExtendedTypeText = InnerExtendedTypeText ;
2014-06-02 14:20:58 -04:00
Property = ArrayProperty - > Inner ;
2014-03-14 14:13:41 -04:00
bIsRepeated = true ;
}
else
{
FError : : Throwf ( TEXT ( " ExportProtoDeclaration - Unhandled property type '%s': %s " ) , * PropClass - > GetName ( ) , * Property - > GetPathName ( ) ) ;
}
}
2015-04-21 10:25:59 -04:00
else if ( UMapProperty * MapProperty = Cast < UMapProperty > ( Property ) )
{
FError : : Throwf ( TEXT ( " ExportProtoDeclaration - Map properties not yet supported '%s': %s " ) , * PropClass - > GetName ( ) , * Property - > GetPathName ( ) ) ;
}
2014-03-14 14:13:41 -04:00
else if ( Property - > ArrayDim ! = 1 )
{
bIsRepeated = true ;
}
FString VariableTypeName = FString : : Printf ( TEXT ( " %s%s " ) , * TypeText , * ExtendedTypeText ) ;
FString * ProtoTypeName = NULL ;
UStructProperty * StructProperty = Cast < UStructProperty > ( Property ) ;
if ( StructProperty ! = NULL )
{
TFieldIterator < UProperty > StructIt ( StructProperty - > Struct ) ;
2015-03-27 18:10:52 -04:00
ExportProtoDeclaration ( Out , VariableTypeName , StructIt , CPF_AllFlags , Indent + 1 ) ;
2014-03-14 14:13:41 -04:00
VariableTypeName = FString : : Printf ( TEXT ( " CMsg%sMessage " ) , * VariableTypeName ) ;
ProtoTypeName = & VariableTypeName ;
}
else
{
ProtoTypeName = ToProtoTypeMappings . Find ( VariableTypeName ) ;
}
2015-09-21 07:53:49 -04:00
Out . Log ( FCString : : Tab ( Indent + 1 ) ) ;
2015-03-27 18:10:52 -04:00
Out . Log ( bIsRepeated ? TEXT ( " repeated " ) : TEXT ( " optional " ) ) ;
2014-03-14 14:13:41 -04:00
if ( ProtoTypeName ! = NULL )
{
Out . Logf ( TEXT ( " %s %s = %d; \r \n " ) , * * ProtoTypeName , * Property - > GetNameCPP ( ) , FieldIdx ) ;
FieldIdx + + ;
}
else
{
FError : : Throwf ( TEXT ( " ExportProtoDeclaration - Unhandled property mapping '%s': %s " ) , * PropClass - > GetName ( ) , * Property - > GetPathName ( ) ) ;
}
}
else
{
FError : : Throwf ( TEXT ( " ExportProtoDeclaration - Unhandled property type '%s': %s " ) , * PropClass - > GetName ( ) , * Property - > GetPathName ( ) ) ;
}
}
2015-09-21 07:53:49 -04:00
Out . Logf ( TEXT ( " %s} \r \n " ) , FCString : : Tab ( Indent ) ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Generate a . proto message declaration for any functions marked as requiring one
*
* @ param InCallbackFunctions array of functions for consideration to generate . proto definitions
* @ param Indent starting indentation level
* @ param Output optional output redirect
*/
2015-11-18 16:20:49 -05:00
void FNativeClassHeaderGenerator : : ExportProtoMessage ( const TArray < UFunction * > & InCallbackFunctions , int32 Indent , FUHTStringBuilder * Output )
2014-03-14 14:13:41 -04:00
{
// Parms struct definitions.
2015-03-27 18:10:52 -04:00
FUHTStringBuilder HeaderOutput ;
2014-03-14 14:13:41 -04:00
TArray < UFunction * > CallbackFunctions = InCallbackFunctions ;
CallbackFunctions . Sort ( ) ;
for ( int32 Index = 0 ; Index < CallbackFunctions . Num ( ) ; Index + + )
{
UFunction * Function = CallbackFunctions [ Index ] ;
2015-01-20 09:33:54 -05:00
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
2014-03-14 14:13:41 -04:00
const FFuncInfo & FunctionData = CompilerInfo - > GetFunctionData ( ) ;
if ( FunctionData . FunctionExportFlags & FUNCEXPORT_NeedsProto )
{
if ( WillExportEventParms ( Function ) & & ! Function - > HasAnyFunctionFlags ( FUNC_Delegate ) )
{
FString FunctionName = Function - > GetName ( ) ;
TFieldIterator < UProperty > CommentIt ( Function ) ;
FString ParameterList ;
for ( ; CommentIt & & ( CommentIt - > PropertyFlags & CPF_Parm ) ; + + CommentIt )
{
UProperty * Param = * CommentIt ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Param ) ;
2014-03-14 14:13:41 -04:00
FString TypeText , ExtendedTypeText ;
TypeText = Param - > GetCPPType ( & ExtendedTypeText , CPPF_None ) ;
FString ParamName = FString : : Printf ( TEXT ( " %s%s %s " ) , * TypeText , * ExtendedTypeText , * Param - > GetName ( ) ) ;
// add this property to the parameter list string
if ( ParameterList . Len ( ) )
{
ParameterList + = TCHAR ( ' , ' ) ;
}
ParameterList + = ParamName ;
}
2015-09-21 07:53:49 -04:00
HeaderOutput . Logf ( TEXT ( " // %s%s(%s) \r \n " ) , FCString : : Tab ( Indent ) , * FunctionName , * ParameterList ) ;
2014-03-14 14:13:41 -04:00
TFieldIterator < UProperty > ParamIt ( Function ) ;
ExportProtoDeclaration ( HeaderOutput , FunctionName , ParamIt , CPF_Parm , Indent ) ;
}
}
}
if ( ! Output )
{
GeneratedProtoText . Log ( * HeaderOutput ) ;
}
else
{
Output - > Log ( HeaderOutput ) ;
}
}
// Java uses different coding standards for capitalization
static FString FixJavaName ( const FString & StringIn )
{
FString FixedString = StringIn ;
FixedString [ 0 ] = FChar : : ToLower ( FixedString [ 0 ] ) ; // java classes/variable start lower case
FixedString . ReplaceInline ( TEXT ( " ID " ) , TEXT ( " Id " ) , ESearchCase : : CaseSensitive ) ; // Id is standard instead of ID, some of our fnames use ID
return FixedString ;
}
/**
* Export a single . java declaration , recursing as necessary for sub declarations
*
* @ param Out output device
* @ param MessageName name of the message in the declaration
* @ param Properties array of parameters in the function definition
* @ param PropertyFlags flags to filter property array against
* @ param Ident starting indentation level
*/
void ExportMCPDeclaration ( FOutputDevice & Out , const FString & MessageName , TFieldIterator < UProperty > & Properties , uint64 PropertyFlags , int32 Indent )
{
2015-09-21 07:53:49 -04:00
Out . Logf ( TEXT ( " %spublic class %sCommand extends ProfileCommand \r \n " ) , FCString : : Tab ( Indent ) , * MessageName ) ;
Out . Logf ( TEXT ( " %s{ \r \n " ) , FCString : : Tab ( Indent ) ) ;
2014-03-14 14:13:41 -04:00
static TMap < FString , FString > ToMCPTypeMappings ;
static TMap < FString , FString > ToAnnotationMappings ;
static bool bInitMapping = false ;
if ( ! bInitMapping )
{
// Explicit type mappings
ToMCPTypeMappings . Add ( TEXT ( " FString " ) , TEXT ( " String " ) ) ;
ToMCPTypeMappings . Add ( TEXT ( " int32 " ) , TEXT ( " int " ) ) ;
ToMCPTypeMappings . Add ( TEXT ( " int64 " ) , TEXT ( " int " ) ) ;
ToMCPTypeMappings . Add ( TEXT ( " uint8 " ) , TEXT ( " byte " ) ) ;
ToMCPTypeMappings . Add ( TEXT ( " bool " ) , TEXT ( " boolean " ) ) ;
ToMCPTypeMappings . Add ( TEXT ( " double " ) , TEXT ( " double " ) ) ;
ToMCPTypeMappings . Add ( TEXT ( " float " ) , TEXT ( " float " ) ) ;
2014-04-23 19:29:53 -04:00
ToMCPTypeMappings . Add ( TEXT ( " byte " ) , TEXT ( " byte " ) ) ;
2014-03-14 14:13:41 -04:00
ToAnnotationMappings . Add ( TEXT ( " FString " ) , TEXT ( " @NotBlankOrNull " ) ) ;
bInitMapping = true ;
}
FString ConstructorParams ;
FString ConstructorText ;
for ( ; Properties & & ( Properties - > PropertyFlags & PropertyFlags ) ; + + Properties )
{
UProperty * Property = * Properties ;
UClass * PropClass = Property - > GetClass ( ) ;
// Skip out and return paramaters
if ( ( Property - > PropertyFlags & CPF_RepSkip ) | | ( Property - > PropertyFlags & CPF_ReturnParm ) )
{
continue ;
}
// export the property type text (e.g. FString; int32; TArray, etc.)
FString TypeText , ExtendedTypeText ;
TypeText = Property - > GetCPPType ( & ExtendedTypeText , CPPF_None ) ;
if ( PropClass ! = UInterfaceProperty : : StaticClass ( ) & & PropClass ! = UObjectProperty : : StaticClass ( ) )
{
// TODO Implement arrays
UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( Property ) ;
if ( ArrayProperty ! = NULL )
{
// skip array generation for Java, this should result in a List<TYPE> declaration, but we can do this by hand for now.
continue ;
}
2015-04-21 10:25:59 -04:00
// TODO Implement maps
UMapProperty * MapProperty = Cast < UMapProperty > ( Property ) ;
if ( MapProperty ! = NULL )
{
continue ;
}
2014-03-14 14:13:41 -04:00
/*bool bIsRepeated = false;
UArrayProperty * ArrayProperty = Cast < UArrayProperty > ( Property ) ;
if ( ArrayProperty ! = NULL )
{
UClass * InnerPropClass = ArrayProperty - > Inner - > GetClass ( ) ;
if ( InnerPropClass ! = UInterfaceProperty : : StaticClass ( ) & & InnerPropClass ! = UObjectProperty : : StaticClass ( ) )
{
FString InnerExtendedTypeText ;
FString InnerTypeText = ArrayProperty - > Inner - > GetCPPType ( & InnerExtendedTypeText , CPPF_None ) ;
TypeText = InnerTypeText ;
ExtendedTypeText = InnerExtendedTypeText ;
Property = ArrayProperty - > Inner ;
bIsRepeated = true ;
}
else
{
FError : : Throwf ( TEXT ( " ExportMCPDeclaration - Unhandled property type '%s': %s " ) , * PropClass - > GetName ( ) , * Property - > GetPathName ( ) ) ;
}
}
else if ( Property - > ArrayDim ! = 1 )
{
bIsRepeated = true ;
} */
FString VariableTypeName = FString : : Printf ( TEXT ( " %s%s " ) , * TypeText , * ExtendedTypeText ) ;
FString PropertyName = FixJavaName ( Property - > GetNameCPP ( ) ) ;
FString * MCPTypeName = NULL ;
FString * AnnotationName = NULL ;
UStructProperty * StructProperty = Cast < UStructProperty > ( Property ) ;
if ( StructProperty ! = NULL )
{
// TODO Implement structs
/* TFieldIterator<UProperty> StructIt(StructProperty->Struct);
2015-03-27 18:10:52 -04:00
ExportMCPDeclaration ( Out , VariableTypeName , StructIt , CPF_AllFlags , Indent + 1 ) ;
2014-03-14 14:13:41 -04:00
VariableTypeName = FString : : Printf ( TEXT ( " CMsg%sMessage " ) , * VariableTypeName ) ;
MCPTypeName = & VariableTypeName ; */
2014-08-21 20:30:51 -04:00
continue ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-04-23 19:29:53 -04:00
UByteProperty * ByteProperty = Cast < UByteProperty > ( Property ) ;
if ( ByteProperty ! = NULL & & ByteProperty - > Enum ! = NULL )
{
// treat enums like strings because that's how they'll be exported in JSON
MCPTypeName = ToMCPTypeMappings . Find ( TEXT ( " FString " ) ) ;
AnnotationName = ToAnnotationMappings . Find ( TEXT ( " FString " ) ) ;
}
else
{
MCPTypeName = ToMCPTypeMappings . Find ( VariableTypeName ) ;
AnnotationName = ToAnnotationMappings . Find ( VariableTypeName ) ;
}
2014-03-14 14:13:41 -04:00
}
if ( AnnotationName ! = NULL & & ! AnnotationName - > IsEmpty ( ) )
{
2015-09-21 07:53:49 -04:00
Out . Log ( FCString : : Tab ( Indent + 1 ) ) ;
2014-03-14 14:13:41 -04:00
Out . Logf ( TEXT ( " %s \r \n " ) , * * AnnotationName ) ;
}
if ( MCPTypeName ! = NULL )
{
2015-09-21 07:53:49 -04:00
Out . Log ( FCString : : Tab ( Indent + 1 ) ) ;
2014-03-14 14:13:41 -04:00
Out . Logf ( TEXT ( " private %s %s; \r \n " ) , * * MCPTypeName , * PropertyName ) ;
ConstructorParams + = FString : : Printf ( TEXT ( " , %s %s " ) , * * MCPTypeName , * PropertyName ) ;
2015-09-21 07:53:49 -04:00
ConstructorText + = FString : : Printf ( TEXT ( " %sthis.%s = %s; \r \n " ) , FCString : : Tab ( Indent + 2 ) , * PropertyName , * PropertyName ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-04-23 19:29:53 -04:00
FError : : Throwf ( TEXT ( " ExportMCPDeclaration - Unhandled property mapping '%s' (%s): %s " ) , * PropClass - > GetName ( ) , * VariableTypeName , * Property - > GetPathName ( ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
FError : : Throwf ( TEXT ( " ExportMCPDeclaration - Unhandled property type '%s': %s " ) , * PropClass - > GetName ( ) , * Property - > GetPathName ( ) ) ;
}
}
2015-09-21 07:53:49 -04:00
Out . Logf ( TEXT ( " \r \n %spublic %sCommand(String epicId, String profileId%s) \r \n " ) , FCString : : Tab ( Indent + 1 ) , * MessageName , * ConstructorParams ) ;
Out . Logf ( TEXT ( " %s{ \r \n " ) , FCString : : Tab ( Indent + 1 ) ) ;
Out . Logf ( TEXT ( " %ssuper(epicId, profileId); \r \n " ) , FCString : : Tab ( Indent + 2 ) ) ;
2014-03-14 14:13:41 -04:00
Out . Logf ( TEXT ( " %s " ) , * ConstructorText ) ;
2015-09-21 07:53:49 -04:00
Out . Logf ( TEXT ( " %s} \r \n " ) , FCString : : Tab ( Indent + 1 ) ) ;
2014-03-14 14:13:41 -04:00
2015-09-21 07:53:49 -04:00
Out . Logf ( TEXT ( " \r \n %s@Override \r \n " ) , FCString : : Tab ( Indent + 1 ) ) ;
Out . Logf ( TEXT ( " %sprotected void execute(@Name( \" profile \" ) @NotNull ProfileEx profile) \r \n " ) , FCString : : Tab ( Indent + 1 ) ) ;
Out . Logf ( TEXT ( " %s{ \r \n " ) , FCString : : Tab ( Indent + 1 ) ) ;
Out . Logf ( TEXT ( " %s} \r \n " ) , FCString : : Tab ( Indent + 1 ) ) ;
2014-03-14 14:13:41 -04:00
2015-09-21 07:53:49 -04:00
Out . Logf ( TEXT ( " %s} \r \n " ) , FCString : : Tab ( Indent ) ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Generate a . MCP message declaration for any functions marked as requiring one
*
* @ param InCallbackFunctions array of functions for consideration to generate . proto definitions
* @ param Indent starting indentation level
* @ param Output optional output redirect
*/
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportMCPMessage ( const TArray < UFunction * > & InCallbackFunctions , FClassMetaData * ClassData , int32 Indent , FUHTStringBuilder * Output )
2014-03-14 14:13:41 -04:00
{
// Parms struct definitions.
2015-03-27 18:10:52 -04:00
FUHTStringBuilder HeaderOutput ;
2014-03-14 14:13:41 -04:00
TArray < UFunction * > CallbackFunctions = InCallbackFunctions ;
CallbackFunctions . Sort ( ) ;
for ( int32 Index = 0 ; Index < CallbackFunctions . Num ( ) ; Index + + )
{
UFunction * Function = CallbackFunctions [ Index ] ;
2015-01-20 09:33:54 -05:00
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
2014-03-14 14:13:41 -04:00
const FFuncInfo & FunctionData = CompilerInfo - > GetFunctionData ( ) ;
if ( FunctionData . FunctionExportFlags & FUNCEXPORT_NeedsMCP )
{
if ( WillExportEventParms ( Function ) & & ! Function - > HasAnyFunctionFlags ( FUNC_Delegate ) )
{
FString FunctionName = Function - > GetName ( ) ;
TFieldIterator < UProperty > CommentIt ( Function ) ;
FString ParameterList ;
for ( ; CommentIt & & ( CommentIt - > PropertyFlags & CPF_Parm ) ; + + CommentIt )
{
UProperty * Param = * CommentIt ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Param ) ;
2014-03-14 14:13:41 -04:00
FString TypeText , ExtendedTypeText ;
TypeText = Param - > GetCPPType ( & ExtendedTypeText , CPPF_None ) ;
FString ParamName = FString : : Printf ( TEXT ( " %s%s %s " ) , * TypeText , * ExtendedTypeText , * Param - > GetName ( ) ) ;
// add this property to the parameter list string
if ( ParameterList . Len ( ) )
{
ParameterList + = TCHAR ( ' , ' ) ;
}
ParameterList + = ParamName ;
}
2015-09-21 07:53:49 -04:00
HeaderOutput . Logf ( TEXT ( " // %s%s(%s) \r \n " ) , FCString : : Tab ( Indent ) , * FunctionName , * ParameterList ) ;
2014-03-14 14:13:41 -04:00
TFieldIterator < UProperty > ParamIt ( Function ) ;
ExportMCPDeclaration ( HeaderOutput , FunctionName , ParamIt , CPF_Parm , Indent ) ;
}
}
}
if ( ! Output )
{
GeneratedMCPText . Log ( * HeaderOutput ) ;
}
else
{
Output - > Log ( HeaderOutput ) ;
}
}
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportEventParm ( UFunction * Function , FUHTStringBuilder & HeaderOutput , int32 Indent , bool bOutputConstructor )
2015-01-20 09:33:54 -05:00
{
if ( ! WillExportEventParms ( Function ) )
{
return ;
}
FString FunctionName = Function - > GetName ( ) ;
if ( Function - > HasAnyFunctionFlags ( FUNC_Delegate ) )
{
FunctionName = FunctionName . LeftChop ( FString ( HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX ) . Len ( ) ) ;
}
FString EventParmStructName = GetEventStructParamsName ( Function - > GetOuter ( ) , * FunctionName ) ;
2015-09-21 07:53:49 -04:00
HeaderOutput . Logf ( TEXT ( " %sstruct %s \r \n " ) , FCString : : Tab ( Indent ) , * EventParmStructName ) ;
HeaderOutput . Logf ( TEXT ( " %s{ \r \n " ) , FCString : : Tab ( Indent ) ) ;
2015-01-20 09:33:54 -05:00
for ( TFieldIterator < UProperty > It ( Function ) ; It & & ( It - > PropertyFlags & CPF_Parm ) ; + + It )
{
UProperty * Prop = * It ;
ForwardDeclarations . Add ( Prop ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder PropertyText ;
2015-09-21 07:53:49 -04:00
PropertyText . Log ( FCString : : Tab ( Indent + 1 ) ) ;
2015-01-20 09:33:54 -05:00
bool bEmitConst = Prop - > HasAnyPropertyFlags ( CPF_ConstParm ) & & Prop - > IsA < UObjectProperty > ( ) ;
//@TODO: UCREMOVAL: This is awful code duplication to avoid a double-const
{
// export 'const' for parameters
const bool bIsConstParam = ( Prop - > IsA ( UInterfaceProperty : : StaticClass ( ) ) & & ! Prop - > HasAllPropertyFlags ( CPF_OutParm ) ) ; //@TODO: This should be const once that flag exists
const bool bIsOnConstClass = ( Prop - > IsA ( UObjectProperty : : StaticClass ( ) ) & & ( ( UObjectProperty * ) Prop ) - > PropertyClass ! = NULL & & ( ( UObjectProperty * ) Prop ) - > PropertyClass - > HasAnyClassFlags ( CLASS_Const ) ) ;
if ( bIsConstParam | | bIsOnConstClass )
{
bEmitConst = false ; // ExportCppDeclaration will do it for us
}
}
if ( bEmitConst )
{
PropertyText . Logf ( TEXT ( " const " ) ) ;
}
const FString * Dim = GArrayDimensions . Find ( Prop ) ;
Prop - > ExportCppDeclaration ( PropertyText , EExportedDeclaration : : Local , Dim ? * * Dim : NULL ) ;
ApplyAlternatePropertyExportText ( Prop , PropertyText ) ;
PropertyText . Log ( TEXT ( " ; \r \n " ) ) ;
HeaderOutput + = * PropertyText ;
}
// constructor must initialize the return property if it needs it
UProperty * Prop = Function - > GetReturnProperty ( ) ;
if ( Prop & & bOutputConstructor )
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder InitializationAr ;
2015-01-20 09:33:54 -05:00
UStructProperty * InnerStruct = Cast < UStructProperty > ( Prop ) ;
bool bNeedsOutput = true ;
if ( InnerStruct )
{
bNeedsOutput = InnerStruct - > HasNoOpConstructor ( ) ;
}
else if (
Cast < UNameProperty > ( Prop ) | |
Cast < UDelegateProperty > ( Prop ) | |
Cast < UMulticastDelegateProperty > ( Prop ) | |
Cast < UStrProperty > ( Prop ) | |
Cast < UTextProperty > ( Prop ) | |
Cast < UArrayProperty > ( Prop ) | |
2015-04-21 10:25:59 -04:00
Cast < UMapProperty > ( Prop ) | |
2015-01-20 09:33:54 -05:00
Cast < UInterfaceProperty > ( Prop )
)
{
bNeedsOutput = false ;
}
if ( bNeedsOutput )
{
check ( Prop - > ArrayDim = = 1 ) ; // can't return arrays
2015-09-21 07:53:49 -04:00
HeaderOutput . Logf ( TEXT ( " \r \n %s/** Constructor, intializes return property only **/ \r \n " ) , FCString : : Tab ( Indent + 1 ) ) ;
HeaderOutput . Logf ( TEXT ( " %s%s() \r \n " ) , FCString : : Tab ( Indent + 1 ) , * EventParmStructName ) ;
HeaderOutput . Logf ( TEXT ( " %s%s %s(%s) \r \n " ) , FCString : : Tab ( Indent + 2 ) , TEXT ( " : " ) , * Prop - > GetName ( ) , * GetNullParameterValue ( Prop , false , true ) ) ;
HeaderOutput . Logf ( TEXT ( " %s{ \r \n " ) , FCString : : Tab ( Indent + 1 ) ) ;
HeaderOutput . Logf ( TEXT ( " %s} \r \n " ) , FCString : : Tab ( Indent + 1 ) ) ;
2015-01-20 09:33:54 -05:00
}
}
2015-09-21 07:53:49 -04:00
HeaderOutput . Logf ( TEXT ( " %s}; \r \n " ) , FCString : : Tab ( Indent ) ) ;
2015-01-20 09:33:54 -05:00
}
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportEventParms ( FScope & Scope , const TArray < UFunction * > & InCallbackFunctions , FUHTStringBuilder & Output , int32 Indent , bool bOutputConstructor )
2014-03-14 14:13:41 -04:00
{
// Parms struct definitions.
2015-03-27 18:10:52 -04:00
FUHTStringBuilder HeaderOutput ;
2014-03-14 14:13:41 -04:00
TArray < UFunction * > CallbackFunctions = InCallbackFunctions ;
CallbackFunctions . Sort ( ) ;
for ( int32 Index = 0 ; Index < CallbackFunctions . Num ( ) ; Index + + )
{
UFunction * Function = CallbackFunctions [ Index ] ;
2015-01-20 09:33:54 -05:00
ExportEventParm ( Function , HeaderOutput , Indent , bOutputConstructor ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
Output . Log ( HeaderOutput ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Get the intrinsic null value for this property
*
* @ param Prop the property to get the null value for
* @ param bMacroContext true when exporting the P_GET * macro , false when exporting the friendly C + + function header
*
* @ return the intrinsic null value for the property ( 0 for ints , TEXT ( " " ) for strings , etc . )
*/
FString FNativeClassHeaderGenerator : : GetNullParameterValue ( UProperty * Prop , bool bMacroContext , bool bInitializer /*=false*/ )
{
UClass * PropClass = Prop - > GetClass ( ) ;
UObjectPropertyBase * ObjectProperty = Cast < UObjectPropertyBase > ( Prop ) ;
if ( PropClass = = UByteProperty : : StaticClass ( )
| | PropClass = = UIntProperty : : StaticClass ( )
| | PropClass = = UBoolProperty : : StaticClass ( )
| | PropClass = = UFloatProperty : : StaticClass ( )
| | PropClass = = UDoubleProperty : : StaticClass ( ) )
{
// if we have a BoolProperty then set it to be false instead of 0
if ( PropClass = = UBoolProperty : : StaticClass ( ) )
{
return TEXT ( " false " ) ;
}
return TEXT ( " 0 " ) ;
}
else if ( PropClass = = UNameProperty : : StaticClass ( ) )
{
return TEXT ( " NAME_None " ) ;
}
else if ( PropClass = = UStrProperty : : StaticClass ( ) )
{
return TEXT ( " TEXT( \" \" ) " ) ;
}
else if ( PropClass = = UTextProperty : : StaticClass ( ) )
{
return TEXT ( " FText::GetEmpty() " ) ;
}
else if ( PropClass = = UArrayProperty : : StaticClass ( )
2015-04-21 10:25:59 -04:00
| | PropClass = = UMapProperty : : StaticClass ( )
2014-03-14 14:13:41 -04:00
| | PropClass = = UDelegateProperty : : StaticClass ( )
2014-06-02 14:20:58 -04:00
| | PropClass = = UMulticastDelegateProperty : : StaticClass ( ) )
2014-03-14 14:13:41 -04:00
{
FString Type , ExtendedType ;
Type = Prop - > GetCPPType ( & ExtendedType , CPPF_OptionalValue ) ;
return Type + ExtendedType + TEXT ( " () " ) ;
}
else if ( PropClass = = UStructProperty : : StaticClass ( ) )
{
bool bHasNoOpConstuctor = CastChecked < UStructProperty > ( Prop ) - > HasNoOpConstructor ( ) ;
if ( bInitializer & & bHasNoOpConstuctor )
{
return TEXT ( " ForceInit " ) ;
}
FString Type , ExtendedType ;
Type = Prop - > GetCPPType ( & ExtendedType , CPPF_OptionalValue ) ;
return Type + ExtendedType + ( bHasNoOpConstuctor ? TEXT ( " (ForceInit) " ) : TEXT ( " () " ) ) ;
}
else if ( ObjectProperty )
{
return TEXT ( " NULL " ) ;
}
else if ( PropClass = = UInterfaceProperty : : StaticClass ( ) )
{
return TEXT ( " NULL " ) ;
}
UE_LOG ( LogCompile , Fatal , TEXT ( " GetNullParameterValue - Unhandled property type '%s': %s " ) , * PropClass - > GetName ( ) , * Prop - > GetPathName ( ) ) ;
return TEXT ( " " ) ;
}
2014-12-08 07:30:42 -05:00
FString FNativeClassHeaderGenerator : : GetFunctionReturnString ( UFunction * Function )
{
if ( auto Return = Function - > GetReturnProperty ( ) )
{
FString ExtendedReturnType ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Return ) ;
2014-12-08 07:30:42 -05:00
FString ReturnType = Return - > GetCPPType ( & ExtendedReturnType , CPPF_ArgumentOrReturnValue ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder ReplacementText ;
ReplacementText + = ReturnType ;
2014-12-08 07:30:42 -05:00
ApplyAlternatePropertyExportText ( Return , ReplacementText ) ;
return ReplacementText + ExtendedReturnType ;
}
return TEXT ( " void " ) ;
}
/**
* Gets string with function const modifier type .
*
* @ param Function Function to get const modifier of .
* @ return Empty FString if function is non - const , FString ( " const " ) if function is const .
*/
FString GetFunctionConstModifierString ( UFunction * Function )
{
if ( Function - > HasAllFunctionFlags ( FUNC_Const ) )
{
return TEXT ( " const " ) ;
}
return FString ( ) ;
}
2015-04-20 06:19:21 -04:00
/**
* Converts Position within File to Line and Column .
*
* @ param File File contents .
* @ param Position Position in string to convert .
* @ param OutLine Result line .
* @ param OutColumn Result column .
*/
void GetLineAndColumnFromPositionInFile ( const FString & File , int32 Position , int32 & OutLine , int32 & OutColumn )
2014-12-08 07:30:42 -05:00
{
2015-04-20 06:19:21 -04:00
OutLine = 1 ;
OutColumn = 1 ;
int32 i ;
for ( i = 1 ; i < = Position ; + + i )
{
if ( File [ i ] = = ' \n ' )
{
+ + OutLine ;
OutColumn = 0 ;
}
else
{
+ + OutColumn ;
}
}
}
bool FNativeClassHeaderGenerator : : IsMissingVirtualSpecifier ( const FString & SourceFile , int32 FunctionNamePosition ) const
{
auto IsEndOfSearchChar = [ ] ( TCHAR C ) { return ( C = = TEXT ( ' } ' ) ) | | ( C = = TEXT ( ' { ' ) ) | | ( C = = TEXT ( ' ; ' ) ) ; } ;
// Find first occurrence of "}", ";", "{" going backwards from ImplementationPosition.
int32 EndOfSearchCharIndex = SourceFile . FindLastCharByPredicate ( IsEndOfSearchChar , FunctionNamePosition ) ;
check ( EndOfSearchCharIndex ! = INDEX_NONE ) ;
// Then find if there is "virtual" keyword starting from position of found character to ImplementationPosition
return ! HasIdentifierExactMatch ( & SourceFile [ EndOfSearchCharIndex ] , & SourceFile [ FunctionNamePosition ] , TEXT ( " virtual " ) ) ;
}
FString CreateClickableErrorMessage ( const FString & Filename , int32 Line , int32 Column )
{
return FString : : Printf ( TEXT ( " %s(%d,%d): error: " ) , * Filename , Line , Column ) ;
}
void FNativeClassHeaderGenerator : : CheckRPCFunctions ( const FFuncInfo & FunctionData , const FString & ClassName , int32 ImplementationPosition , int32 ValidatePosition , const FUnrealSourceFile & SourceFile )
{
bool bHasImplementation = ImplementationPosition ! = INDEX_NONE ;
bool bHasValidate = ValidatePosition ! = INDEX_NONE ;
2014-12-08 07:30:42 -05:00
auto Function = FunctionData . FunctionReference ;
auto FunctionReturnType = GetFunctionReturnString ( Function ) ;
2015-04-10 06:02:22 -04:00
auto ConstModifier = GetFunctionConstModifierString ( Function ) + TEXT ( " " ) ;
2014-12-08 07:30:42 -05:00
auto bIsNative = Function - > HasAllFunctionFlags ( FUNC_Native ) ;
auto bIsNet = Function - > HasAllFunctionFlags ( FUNC_Net ) ;
auto bIsNetValidate = Function - > HasAllFunctionFlags ( FUNC_NetValidate ) ;
auto bIsNetResponse = Function - > HasAllFunctionFlags ( FUNC_NetResponse ) ;
auto bIsBlueprintEvent = Function - > HasAllFunctionFlags ( FUNC_BlueprintEvent ) ;
bool bNeedsImplementation = ( bIsNet & & ! bIsNetResponse ) | | bIsBlueprintEvent | | bIsNative ;
bool bNeedsValidate = ( bIsNative | | bIsNet ) & & ! bIsNetResponse & & bIsNetValidate ;
check ( bNeedsImplementation | | bNeedsValidate ) ;
auto ParameterString = GetFunctionParameterString ( Function ) ;
2015-04-20 06:19:21 -04:00
const auto & Filename = SourceFile . GetFilename ( ) ;
const auto & FileContent = SourceFile . GetContent ( ) ;
2014-12-08 07:30:42 -05:00
//
// Get string with function specifiers, listing why we need _Implementation or _Validate functions.
//
TArray < FString > FunctionSpecifiers ;
FunctionSpecifiers . Reserve ( 4 ) ;
if ( bIsNative ) { FunctionSpecifiers . Add ( TEXT ( " Native " ) ) ; }
if ( bIsNet ) { FunctionSpecifiers . Add ( TEXT ( " Net " ) ) ; }
if ( bIsBlueprintEvent ) { FunctionSpecifiers . Add ( TEXT ( " BlueprintEvent " ) ) ; }
if ( bIsNetValidate ) { FunctionSpecifiers . Add ( TEXT ( " NetValidate " ) ) ; }
check ( FunctionSpecifiers . Num ( ) > 0 ) ;
//
// Coin static_assert message
//
2015-03-27 18:10:52 -04:00
FUHTStringBuilder AssertMessage ;
2014-12-08 07:30:42 -05:00
AssertMessage . Logf ( TEXT ( " Function %s was marked as %s " ) , * ( Function - > GetName ( ) ) , * FunctionSpecifiers [ 0 ] ) ;
for ( int32 i = 1 ; i < FunctionSpecifiers . Num ( ) ; + + i )
{
AssertMessage . Logf ( TEXT ( " , %s " ) , * FunctionSpecifiers [ i ] ) ;
}
AssertMessage . Logf ( TEXT ( " . " ) ) ;
//
2015-04-20 06:19:21 -04:00
// Check if functions are missing.
2014-12-08 07:30:42 -05:00
//
2015-04-20 06:19:21 -04:00
int32 Line ;
int32 Column ;
GetLineAndColumnFromPositionInFile ( FileContent , FunctionData . InputPos , Line , Column ) ;
2015-04-10 06:02:22 -04:00
if ( bNeedsImplementation & & ! bHasImplementation )
2014-12-08 07:30:42 -05:00
{
2015-04-20 06:19:21 -04:00
FString ErrorPosition = CreateClickableErrorMessage ( Filename , Line , Column ) ;
FString FunctionDecl = FString : : Printf ( TEXT ( " virtual %s %s::%s(%s) %s " ) , * FunctionReturnType , * ClassName , * FunctionData . CppImplName , * ParameterString , * ConstModifier ) ;
FError : : Throwf ( TEXT ( " %s%s Declare function %s " ) , * ErrorPosition , * AssertMessage , * FunctionDecl ) ;
2014-12-08 07:30:42 -05:00
}
2015-04-10 06:02:22 -04:00
if ( bNeedsValidate & & ! bHasValidate )
2014-12-08 07:30:42 -05:00
{
2015-04-20 06:19:21 -04:00
FString ErrorPosition = CreateClickableErrorMessage ( Filename , Line , Column ) ;
FString FunctionDecl = FString : : Printf ( TEXT ( " virtual bool %s::%s(%s) %s " ) , * ClassName , * FunctionData . CppValidationImplName , * ParameterString , * ConstModifier ) ;
FError : : Throwf ( TEXT ( " %s%s Declare function %s " ) , * ErrorPosition , * AssertMessage , * FunctionDecl ) ;
}
//
// If all needed functions are declared, check if they have virtual specifiers.
//
if ( bNeedsImplementation & & bHasImplementation & & IsMissingVirtualSpecifier ( FileContent , ImplementationPosition ) )
{
GetLineAndColumnFromPositionInFile ( FileContent , ImplementationPosition , Line , Column ) ;
FString ErrorPosition = CreateClickableErrorMessage ( Filename , Line , Column ) ;
FString FunctionDecl = FString : : Printf ( TEXT ( " %s %s::%s(%s) %s " ) , * FunctionReturnType , * ClassName , * FunctionData . CppImplName , * ParameterString , * ConstModifier ) ;
FError : : Throwf ( TEXT ( " %sDeclared function %sis not marked as virtual. " ) , * ErrorPosition , * FunctionDecl ) ;
}
if ( bNeedsValidate & & bHasValidate & & IsMissingVirtualSpecifier ( FileContent , ValidatePosition ) )
{
GetLineAndColumnFromPositionInFile ( FileContent , ValidatePosition , Line , Column ) ;
FString ErrorPosition = CreateClickableErrorMessage ( Filename , Line , Column ) ;
FString FunctionDecl = FString : : Printf ( TEXT ( " bool %s::%s(%s) %s " ) , * ClassName , * FunctionData . CppValidationImplName , * ParameterString , * ConstModifier ) ;
FError : : Throwf ( TEXT ( " %sDeclared function %sis not marked as virtual. " ) , * ErrorPosition , * FunctionDecl ) ;
2014-12-08 07:30:42 -05:00
}
}
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportNativeFunctionHeader ( const FFuncInfo & FunctionData , FUHTStringBuilder & HeaderOutput , EExportFunctionType : : Type FunctionType , EExportFunctionHeaderStyle : : Type FunctionHeaderStyle , const TCHAR * ExtraParam )
2014-03-14 14:13:41 -04:00
{
UFunction * Function = FunctionData . FunctionReference ;
const bool bIsDelegate = Function - > HasAnyFunctionFlags ( FUNC_Delegate ) ;
const bool bIsInterface = ! bIsDelegate & & Function - > GetOwnerClass ( ) - > HasAnyClassFlags ( CLASS_Interface ) ;
const bool bIsK2Override = Function - > HasAnyFunctionFlags ( FUNC_BlueprintEvent ) ;
2015-03-27 18:10:52 -04:00
if ( ! bIsDelegate )
{
HeaderOutput + = TEXT ( " \t " ) ;
}
2014-03-14 14:13:41 -04:00
if ( FunctionHeaderStyle = = EExportFunctionHeaderStyle : : Declaration )
{
// cpp implementation of functions never have these appendages
// If the function was marked as 'RequiredAPI', then add the *_API macro prefix. Note that if the class itself
// was marked 'RequiredAPI', this is not needed as C++ will exports all methods automatically.
2015-01-20 09:33:54 -05:00
if ( FunctionType ! = EExportFunctionType : : Event & &
! Function - > GetOwnerClass ( ) - > HasAnyClassFlags ( CLASS_RequiredAPI ) & &
( FunctionData . FunctionExportFlags & FUNCEXPORT_RequiredAPI ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
HeaderOutput . Log ( GetAPIString ( ) ) ;
2014-03-14 14:13:41 -04:00
}
if ( FunctionType = = EExportFunctionType : : Interface )
{
HeaderOutput . Log ( TEXT ( " static " ) ) ;
}
else if ( bIsK2Override )
{
HeaderOutput . Log ( TEXT ( " virtual " ) ) ;
}
// if the owning class is an interface class
else if ( bIsInterface )
{
HeaderOutput . Log ( TEXT ( " virtual " ) ) ;
}
// this is not an event, the function is not a static function and the function is not marked final
else if ( FunctionType ! = EExportFunctionType : : Event & & ! Function - > HasAnyFunctionFlags ( FUNC_Static ) & & ! ( FunctionData . FunctionExportFlags & FUNCEXPORT_Final ) )
{
HeaderOutput . Log ( TEXT ( " virtual " ) ) ;
}
else if ( FunctionData . FunctionExportFlags & FUNCEXPORT_Inline )
{
HeaderOutput . Log ( TEXT ( " inline " ) ) ;
}
}
if ( auto Return = Function - > GetReturnProperty ( ) )
{
FString ExtendedReturnType ;
FString ReturnType = Return - > GetCPPType ( & ExtendedReturnType , ( FunctionHeaderStyle = = EExportFunctionHeaderStyle : : Definition & & ( FunctionType ! = EExportFunctionType : : Interface ) ? CPPF_Implementation : 0 ) | CPPF_ArgumentOrReturnValue ) ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Return ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder ReplacementText ;
ReplacementText + = ReturnType ;
2014-03-14 14:13:41 -04:00
ApplyAlternatePropertyExportText ( Return , ReplacementText ) ;
HeaderOutput . Logf ( TEXT ( " %s%s " ) , * ReplacementText , * ExtendedReturnType ) ;
}
else
{
HeaderOutput . Log ( TEXT ( " void " ) ) ;
}
FString FunctionName ;
if ( FunctionHeaderStyle = = EExportFunctionHeaderStyle : : Definition )
{
2014-06-02 07:02:29 -04:00
FunctionName = FString ( NameLookupCPP . GetNameCPP ( CastChecked < UClass > ( Function - > GetOuter ( ) ) , bIsInterface | | FunctionType = = EExportFunctionType : : Interface ) ) + TEXT ( " :: " ) ;
2014-03-14 14:13:41 -04:00
}
if ( FunctionType = = EExportFunctionType : : Interface )
{
FunctionName + = FString : : Printf ( TEXT ( " Execute_%s " ) , * Function - > GetName ( ) ) ;
}
else if ( FunctionType = = EExportFunctionType : : Event )
{
FunctionName + = FunctionData . MarshallAndCallName ;
}
else
{
FunctionName + = FunctionData . CppImplName ;
}
HeaderOutput . Logf ( TEXT ( " %s( " ) , * FunctionName ) ;
int32 ParmCount = 0 ;
// Emit extra parameter if we have one
if ( ExtraParam )
{
HeaderOutput + = ExtraParam ;
+ + ParmCount ;
}
for ( TFieldIterator < UProperty > It ( Function ) ; It & & ( It - > PropertyFlags & ( CPF_Parm | CPF_ReturnParm ) ) = = CPF_Parm ; + + It )
{
UProperty * Property = * It ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Property ) ;
2015-01-20 09:33:54 -05:00
2014-03-14 14:13:41 -04:00
if ( ParmCount + + )
{
HeaderOutput . Log ( TEXT ( " , " ) ) ;
}
2015-03-27 18:10:52 -04:00
FUHTStringBuilder PropertyText ;
2014-03-14 14:13:41 -04:00
const FString * Dim = GArrayDimensions . Find ( Property ) ;
Property - > ExportCppDeclaration ( PropertyText , EExportedDeclaration : : Parameter , Dim ? * * Dim : NULL ) ;
ApplyAlternatePropertyExportText ( Property , PropertyText ) ;
HeaderOutput + = PropertyText ;
}
HeaderOutput . Log ( TEXT ( " ) " ) ) ;
if ( FunctionType ! = EExportFunctionType : : Interface )
{
if ( ! bIsDelegate & & Function - > HasAllFunctionFlags ( FUNC_Const ) )
{
HeaderOutput . Log ( TEXT ( " const " ) ) ;
}
if ( bIsInterface & & FunctionHeaderStyle = = EExportFunctionHeaderStyle : : Declaration )
{
// all methods in interface classes are pure virtuals
HeaderOutput . Log ( TEXT ( " =0 " ) ) ;
}
}
}
/**
* Export the actual internals to a standard thunk function
*
* @ param RPCWrappers output device for writing
* @ param FunctionData function data for the current function
* @ param Parameters list of parameters in the function
* @ param Return return parameter for the function
2015-03-17 05:19:11 -04:00
* @ param DeprecationWarningOutputDevice Device to output deprecation warnings for _Validate and _Implementation functions .
2014-03-14 14:13:41 -04:00
*/
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ExportFunctionThunk ( FUHTStringBuilder & RPCWrappers , UFunction * Function , const FFuncInfo & FunctionData , const TArray < UProperty * > & Parameters , UProperty * Return , FUHTStringBuilder & DeprecationWarningOutputDevice )
2014-03-14 14:13:41 -04:00
{
// export the GET macro for this parameter
FString ParameterList ;
2014-12-08 07:30:42 -05:00
for ( int32 ParameterIndex = 0 ; ParameterIndex < Parameters . Num ( ) ; ParameterIndex + + )
2014-03-14 14:13:41 -04:00
{
UProperty * Param = Parameters [ ParameterIndex ] ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Param ) ;
2015-01-20 09:33:54 -05:00
2014-03-14 14:13:41 -04:00
FString EvalBaseText = TEXT ( " P_GET_ " ) ; // e.g. P_GET_STR
FString EvalModifierText ; // e.g. _REF
FString EvalParameterText ; // e.g. (UObject*,NULL)
FString TypeText ;
2015-07-10 08:56:36 -04:00
bool bPassAsNoPtr = false ;
2014-12-08 07:30:42 -05:00
if ( Param - > ArrayDim > 1 )
2014-03-14 14:13:41 -04:00
{
EvalBaseText + = TEXT ( " ARRAY " ) ;
TypeText = Param - > GetCPPType ( ) ;
}
else
{
EvalBaseText + = Param - > GetCPPMacroType ( TypeText ) ;
}
2015-07-10 08:56:36 -04:00
if ( Param - > HasAllPropertyFlags ( CPF_UObjectWrapper | CPF_OutParm )
& & Param - > IsA ( UClassProperty : : StaticClass ( ) ) )
{
TypeText = Param - > GetCPPType ( ) ;
bPassAsNoPtr = true ;
}
2015-03-27 18:10:52 -04:00
FUHTStringBuilder ReplacementText ;
ReplacementText + = TypeText ;
2015-07-10 08:56:36 -04:00
2014-03-14 14:13:41 -04:00
ApplyAlternatePropertyExportText ( Param , ReplacementText ) ;
TypeText = ReplacementText ;
FString DefaultValueText ;
2015-04-13 13:43:58 -04:00
FString ParamPrefix = TEXT ( " Z_Param_ " ) ;
2014-03-14 14:13:41 -04:00
// if this property is an out parm, add the REF tag
if ( Param - > PropertyFlags & CPF_OutParm )
{
2015-07-10 08:56:36 -04:00
if ( ! bPassAsNoPtr )
{
2014-03-14 14:13:41 -04:00
EvalModifierText + = TEXT ( " _REF " ) ;
2015-07-10 08:56:36 -04:00
}
else
{
// Parameters passed as TSubclassOf<Class>& shouldn't have asterisk added.
EvalModifierText + = TEXT ( " _REF_NO_PTR " ) ;
}
2015-04-13 13:43:58 -04:00
ParamPrefix + = TEXT ( " Out_ " ) ;
2014-03-14 14:13:41 -04:00
}
// if this property requires a specialization, add a comma to the type name so we can print it out easily
2014-12-08 07:30:42 -05:00
if ( TypeText ! = TEXT ( " " ) )
2014-03-14 14:13:41 -04:00
{
TypeText + = TCHAR ( ' , ' ) ;
}
FString ParamName = ParamPrefix + Param - > GetName ( ) ;
EvalParameterText = FString : : Printf ( TEXT ( " (%s%s%s) " ) , * TypeText , * ParamName , * DefaultValueText ) ;
2015-03-27 18:10:52 -04:00
RPCWrappers . Logf ( TEXT ( " \t \t %s%s%s; " ) LINE_TERMINATOR , * EvalBaseText , * EvalModifierText , * EvalParameterText ) ;
2014-03-14 14:13:41 -04:00
// add this property to the parameter list string
2014-12-08 07:30:42 -05:00
if ( ParameterList . Len ( ) )
2014-03-14 14:13:41 -04:00
{
ParameterList + = TCHAR ( ' , ' ) ;
}
{
2014-12-08 07:30:42 -05:00
UDelegateProperty * DelegateProp = Cast < UDelegateProperty > ( Param ) ;
if ( DelegateProp ! = NULL )
2014-03-14 14:13:41 -04:00
{
// For delegates, add an explicit conversion to the specific type of delegate before passing it along
2014-12-08 07:30:42 -05:00
const FString FunctionName = DelegateProp - > SignatureFunction - > GetName ( ) . LeftChop ( FString ( HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX ) . Len ( ) ) ;
const FString CPPDelegateName = FString ( TEXT ( " F " ) ) + FunctionName ;
ParamName = FString : : Printf ( TEXT ( " %s(%s) " ) , * CPPDelegateName , * ParamName ) ;
2014-03-14 14:13:41 -04:00
}
}
{
2014-12-08 07:30:42 -05:00
UMulticastDelegateProperty * MulticastDelegateProp = Cast < UMulticastDelegateProperty > ( Param ) ;
if ( MulticastDelegateProp ! = NULL )
2014-03-14 14:13:41 -04:00
{
// For delegates, add an explicit conversion to the specific type of delegate before passing it along
2014-12-08 07:30:42 -05:00
const FString FunctionName = MulticastDelegateProp - > SignatureFunction - > GetName ( ) . LeftChop ( FString ( HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX ) . Len ( ) ) ;
const FString CPPDelegateName = FString ( TEXT ( " F " ) ) + FunctionName ;
ParamName = FString : : Printf ( TEXT ( " %s(%s) " ) , * CPPDelegateName , * ParamName ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-08-12 08:51:25 -04:00
UByteProperty * ByteProp = Cast < UByteProperty > ( Param ) ;
if ( ByteProp & & ByteProp - > Enum )
2014-03-14 14:13:41 -04:00
{
// For enums, add an explicit conversion
if ( ! ( ByteProp - > PropertyFlags & CPF_OutParm ) )
{
2014-12-08 07:30:42 -05:00
ParamName = FString : : Printf ( TEXT ( " %s(%s) " ) , * ByteProp - > Enum - > CppType , * ParamName ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-12-15 15:29:48 -05:00
if ( ByteProp - > Enum - > GetCppForm ( ) = = UEnum : : ECppForm : : EnumClass )
{
// If we're an enum class don't require the wrapper
ParamName = FString : : Printf ( TEXT ( " (%s&)(%s) " ) , * ByteProp - > Enum - > CppType , * ParamName ) ;
}
else
{
ParamName = FString : : Printf ( TEXT ( " (TEnumAsByte<%s>&)(%s) " ) , * ByteProp - > Enum - > CppType , * ParamName ) ;
}
2014-03-14 14:13:41 -04:00
}
}
ParameterList + = ParamName ;
}
2015-03-27 18:10:52 -04:00
RPCWrappers + = TEXT ( " \t \t P_FINISH; " ) LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
2014-12-11 11:49:41 -05:00
auto ClassRange = ClassDefinitionRange ( ) ;
2015-01-20 09:33:54 -05:00
if ( ClassDefinitionRanges . Contains ( Function - > GetOwnerClass ( ) ) )
2014-12-11 11:49:41 -05:00
{
2015-01-20 09:33:54 -05:00
ClassRange = ClassDefinitionRanges [ Function - > GetOwnerClass ( ) ] ;
2015-07-15 13:24:05 -04:00
ClassRange . Validate ( ) ;
2014-12-11 11:49:41 -05:00
}
auto ClassStart = ClassRange . Start ;
auto ClassEnd = ClassRange . End ;
auto ClassDefinition = FString ( ClassEnd - ClassStart , ClassStart ) ;
2015-01-20 09:33:54 -05:00
auto ClassName = Function - > GetOwnerClass ( ) - > GetName ( ) ;
2014-12-11 11:49:41 -05:00
auto FunctionName = Function - > GetName ( ) ;
2015-04-10 06:02:22 -04:00
bool bHasImplementation = HasIdentifierExactMatch ( ClassDefinition , FunctionData . CppImplName ) ;
bool bHasValidate = HasIdentifierExactMatch ( ClassDefinition , FunctionData . CppValidationImplName ) ;
2014-12-11 11:49:41 -05:00
auto bShouldEnableImplementationDeprecation =
// Enable deprecation warnings only if GENERATED_BODY is used inside class or interface (not GENERATED_UCLASS_BODY etc.)
ClassRange . bHasGeneratedBody
2015-02-06 09:54:41 -05:00
// and implementation function is called, but not the one declared by user
& & ( FunctionData . CppImplName ! = FunctionName & & ! bHasImplementation ) ;
2014-12-11 11:49:41 -05:00
auto bShouldEnableValidateDeprecation =
// Enable deprecation warnings only if GENERATED_BODY is used inside class or interface (not GENERATED_UCLASS_BODY etc.)
ClassRange . bHasGeneratedBody
2015-02-06 09:54:41 -05:00
// and validation function is called
& & ( FunctionData . FunctionFlags & FUNC_NetValidate ) & & ! bHasValidate ;
2014-12-11 11:49:41 -05:00
//Emit warning here if necessary
2015-03-27 18:10:52 -04:00
FUHTStringBuilder FunctionDeclaration ;
2014-12-11 11:49:41 -05:00
ExportNativeFunctionHeader ( FunctionData , FunctionDeclaration , EExportFunctionType : : Function , EExportFunctionHeaderStyle : : Declaration ) ;
FunctionDeclaration . Trim ( ) ;
2014-03-14 14:13:41 -04:00
// Call the validate function if there is one
2014-12-08 07:30:42 -05:00
if ( ! ( FunctionData . FunctionExportFlags & FUNCEXPORT_CppStatic ) & & ( FunctionData . FunctionFlags & FUNC_NetValidate ) )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
RPCWrappers . Logf ( TEXT ( " \t \t if (!this->%s(%s)) " ) LINE_TERMINATOR , * FunctionData . CppValidationImplName , * ParameterList ) ;
RPCWrappers . Logf ( TEXT ( " \t \t { " ) LINE_TERMINATOR ) ;
RPCWrappers . Logf ( TEXT ( " \t \t \t RPC_ValidateFailed(TEXT( \" %s \" )); " ) LINE_TERMINATOR , * FunctionData . CppValidationImplName ) ;
RPCWrappers . Logf ( TEXT ( " \t \t \t return; " ) LINE_TERMINATOR ) ; // If we got here, the validation function check failed
RPCWrappers . Logf ( TEXT ( " \t \t } " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
}
// write out the return value
2015-03-27 18:10:52 -04:00
RPCWrappers . Log ( TEXT ( " \t \t " ) ) ;
2014-12-08 07:30:42 -05:00
if ( Return ! = NULL )
2014-03-14 14:13:41 -04:00
{
FString ReturnType , ReturnExtendedType ;
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Return ) ;
2014-03-14 14:13:41 -04:00
ReturnType = Return - > GetCPPType ( & ReturnExtendedType ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder ReplacementText ;
ReplacementText + = ReturnType ;
2014-03-14 14:13:41 -04:00
ApplyAlternatePropertyExportText ( Return , ReplacementText ) ;
ReturnType = ReplacementText ;
2015-04-13 13:43:58 -04:00
RPCWrappers . Logf ( TEXT ( " *(%s%s*) " ) TEXT ( PREPROCESSOR_TO_STRING ( RESULT_PARAM ) ) TEXT ( " = " ) , * ReturnType , * ReturnExtendedType ) ;
2014-03-14 14:13:41 -04:00
}
// export the call to the C++ version
if ( FunctionData . FunctionExportFlags & FUNCEXPORT_CppStatic )
{
2015-03-27 18:10:52 -04:00
RPCWrappers . Logf ( TEXT ( " %s::%s(%s); " ) LINE_TERMINATOR , NameLookupCPP . GetNameCPP ( Function - > GetOwnerClass ( ) ) , * FunctionData . CppImplName , * ParameterList ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-03-27 18:10:52 -04:00
RPCWrappers . Logf ( TEXT ( " this->%s(%s); " ) LINE_TERMINATOR , * FunctionData . CppImplName , * ParameterList ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-12-08 07:30:42 -05:00
FString FNativeClassHeaderGenerator : : GetFunctionParameterString ( UFunction * Function )
{
FString ParameterList ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder PropertyText ;
2014-12-08 07:30:42 -05:00
for ( auto Property : TFieldRange < UProperty > ( Function ) )
{
2014-12-11 11:49:41 -05:00
ForwardDeclarations . Add ( Property ) ;
2014-12-08 07:30:42 -05:00
if ( ( Property - > PropertyFlags & ( CPF_Parm | CPF_ReturnParm ) ) ! = CPF_Parm )
{
break ;
}
if ( ParameterList . Len ( ) )
{
ParameterList + = TEXT ( " , " ) ;
}
auto Dim = GArrayDimensions . Find ( Property ) ;
2014-12-11 16:29:40 -05:00
Property - > ExportCppDeclaration ( PropertyText , EExportedDeclaration : : Parameter , Dim ? * * Dim : NULL , 0 , true ) ;
2014-12-08 07:30:42 -05:00
ApplyAlternatePropertyExportText ( Property , PropertyText ) ;
ParameterList + = PropertyText ;
2015-03-27 18:10:52 -04:00
PropertyText . Reset ( ) ;
2014-12-08 07:30:42 -05:00
}
return ParameterList ;
}
2015-01-20 09:33:54 -05:00
void FNativeClassHeaderGenerator : : ExportNativeFunctions ( FUnrealSourceFile & SourceFile , UClass * Class , FClassMetaData * ClassData )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder RPCWrappers ;
2015-04-10 06:02:22 -04:00
FUHTStringBuilder AutogeneratedBlueprintFunctionDeclarations ;
FUHTStringBuilder AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared ;
auto ClassName = Class - > GetName ( ) ;
2014-03-14 14:13:41 -04:00
2014-12-11 11:49:41 -05:00
auto ClassRange = ClassDefinitionRange ( ) ;
2015-01-20 09:33:54 -05:00
if ( ClassDefinitionRanges . Contains ( Class ) )
2014-12-11 11:49:41 -05:00
{
2015-01-20 09:33:54 -05:00
ClassRange = ClassDefinitionRanges [ Class ] ;
2015-07-15 13:24:05 -04:00
ClassRange . Validate ( ) ;
2014-12-11 11:49:41 -05:00
}
2014-03-14 14:13:41 -04:00
// export the C++ stubs
2015-01-20 09:33:54 -05:00
2015-09-21 07:53:49 -04:00
for ( UFunction * Function : TFieldRange < UFunction > ( Class , EFieldIteratorFlags : : ExcludeSuper ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
if ( ! ( Function - > FunctionFlags & FUNC_Native ) )
{
continue ;
}
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
2014-12-08 07:30:42 -05:00
const FFuncInfo & FunctionData = CompilerInfo - > GetFunctionData ( ) ;
// Custom thunks don't get any C++ stub function generated
if ( FunctionData . FunctionExportFlags & FUNCEXPORT_CustomThunk )
2015-01-20 09:33:54 -05:00
{
2014-12-08 07:30:42 -05:00
continue ;
2015-01-20 09:33:54 -05:00
}
2014-12-08 07:30:42 -05:00
2015-03-27 18:10:52 -04:00
FUHTStringBuilder & DestinationForDecl = RPCWrappers ;
2014-12-08 07:30:42 -05:00
// Should we emit these to RPC wrappers or just ignore them?
const bool bWillBeProgrammerTyped = FunctionData . CppImplName = = Function - > GetName ( ) ;
if ( ! bWillBeProgrammerTyped )
2014-03-14 14:13:41 -04:00
{
2014-12-11 11:49:41 -05:00
auto ClassStart = ClassRange . Start ;
auto ClassEnd = ClassRange . End ;
auto ClassDefinition = FString ( ClassEnd - ClassStart , ClassStart ) ;
auto FunctionName = Function - > GetName ( ) ;
2015-04-20 06:19:21 -04:00
int32 ClassDefinitionStartPosition = ClassStart - * SourceFile . GetContent ( ) ;
2014-12-11 11:49:41 -05:00
2015-04-20 06:19:21 -04:00
int32 ImplementationPosition = FindIdentifierExactMatch ( ClassDefinition , FunctionData . CppImplName ) ;
if ( ImplementationPosition ! = INDEX_NONE )
{
ImplementationPosition + = ClassDefinitionStartPosition ;
}
int32 ValidatePosition = FindIdentifierExactMatch ( ClassDefinition , FunctionData . CppValidationImplName ) ;
if ( ValidatePosition ! = INDEX_NONE )
{
ValidatePosition + = ClassDefinitionStartPosition ;
}
bool bHasImplementation = ImplementationPosition ! = INDEX_NONE ;
bool bHasValidate = ValidatePosition ! = INDEX_NONE ;
2014-12-11 11:49:41 -05:00
//Emit warning here if necessary
2015-03-27 18:10:52 -04:00
FUHTStringBuilder FunctionDeclaration ;
2014-12-11 11:49:41 -05:00
ExportNativeFunctionHeader ( FunctionData , FunctionDeclaration , EExportFunctionType : : Function , EExportFunctionHeaderStyle : : Declaration ) ;
FunctionDeclaration . Log ( TEXT ( " ; \r \n " ) ) ;
2014-03-14 14:13:41 -04:00
// Declare validation function if needed
2014-12-08 07:30:42 -05:00
if ( FunctionData . FunctionFlags & FUNC_NetValidate )
2014-03-14 14:13:41 -04:00
{
2014-12-08 07:30:42 -05:00
FString ParameterList = GetFunctionParameterString ( Function ) ;
2014-08-19 09:44:20 -04:00
2014-12-08 07:30:42 -05:00
auto Virtual = ( ! FunctionData . FunctionReference - > HasAnyFunctionFlags ( FUNC_Static ) & & ! ( FunctionData . FunctionExportFlags & FUNCEXPORT_Final ) ) ? TEXT ( " virtual " ) : TEXT ( " " ) ;
2015-03-17 05:19:11 -04:00
FStringOutputDevice ValidDecl ;
ValidDecl . Logf ( TEXT ( " \t %s bool %s(%s); \r \n " ) , Virtual , * FunctionData . CppValidationImplName , * ParameterList ) ;
AutogeneratedBlueprintFunctionDeclarations . Log ( * ValidDecl ) ;
2014-12-11 11:49:41 -05:00
if ( ! bHasValidate )
{
2015-03-17 05:19:11 -04:00
AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared . Logf ( * ValidDecl ) ;
2014-12-11 11:49:41 -05:00
}
2014-03-14 14:13:41 -04:00
}
2014-12-11 11:49:41 -05:00
AutogeneratedBlueprintFunctionDeclarations . Log ( * FunctionDeclaration ) ;
2015-02-06 09:54:41 -05:00
if ( ( FunctionData . CppImplName ! = FunctionName & & ! bHasImplementation ) )
2014-03-14 14:13:41 -04:00
{
2014-12-11 11:49:41 -05:00
AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared . Log ( * FunctionDeclaration ) ;
2014-03-14 14:13:41 -04:00
}
2014-12-11 11:49:41 -05:00
2015-04-10 06:02:22 -04:00
// Versions that skip function autodeclaration throw an error when a function is missing.
if ( ( SourceFile . GetGeneratedCodeVersionForStruct ( Class ) > EGeneratedCodeVersion : : V1 ) & & ClassRange . bHasGeneratedBody )
{
2015-04-20 06:19:21 -04:00
auto Name = Class - > HasAnyClassFlags ( CLASS_Interface ) ? * ( FString ( TEXT ( " I " ) ) + ClassName ) : NameLookupCPP . GetNameCPP ( Class ) ;
CheckRPCFunctions ( FunctionData , Name , ImplementationPosition , ValidatePosition , SourceFile ) ;
2015-04-10 06:02:22 -04:00
}
2014-03-14 14:13:41 -04:00
}
2014-12-08 07:30:42 -05:00
if ( bMultiLineUFUNCTION )
{
RPCWrappers . Log ( TEXT ( " \r \n " ) ) ;
}
// if this function was originally declared in a base class, and it isn't a static function,
// only the C++ function header will be exported
if ( ! ShouldExportFunction ( Function ) )
{
continue ;
}
// export the script wrappers
2015-03-27 18:10:52 -04:00
RPCWrappers . Logf ( TEXT ( " \t DECLARE_FUNCTION(%s) " ) , * FunctionData . UnMarshallAndCallName ) ;
RPCWrappers + = LINE_TERMINATOR TEXT ( " \t { " ) LINE_TERMINATOR ;
2014-12-08 07:30:42 -05:00
auto Parameters = GetFunctionParmsAndReturn ( FunctionData . FunctionReference ) ;
2015-03-17 05:19:11 -04:00
ExportFunctionThunk ( RPCWrappers , Function , FunctionData , Parameters . Parms , Parameters . Return , AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared ) ;
2014-12-08 07:30:42 -05:00
2015-03-27 18:10:52 -04:00
RPCWrappers + = TEXT ( " \t } " ) LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
FString MacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _RPC_WRAPPERS " ) ) ;
WriteMacro ( GeneratedHeaderText , MacroName , AutogeneratedBlueprintFunctionDeclarations + RPCWrappers ) ;
2015-03-27 18:10:52 -04:00
InClassMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * MacroName ) ;
2014-12-08 07:30:42 -05:00
// Put static checks before RPCWrappers to get proper messages from static asserts before compiler errors.
2015-01-20 09:33:54 -05:00
FString NoPureDeclsMacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _RPC_WRAPPERS_NO_PURE_DECLS " ) ) ;
2015-04-10 06:02:22 -04:00
if ( SourceFile . GetGeneratedCodeVersionForStruct ( Class ) > EGeneratedCodeVersion : : V1 )
{
WriteMacro ( GeneratedHeaderText , NoPureDeclsMacroName , RPCWrappers ) ;
}
else
{
WriteMacro ( GeneratedHeaderText , NoPureDeclsMacroName , AutogeneratedBlueprintFunctionDeclarationsOnlyNotDeclared + RPCWrappers ) ;
}
2015-03-27 18:10:52 -04:00
InClassNoPureDeclsMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * NoPureDeclsMacroName ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Exports the methods which trigger UnrealScript events and delegates .
*
* @ param CallbackFunctions the functions to export
*/
2015-01-20 09:33:54 -05:00
TArray < UFunction * > FNativeClassHeaderGenerator : : ExportCallbackFunctions ( FUnrealSourceFile & SourceFile , UClass * Class , FClassMetaData * ClassData )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
TArray < UFunction * > CallbackFunctions ;
2014-03-14 14:13:41 -04:00
2015-09-21 07:53:49 -04:00
for ( UFunction * Function : TFieldRange < UFunction > ( Class , EFieldIteratorFlags : : ExcludeSuper ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
if ( ( Function - > FunctionFlags & FUNC_Event ) & & Function - > GetSuperFunction ( ) = = nullptr )
{
CallbackFunctions . Add ( Function ) ;
}
}
2015-03-27 18:10:52 -04:00
FUHTStringBuilder RPCWrappers ;
FUHTStringBuilder RPCWrappersCPP ;
2015-01-20 09:33:54 -05:00
if ( CallbackFunctions . Num ( ) = = 0 )
{
// Early out.
return CallbackFunctions ;
2014-03-14 14:13:41 -04:00
}
CallbackFunctions . Sort ( ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder UClassMacroContent ;
2015-01-20 09:33:54 -05:00
// export parameters structs for all events and delegates
2015-03-27 18:10:52 -04:00
ExportEventParms ( SourceFile . GetScope ( ) . Get ( ) , CallbackFunctions , UClassMacroContent , /*Indent=*/ 1 , /*bOutputConstructor=*/ true ) ;
2015-01-20 09:33:54 -05:00
FString MacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _EVENT_PARMS " ) ) ;
WriteMacro ( GeneratedHeaderText , MacroName , UClassMacroContent ) ;
2015-03-27 18:10:52 -04:00
PrologMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * MacroName ) ;
2015-01-20 09:33:54 -05:00
// export .proto files for any net service functions
2015-11-18 16:20:49 -05:00
ExportProtoMessage ( CallbackFunctions ) ;
2015-01-20 09:33:54 -05:00
// export .java files for any net service functions
ExportMCPMessage ( CallbackFunctions , ClassData ) ;
for ( int32 CallbackIndex = 0 ; CallbackIndex < CallbackFunctions . Num ( ) ; CallbackIndex + + )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
UFunction * Function = CallbackFunctions [ CallbackIndex ] ;
2014-03-14 14:13:41 -04:00
// Never expecting to export delegate functions this way
2015-01-20 09:33:54 -05:00
check ( ! Function - > HasAnyFunctionFlags ( FUNC_Delegate ) ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
auto * CompilerInfo = FFunctionData : : FindForFunction ( Function ) ;
2014-03-14 14:13:41 -04:00
// cache the TCHAR* for a few strings we'll use a lot here
FString FunctionName = Function - > GetName ( ) ;
2015-01-20 09:33:54 -05:00
GeneratedHeaderText . Logf ( TEXT ( " extern %s FName %s_%s; " ) LINE_TERMINATOR , * GetAPIString ( ) , * API , * FunctionName ) ;
ReferencedNames . Add ( Function - > GetFName ( ) ) ;
2014-03-14 14:13:41 -04:00
const FFuncInfo & FunctionData = CompilerInfo - > GetFunctionData ( ) ;
if ( FunctionData . FunctionFlags & FUNC_NetResponse )
{
// Net response functions don't go into the VM
continue ;
}
const bool bWillBeProgrammerTyped = Function - > GetName ( ) = = FunctionData . MarshallAndCallName ;
// Emit the declaration if the programmer isn't responsible for declaring this wrapper
if ( ! bWillBeProgrammerTyped )
{
// export the line that looks like: int32 Main(const FString& Parms)
ExportNativeFunctionHeader ( FunctionData , RPCWrappers , EExportFunctionType : : Event , EExportFunctionHeaderStyle : : Declaration ) ;
RPCWrappers . Log ( TEXT ( " ; \r \n " ) ) ;
if ( bMultiLineUFUNCTION )
{
RPCWrappers . Log ( TEXT ( " \r \n " ) ) ;
}
}
// Emit the thunk implementation
ExportNativeFunctionHeader ( FunctionData , RPCWrappersCPP , EExportFunctionType : : Event , EExportFunctionHeaderStyle : : Definition ) ;
auto Parameters = GetFunctionParmsAndReturn ( FunctionData . FunctionReference ) ;
2015-01-20 09:33:54 -05:00
if ( ! ( Class - > ClassFlags & CLASS_Interface ) )
2014-03-14 14:13:41 -04:00
{
2015-03-27 18:10:52 -04:00
WriteEventFunctionPrologue ( RPCWrappersCPP , /*Indent=*/ 1 , Parameters , Function - > GetOuter ( ) , * FunctionName ) ;
2015-01-20 09:33:54 -05:00
{
// Cast away const just in case, because ProcessEvent isn't const
RPCWrappersCPP . Logf (
2015-03-27 18:10:52 -04:00
TEXT ( " \t \t %sProcessEvent(FindFunctionChecked(%s_%s),%s); \r \n " ) ,
2015-01-20 09:33:54 -05:00
( Function - > HasAllFunctionFlags ( FUNC_Const ) ) ? * FString : : Printf ( TEXT ( " const_cast<%s*>(this)-> " ) , NameLookupCPP . GetNameCPP ( Cast < UClass > ( Function - > GetOuter ( ) ) ) ) : TEXT ( " " ) ,
* API ,
* FunctionName ,
Parameters . HasParms ( ) ? TEXT ( " &Parms " ) : TEXT ( " NULL " )
) ;
}
2015-03-27 18:10:52 -04:00
WriteEventFunctionEpilogue ( RPCWrappersCPP , /*Indent=*/ 1 , Parameters , * FunctionName ) ;
2015-01-20 09:33:54 -05:00
}
else
{
2015-03-27 18:10:52 -04:00
RPCWrappersCPP + = LINE_TERMINATOR ;
RPCWrappersCPP + = TEXT ( " \t { " ) LINE_TERMINATOR ;
2015-01-20 09:33:54 -05:00
// assert if this is ever called directly
2015-03-27 18:10:52 -04:00
RPCWrappersCPP . Logf ( TEXT ( " \t \t check(0 && \" Do not directly call Event functions in Interfaces. Call Execute_%s instead. \" ); " ) LINE_TERMINATOR , * FunctionName ) ;
2015-01-20 09:33:54 -05:00
// satisfy compiler if it's expecting a return value
if ( Parameters . Return )
{
FString EventParmStructName = GetEventStructParamsName ( Function - > GetOuter ( ) , * FunctionName ) ;
2015-03-27 18:10:52 -04:00
RPCWrappersCPP . Logf ( TEXT ( " \t \t %s Parms; " ) LINE_TERMINATOR , * EventParmStructName ) ;
RPCWrappersCPP . Logf ( TEXT ( " \t \t return Parms.ReturnValue; " ) LINE_TERMINATOR ) ;
2015-01-20 09:33:54 -05:00
}
2015-03-27 18:10:52 -04:00
RPCWrappersCPP + = TEXT ( " \t } " ) LINE_TERMINATOR ;
2014-03-14 14:13:41 -04:00
}
}
2015-01-20 09:33:54 -05:00
if ( ! Class - > HasAnyClassFlags ( CLASS_NoExport ) )
2014-03-14 14:13:41 -04:00
{
GeneratedPackageCPP . Log ( * RPCWrappersCPP ) ;
}
// else drop the implementation on the floor
2015-01-20 09:33:54 -05:00
FString CallbackWrappersMacroName = SourceFile . GetGeneratedMacroName ( ClassData , TEXT ( " _CALLBACK_WRAPPERS " ) ) ;
WriteMacro ( GeneratedHeaderText , CallbackWrappersMacroName , RPCWrappers ) ;
2015-03-27 18:10:52 -04:00
InClassMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * CallbackWrappersMacroName ) ;
InClassNoPureDeclsMacroCalls . Logf ( TEXT ( " \t %s \r \n " ) , * CallbackWrappersMacroName ) ;
2015-01-20 09:33:54 -05:00
return CallbackFunctions ;
2014-03-14 14:13:41 -04:00
}
/**
* Determines if the property has alternate export text associated with it and if so replaces the text in PropertyText with the
* alternate version . ( for example , structs or properties that specify a native type using export - text ) . Should be called immediately
* after ExportCppDeclaration ( )
*
* @ param Prop the property that is being exported
* @ param PropertyText the string containing the text exported from ExportCppDeclaration
*/
2015-03-27 18:10:52 -04:00
void FNativeClassHeaderGenerator : : ApplyAlternatePropertyExportText ( UProperty * Prop , FUHTStringBuilder & PropertyText )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
if ( ! bIsExportingForOffsetDeterminationOnly )
2014-03-14 14:13:41 -04:00
{
return ;
}
2015-01-20 09:33:54 -05:00
UDelegateProperty * DelegateProperty = Cast < UDelegateProperty > ( Prop ) ;
UMulticastDelegateProperty * MulticastDelegateProperty = Cast < UMulticastDelegateProperty > ( Prop ) ;
if ( DelegateProperty | | MulticastDelegateProperty )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
FString Original = Prop - > GetCPPType ( ) ;
FString PlaceholderOfSameSizeAndAlignemnt ;
if ( DelegateProperty )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
PlaceholderOfSameSizeAndAlignemnt = TEXT ( " FScriptDelegate " ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
else
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
PlaceholderOfSameSizeAndAlignemnt = TEXT ( " FMulticastScriptDelegate " ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
PropertyText . ReplaceInline ( * Original , * PlaceholderOfSameSizeAndAlignemnt , ESearchCase : : CaseSensitive ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-04-23 20:18:11 -04:00
/**
* Sorts the list of header files being exported from a package according to their dependency on each other .
*
* @ param HeaderDependencyMap a mapping of header filenames to a list of header filenames that must be processed before that one .
* @ param SortedHeaderFilenames [ out ] receives the sorted list of header filenames .
*/
bool FNativeClassHeaderGenerator : : SortHeaderDependencyMap ( const TMap < const FString * , HeaderDependents > & HeaderDependencyMap , TArray < const FString * > & SortedHeaderFilenames ) const
{
SortedHeaderFilenames . Empty ( HeaderDependencyMap . Num ( ) ) ;
while ( SortedHeaderFilenames . Num ( ) < HeaderDependencyMap . Num ( ) )
{
bool bAddedSomething = false ;
// Find headers with no dependencies and add those to the list.
for ( auto It = HeaderDependencyMap . CreateConstIterator ( ) ; It ; + + It )
{
auto Header = It - > Key ;
if ( SortedHeaderFilenames . Contains ( Header ) )
continue ;
bool bHasRemainingDependencies = false ;
for ( auto It2 = It - > Value . CreateConstIterator ( ) ; It2 ; + + It2 )
{
if ( ! SortedHeaderFilenames . Contains ( * It2 ) )
{
bHasRemainingDependencies = true ;
break ;
}
}
if ( ! bHasRemainingDependencies )
{
// Add it to the list.
SortedHeaderFilenames . AddUnique ( Header ) ;
bAddedSomething = true ;
}
}
// Circular dependency error?
if ( ! bAddedSomething )
return false ;
}
return true ;
}
2014-03-14 14:13:41 -04:00
bool FNativeClassHeaderGenerator : : FindInterDependency ( TMap < const FString * , HeaderDependents > & HeaderDependencyMap , const FString * Header , const FString * & OutHeader1 , const FString * & OutHeader2 )
{
TSet < const FString * > VisitedHeaders ;
return FindInterDependencyRecursive ( HeaderDependencyMap , Header , VisitedHeaders , OutHeader1 , OutHeader2 ) ;
}
/**
* Finds to headers that are dependent on each other .
*
* @ param HeaderDependencyMap A map of headers and their dependencies . Each header is represented as an index into a TArray of the actual filename strings .
* @ param HeaderIndex A header to scan for any inter - dependency .
* @ param VisitedHeaders Must be filled with false values before the first call ( must be large enough to be indexed by all headers ) .
* @ param OutHeader1 [ out ] Receives the first inter - dependent header index .
* @ param OutHeader2 [ out ] Receives the second inter - dependent header index .
* @ return true if an inter - dependency was found .
*/
bool FNativeClassHeaderGenerator : : FindInterDependencyRecursive ( TMap < const FString * , HeaderDependents > & HeaderDependencyMap , const FString * Header , TSet < const FString * > & VisitedHeaders , const FString * & OutHeader1 , const FString * & OutHeader2 )
{
VisitedHeaders . Add ( Header ) ;
for ( auto It = HeaderDependencyMap [ Header ] . CreateConstIterator ( ) ; It ; + + It )
{
auto DependentHeader = * It ;
if ( VisitedHeaders . Contains ( DependentHeader ) )
{
OutHeader1 = Header ;
OutHeader2 = DependentHeader ;
return true ;
}
if ( FindInterDependencyRecursive ( HeaderDependencyMap , DependentHeader , VisitedHeaders , OutHeader1 , OutHeader2 ) )
{
return true ;
}
}
return false ;
}
2015-01-20 09:33:54 -05:00
bool IsExportClass ( FClass * Class )
2014-04-23 20:18:11 -04:00
{
2015-01-20 09:33:54 -05:00
return Class - > HasAnyClassFlags ( CLASS_Native ) & & ! Class - > HasAnyClassFlags ( CLASS_NoExport | CLASS_Intrinsic ) ;
2014-04-23 20:18:11 -04:00
}
2015-03-27 18:10:52 -04:00
FUHTStringBuilder & FNativeClassHeaderGenerator : : GetGeneratedFunctionTextDevice ( )
2015-01-16 05:02:48 -05:00
{
2015-09-04 03:35:53 -04:00
static struct FMaxLinesPerCpp
{
int32 Value ;
FMaxLinesPerCpp ( )
{
Miscellaneous fixes for Clang on windows
These changes allow UE4 to compile and run (in Debug) on Clang 3.7 alpha (r231657 only!)
- Disabled editor source file discovery (crashes with Clang currently)
- Disabled FThreadIdleStats in UnrealHeaderTool with Clang on Windows (causes link errors due to inlining bugs with Clang and DLL imports)
- Use MSVC linker by default, even when compiling with Clang (can be tweaked with bAllowClangLinker)
- Enabled shadow variable warnings on Windows with Clang
- Limited max size of reflection code source files (Clang on Windows crashes with huge source files)
- Fixed UE4 deprecation warnings not showing up when using Clang on Windows
- Make sure initialization list order only triggers a warning on Clang for Windows
Other changes:
- Fixed issues with pushed pragmas not getting popped (PRAGMA_ENABLE_DEPRECATION_WARNINGS)
- Removed EMIT_DEPRECATED_WARNING_MESSAGE, wasn't used
- Fixed various third party library includes not being treated as system headers (prevents compiler warnings)
To test Clang on Windows (beta!!):
- Get latest UE4 main branch (4.9)
- Install LLVM+Clang for Windows version r231657. It's a quick install, you don't need to compile anything yourself.
- Open UEBuildWindows.cs, and change bCompileWithClang to true. Be careful not to check that in. We'll probably make this config-driven later, after the Clang toolchain gets more mature.
- Switch to Debug Editor configuration. (See below for more info.)
- Rebuild the game or engine
Notes:
- You must use Clang r231657 (3.7.0 alpha). There are no other releases that I've found that are able to compile UE4 successfully. Most of the newer releases crash during compiling, and older releases aren't able to digest Windows header files well enough.
- Compiling in Development currently will not work due to bugs with Clangs handling of inlining and DLL exports. Monolithic builds should work, though.
- Occasionally you may see runtime crashes (stack overflows or access violations) when running UE4 compiled with Clang on Windows. These may very well be bugs in Clang (remember, we're using an alpha release of Clang 3.7.0.) Unfortunately without better debugger support, it can be difficult to workaround these
- When debugging, you will only have functions and line numbers, no variables or parameters. Clang only has preliminary support for Microsoft's PDB format currently.
XGE is fully supported with Clang on Windows. Best case rebuild times I've seen are 3.5 minutes in Debug.
- Shared PCHs aren't supported yet (similar to on Mac and Linux), so iterative compile times may be slower compared to Visual C++. However the Clang compiler is actually quite fast for rebuilds, probably because of missing debug info though.
- There may be some compiler warnings that are different between Mac/Linux and Windows. We haven't done a line-by-line comparison yet.
- Build products and executables for Clang and VC++ overlap on disk. So you have to rebuild to switch back and forth. Sorry.
- Clang on Windows has a few bugs that we've had to work around. You might see some strange things from time to time. Every new release of Clang has different behavior on Windows.
- We still use the VC++ Linker, even when compiling using Clang. The new Clang linker (lld.exe) can be enabled with bAllowClangLinker but it will crash when linking some modules. It also doesn't produce usable debug symbols by Visual Studio (yet).
#codereview mikolaj.sieluzycki
[CL 2532260 by Mike Fricker in Main branch]
2015-04-30 14:24:21 -04:00
# if ( PLATFORM_WINDOWS && defined(__clang__) ) // @todo clang: Clang r231657 often crashes with huge Engine.generated.cpp files, so we split using a smaller threshold
2015-09-04 03:35:53 -04:00
Value = 15000 ;
Miscellaneous fixes for Clang on windows
These changes allow UE4 to compile and run (in Debug) on Clang 3.7 alpha (r231657 only!)
- Disabled editor source file discovery (crashes with Clang currently)
- Disabled FThreadIdleStats in UnrealHeaderTool with Clang on Windows (causes link errors due to inlining bugs with Clang and DLL imports)
- Use MSVC linker by default, even when compiling with Clang (can be tweaked with bAllowClangLinker)
- Enabled shadow variable warnings on Windows with Clang
- Limited max size of reflection code source files (Clang on Windows crashes with huge source files)
- Fixed UE4 deprecation warnings not showing up when using Clang on Windows
- Make sure initialization list order only triggers a warning on Clang for Windows
Other changes:
- Fixed issues with pushed pragmas not getting popped (PRAGMA_ENABLE_DEPRECATION_WARNINGS)
- Removed EMIT_DEPRECATED_WARNING_MESSAGE, wasn't used
- Fixed various third party library includes not being treated as system headers (prevents compiler warnings)
To test Clang on Windows (beta!!):
- Get latest UE4 main branch (4.9)
- Install LLVM+Clang for Windows version r231657. It's a quick install, you don't need to compile anything yourself.
- Open UEBuildWindows.cs, and change bCompileWithClang to true. Be careful not to check that in. We'll probably make this config-driven later, after the Clang toolchain gets more mature.
- Switch to Debug Editor configuration. (See below for more info.)
- Rebuild the game or engine
Notes:
- You must use Clang r231657 (3.7.0 alpha). There are no other releases that I've found that are able to compile UE4 successfully. Most of the newer releases crash during compiling, and older releases aren't able to digest Windows header files well enough.
- Compiling in Development currently will not work due to bugs with Clangs handling of inlining and DLL exports. Monolithic builds should work, though.
- Occasionally you may see runtime crashes (stack overflows or access violations) when running UE4 compiled with Clang on Windows. These may very well be bugs in Clang (remember, we're using an alpha release of Clang 3.7.0.) Unfortunately without better debugger support, it can be difficult to workaround these
- When debugging, you will only have functions and line numbers, no variables or parameters. Clang only has preliminary support for Microsoft's PDB format currently.
XGE is fully supported with Clang on Windows. Best case rebuild times I've seen are 3.5 minutes in Debug.
- Shared PCHs aren't supported yet (similar to on Mac and Linux), so iterative compile times may be slower compared to Visual C++. However the Clang compiler is actually quite fast for rebuilds, probably because of missing debug info though.
- There may be some compiler warnings that are different between Mac/Linux and Windows. We haven't done a line-by-line comparison yet.
- Build products and executables for Clang and VC++ overlap on disk. So you have to rebuild to switch back and forth. Sorry.
- Clang on Windows has a few bugs that we've had to work around. You might see some strange things from time to time. Every new release of Clang has different behavior on Windows.
- We still use the VC++ Linker, even when compiling using Clang. The new Clang linker (lld.exe) can be enabled with bAllowClangLinker but it will crash when linking some modules. It also doesn't produce usable debug symbols by Visual Studio (yet).
#codereview mikolaj.sieluzycki
[CL 2532260 by Mike Fricker in Main branch]
2015-04-30 14:24:21 -04:00
# else
2015-09-04 03:35:53 -04:00
// We do this only for non-clang builds for now
Value = 30000 ;
check ( GConfig ) ;
GConfig - > GetInt ( TEXT ( " UnrealHeaderTool " ) , TEXT ( " MaxLinesPerCpp " ) , Value , GEngineIni ) ;
Miscellaneous fixes for Clang on windows
These changes allow UE4 to compile and run (in Debug) on Clang 3.7 alpha (r231657 only!)
- Disabled editor source file discovery (crashes with Clang currently)
- Disabled FThreadIdleStats in UnrealHeaderTool with Clang on Windows (causes link errors due to inlining bugs with Clang and DLL imports)
- Use MSVC linker by default, even when compiling with Clang (can be tweaked with bAllowClangLinker)
- Enabled shadow variable warnings on Windows with Clang
- Limited max size of reflection code source files (Clang on Windows crashes with huge source files)
- Fixed UE4 deprecation warnings not showing up when using Clang on Windows
- Make sure initialization list order only triggers a warning on Clang for Windows
Other changes:
- Fixed issues with pushed pragmas not getting popped (PRAGMA_ENABLE_DEPRECATION_WARNINGS)
- Removed EMIT_DEPRECATED_WARNING_MESSAGE, wasn't used
- Fixed various third party library includes not being treated as system headers (prevents compiler warnings)
To test Clang on Windows (beta!!):
- Get latest UE4 main branch (4.9)
- Install LLVM+Clang for Windows version r231657. It's a quick install, you don't need to compile anything yourself.
- Open UEBuildWindows.cs, and change bCompileWithClang to true. Be careful not to check that in. We'll probably make this config-driven later, after the Clang toolchain gets more mature.
- Switch to Debug Editor configuration. (See below for more info.)
- Rebuild the game or engine
Notes:
- You must use Clang r231657 (3.7.0 alpha). There are no other releases that I've found that are able to compile UE4 successfully. Most of the newer releases crash during compiling, and older releases aren't able to digest Windows header files well enough.
- Compiling in Development currently will not work due to bugs with Clangs handling of inlining and DLL exports. Monolithic builds should work, though.
- Occasionally you may see runtime crashes (stack overflows or access violations) when running UE4 compiled with Clang on Windows. These may very well be bugs in Clang (remember, we're using an alpha release of Clang 3.7.0.) Unfortunately without better debugger support, it can be difficult to workaround these
- When debugging, you will only have functions and line numbers, no variables or parameters. Clang only has preliminary support for Microsoft's PDB format currently.
XGE is fully supported with Clang on Windows. Best case rebuild times I've seen are 3.5 minutes in Debug.
- Shared PCHs aren't supported yet (similar to on Mac and Linux), so iterative compile times may be slower compared to Visual C++. However the Clang compiler is actually quite fast for rebuilds, probably because of missing debug info though.
- There may be some compiler warnings that are different between Mac/Linux and Windows. We haven't done a line-by-line comparison yet.
- Build products and executables for Clang and VC++ overlap on disk. So you have to rebuild to switch back and forth. Sorry.
- Clang on Windows has a few bugs that we've had to work around. You might see some strange things from time to time. Every new release of Clang has different behavior on Windows.
- We still use the VC++ Linker, even when compiling using Clang. The new Clang linker (lld.exe) can be enabled with bAllowClangLinker but it will crash when linking some modules. It also doesn't produce usable debug symbols by Visual Studio (yet).
#codereview mikolaj.sieluzycki
[CL 2532260 by Mike Fricker in Main branch]
2015-04-30 14:24:21 -04:00
# endif
2015-09-04 03:35:53 -04:00
}
} MaxLinesPerCpp ;
2015-01-16 05:02:48 -05:00
2015-09-04 03:35:53 -04:00
if ( ( GeneratedFunctionBodyTextSplit . Num ( ) = = 0 ) | | ( GeneratedFunctionBodyTextSplit [ GeneratedFunctionBodyTextSplit . Num ( ) - 1 ] - > GetLineCount ( ) > MaxLinesPerCpp . Value ) )
2015-01-16 05:02:48 -05:00
{
2015-04-14 08:03:34 -04:00
GeneratedFunctionBodyTextSplit . Add ( TUniqueObj < FUHTStringBuilderLineCounter > ( ) ) ;
2015-01-16 05:02:48 -05:00
}
2015-04-14 08:03:34 -04:00
return GeneratedFunctionBodyTextSplit [ GeneratedFunctionBodyTextSplit . Num ( ) - 1 ] . Get ( ) ;
2015-01-16 05:02:48 -05:00
}
2014-03-14 14:13:41 -04:00
// Constructor.
2015-03-02 06:44:04 -05:00
FNativeClassHeaderGenerator : : FNativeClassHeaderGenerator (
2015-11-18 16:20:49 -05:00
const UPackage * InPackage ,
2015-03-02 06:44:04 -05:00
const TArray < FUnrealSourceFile * > & SourceFiles ,
FClasses & AllClasses ,
bool InAllowSaveExportedHeaders
# if WITH_HOT_RELOAD_CTORS
2015-04-22 14:15:56 -04:00
, bool bInExportVTableConstructors
2015-03-02 06:44:04 -05:00
# endif // WITH_HOT_RELOAD_CTORS
2015-11-18 16:20:49 -05:00
, FUHTMakefile & InUHTMakefile
2015-03-02 06:44:04 -05:00
)
2015-01-20 09:33:54 -05:00
: API ( FPackageName : : GetShortName ( InPackage ) . ToUpper ( ) )
2014-03-14 14:13:41 -04:00
, Package ( InPackage )
, bIsExportingForOffsetDeterminationOnly ( false )
, bAllowSaveExportedHeaders ( InAllowSaveExportedHeaders )
, bFailIfGeneratedCodeChanges ( false )
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
2015-04-22 14:15:56 -04:00
, bExportVTableConstructors ( bInExportVTableConstructors )
2015-03-02 06:44:04 -05:00
# endif // WITH_HOT_RELOAD_CTORS
2015-11-18 16:20:49 -05:00
, UHTMakefile ( InUHTMakefile )
2014-03-14 14:13:41 -04:00
{
const FString PackageName = FPackageName : : GetShortName ( Package ) ;
2014-04-23 20:18:11 -04:00
2014-03-14 14:13:41 -04:00
GeneratedCPPFilenameBase = PackageName + TEXT ( " .generated " ) ;
GeneratedProtoFilenameBase = PackageName + TEXT ( " .generated " ) ;
GeneratedMCPFilenameBase = PackageName + TEXT ( " .generated " ) ;
bFailIfGeneratedCodeChanges = FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " FailIfGeneratedCodeChanges " ) ) ;
2015-01-20 09:33:54 -05:00
bool bPackageHasAnyExportClasses = AllClasses . GetClassesInPackage ( Package ) . ContainsByPredicate ( IsExportClass ) ;
2014-03-14 14:13:41 -04:00
bool bHasNamesForExport = false ;
2015-03-27 18:10:52 -04:00
TempHeaderPaths . Reset ( ) ;
PackageHeaderPaths . Reset ( ) ;
2014-04-23 20:18:55 -04:00
2014-03-14 14:13:41 -04:00
// Reset header generation output strings
2015-03-27 18:10:52 -04:00
GeneratedPackageCPP . Reset ( ) ;
GeneratedProtoText . Reset ( ) ;
GeneratedMCPText . Reset ( ) ;
CrossModuleGeneratedFunctionDeclarations . Reset ( ) ;
UniqueCrossModuleReferences . Empty ( UniqueCrossModuleReferences . Num ( ) ) ;
GeneratedFunctionDeclarations . Reset ( ) ;
GeneratedFunctionBodyTextSplit . Reset ( ) ;
ListOfPublicClassesUObjectHeaderModuleIncludes . Reset ( ) ;
2014-04-23 20:18:55 -04:00
2015-01-20 09:33:54 -05:00
if ( bPackageHasAnyExportClasses )
2014-03-14 14:13:41 -04:00
{
FString PkgDir ;
FString GeneratedIncludeDirectory ;
2014-09-18 04:05:01 -04:00
if ( FindPackageLocation ( * PackageName , PkgDir , GeneratedIncludeDirectory ) = = false )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Error , TEXT ( " Failed to find path for package %s " ) , * PackageName ) ;
}
2014-04-28 05:03:10 -04:00
FString ClassesHeaderName = PackageName + TEXT ( " Classes.h " ) ;
2014-04-23 20:18:55 -04:00
ClassesHeaderPath = GeneratedIncludeDirectory / ClassesHeaderName ;
2014-03-14 14:13:41 -04:00
int32 ClassCount = 0 ;
2015-01-20 09:33:54 -05:00
for ( auto * SourceFile : SourceFiles )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
for ( auto * Class : SourceFile - > GetDefinedClasses ( ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
if ( Class - > HasAnyClassFlags ( CLASS_Native ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
if ( GTypeDefinitionInfoMap . Contains ( Class ) & & ! Class - > HasAnyClassFlags ( CLASS_NoExport ) )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
ClassCount + + ;
2014-03-14 14:13:41 -04:00
Class - > UnMark ( OBJECTMARK_TagImp ) ;
Class - > Mark ( OBJECTMARK_TagExp ) ;
}
}
2015-01-20 09:33:54 -05:00
else
{
Class - > UnMark ( EObjectMark ( OBJECTMARK_TagImp | OBJECTMARK_TagExp ) ) ;
}
2014-03-14 14:13:41 -04:00
}
}
2014-04-28 05:03:10 -04:00
if ( ClassCount ! = 0 )
2014-03-14 14:13:41 -04:00
{
2014-04-28 05:03:10 -04:00
ClassesHeaders . Add ( ClassesHeaderName ) ;
2014-04-23 20:18:11 -04:00
2015-03-27 18:10:52 -04:00
ListOfPublicHeaderGroupIncludes . Reset ( ) ;
ListOfAllUObjectHeaderIncludes . Reset ( ) ;
OriginalHeader . Reset ( ) ;
PreHeaderText . Reset ( ) ;
2014-04-23 20:18:55 -04:00
2014-04-28 05:03:10 -04:00
// Load the original header file into memory
FFileHelper : : LoadFileToString ( OriginalHeader , * ClassesHeaderPath ) ;
2014-04-23 20:18:11 -04:00
2014-04-28 05:03:10 -04:00
// Write the classes and enums header prefixes.
2014-04-23 20:18:11 -04:00
2014-04-28 05:03:10 -04:00
PreHeaderText . Logf (
2014-12-07 19:09:38 -05:00
TEXT ( " // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. \r \n " )
2014-04-28 05:03:10 -04:00
TEXT ( " /*=========================================================================== \r \n " )
2015-09-21 07:53:49 -04:00
TEXT ( " \t C++ class boilerplate exported from UnrealHeaderTool. \r \n " )
TEXT ( " \t This is automatically generated by the tools. \r \n " )
TEXT ( " \t DO NOT modify this manually! Edit the corresponding .h files instead! \r \n " )
2014-04-28 05:03:10 -04:00
TEXT ( " ===========================================================================*/ \r \n " )
TEXT ( " #pragma once \r \n " )
TEXT ( " \r \n " )
) ;
2014-04-23 20:18:11 -04:00
2014-04-28 05:03:10 -04:00
// if a global auto-include file exists, generate a line to have that file included
FString GlobalAutoIncludeFilename = PackageName + TEXT ( " GlobalIncludes.h " ) ;
const FString StandardHeaderFileLocation = PkgDir / TEXT ( " Public " ) ;
if ( IFileManager : : Get ( ) . FileSize ( * ( StandardHeaderFileLocation / GlobalAutoIncludeFilename ) ) > 0 )
2014-04-23 20:18:11 -04:00
{
2014-04-28 05:03:10 -04:00
PreHeaderText . Logf ( TEXT ( " #include \" %s \" \r \n \r \n " ) , * GlobalAutoIncludeFilename ) ;
2014-04-23 20:18:11 -04:00
}
2014-04-28 05:03:10 -04:00
// Export an include line for each header
2015-01-20 09:33:54 -05:00
for ( auto * SourceFile : SourceFiles )
2014-04-28 05:03:10 -04:00
{
2015-01-20 09:33:54 -05:00
ExportSourceFileHeader ( AllClasses , SourceFile ) ;
2014-04-28 05:03:10 -04:00
}
// build the full header file out of its pieces
const FString FullClassesHeader = FString : : Printf (
TEXT ( " %s \r \n %s " ) ,
* PreHeaderText ,
2015-01-20 09:33:54 -05:00
* GetListOfPublicHeaderGroupIncludesString ( InPackage )
2014-04-28 05:03:10 -04:00
) ;
// Save the classes header if it has changed.
SaveHeaderIfChanged ( * ClassesHeaderPath , * FullClassesHeader ) ;
}
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
if ( ! bPackageHasAnyExportClasses )
2014-03-14 14:13:41 -04:00
{
// If no headers are generated, check if there's any no export classes that need to have the inl file generated.
2015-01-20 09:33:54 -05:00
for ( auto * SourceFile : SourceFiles )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
ExportSourceFileHeader ( AllClasses , SourceFile ) ;
2014-03-14 14:13:41 -04:00
}
}
// now export the names for the functions in this package
// notice we always export this file (as opposed to only exporting if we have any marked names)
// because there would be no way to know when the file was created otherwise
2014-04-28 05:03:10 -04:00
// Export .generated.cpp
ExportGeneratedCPP ( ) ;
2014-03-14 14:13:41 -04:00
ExportGeneratedProto ( ) ;
ExportGeneratedMCP ( ) ;
// Export all changed headers from their temp files to the .h files
ExportUpdatedHeaders ( PackageName ) ;
// Delete stale *.generated.h files
DeleteUnusedGeneratedHeaders ( ) ;
}
void FNativeClassHeaderGenerator : : DeleteUnusedGeneratedHeaders ( )
{
TArray < FString > AllIntermediateFolders ;
2014-04-23 20:18:55 -04:00
for ( const auto & PackageHeader : PackageHeaderPaths )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
const FString IntermediatePath = FPaths : : GetPath ( PackageHeader ) ;
2014-03-14 14:13:41 -04:00
if ( AllIntermediateFolders . Contains ( IntermediatePath ) )
continue ;
AllIntermediateFolders . Add ( IntermediatePath ) ;
TArray < FString > AllHeaders ;
IFileManager : : Get ( ) . FindFiles ( AllHeaders , * ( IntermediatePath / TEXT ( " *.generated.h " ) ) , true , false ) ;
2014-04-23 20:18:55 -04:00
for ( const auto & Header : AllHeaders )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
const FString HeaderPath = IntermediatePath / Header ;
2014-03-14 14:13:41 -04:00
if ( PackageHeaderPaths . Contains ( HeaderPath ) )
continue ;
// Check intrinsic classes. Get the class name from file name by removing .generated.h.
const FString HeaderFilename = FPaths : : GetBaseFilename ( HeaderPath ) ;
const int32 GeneratedIndex = HeaderFilename . Find ( TEXT ( " .generated " ) , ESearchCase : : IgnoreCase , ESearchDir : : FromEnd ) ;
const FString ClassName = HeaderFilename . Mid ( 0 , GeneratedIndex ) ;
UClass * IntrinsicClass = FindObject < UClass > ( ANY_PACKAGE , * ClassName ) ;
if ( ! IntrinsicClass | | ! IntrinsicClass - > HasAnyClassFlags ( CLASS_Intrinsic ) )
{
IFileManager : : Get ( ) . Delete ( * HeaderPath ) ;
}
}
}
}
2014-04-23 18:36:17 -04:00
/**
* Dirty hack global variable to allow different result codes passed through
* exceptions . Needs to be fixed in future versions of UHT .
*/
ECompilationResult : : Type GCompilationResult = ECompilationResult : : OtherCompilationError ;
2014-03-14 14:13:41 -04:00
bool FNativeClassHeaderGenerator : : SaveHeaderIfChanged ( const TCHAR * HeaderPath , const TCHAR * InNewHeaderContents )
{
if ( ! bAllowSaveExportedHeaders )
{
// Return false indicating that the header did not need updating
return false ;
}
2015-09-21 07:53:49 -04:00
const TCHAR * NewHeaderContents = InNewHeaderContents ;
2014-03-14 14:13:41 -04:00
static bool bTestedCmdLine = false ;
if ( ! bTestedCmdLine )
{
bTestedCmdLine = true ;
2015-03-27 17:16:51 -04:00
const FString ReferenceGeneratedCodePath = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " ReferenceGeneratedCode/ " ) ;
const FString VerifyGeneratedCodePath = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " VerifyGeneratedCode/ " ) ;
if ( FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " WRITEREF " ) ) )
2014-03-14 14:13:41 -04:00
{
bWriteContents = true ;
2015-03-27 17:16:51 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " ********************************* Writing reference generated code to %s. " ) , * ReferenceGeneratedCodePath ) ;
2014-03-14 14:13:41 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " ********************************* Deleting all files in ReferenceGeneratedCode. " ) ) ;
2015-03-27 17:16:51 -04:00
IFileManager : : Get ( ) . DeleteDirectory ( * ReferenceGeneratedCodePath , false , true ) ;
IFileManager : : Get ( ) . MakeDirectory ( * ReferenceGeneratedCodePath ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 17:16:51 -04:00
else if ( FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " VERIFYREF " ) ) )
2014-03-14 14:13:41 -04:00
{
bVerifyContents = true ;
2015-03-27 17:16:51 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " ********************************* Writing generated code to %s and comparing to %s " ) , * VerifyGeneratedCodePath , * ReferenceGeneratedCodePath ) ;
2014-03-14 14:13:41 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " ********************************* Deleting all files in VerifyGeneratedCode. " ) ) ;
2015-03-27 17:16:51 -04:00
IFileManager : : Get ( ) . DeleteDirectory ( * VerifyGeneratedCodePath , false , true ) ;
IFileManager : : Get ( ) . MakeDirectory ( * VerifyGeneratedCodePath ) ;
2014-03-14 14:13:41 -04:00
}
}
if ( bWriteContents | | bVerifyContents )
{
2014-04-23 20:18:55 -04:00
FString Ref = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " ReferenceGeneratedCode " ) / FPaths : : GetCleanFilename ( HeaderPath ) ;
2014-03-14 14:13:41 -04:00
FString Verify = FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " VerifyGeneratedCode " ) / FPaths : : GetCleanFilename ( HeaderPath ) ;
if ( bWriteContents )
{
int32 i ;
for ( i = 0 ; i < 10 ; i + + )
{
if ( FFileHelper : : SaveStringToFile ( NewHeaderContents , * Ref ) )
{
break ;
}
FPlatformProcess : : Sleep ( 1.0f ) ; // I don't know why this fails after we delete the directory
}
check ( i < 10 ) ;
}
else
{
int32 i ;
for ( i = 0 ; i < 10 ; i + + )
{
if ( FFileHelper : : SaveStringToFile ( NewHeaderContents , * Verify ) )
{
break ;
}
FPlatformProcess : : Sleep ( 1.0f ) ; // I don't know why this fails after we delete the directory
}
check ( i < 10 ) ;
FString RefHeader ;
FString Message ;
if ( ! FFileHelper : : LoadFileToString ( RefHeader , * Ref ) )
{
Message = FString : : Printf ( TEXT ( " ********************************* %s appears to be a new generated file. " ) , * FPaths : : GetCleanFilename ( HeaderPath ) ) ;
}
else
{
if ( FCString : : Strcmp ( NewHeaderContents , * RefHeader ) ! = 0 )
{
Message = FString : : Printf ( TEXT ( " ********************************* %s has changed. " ) , * FPaths : : GetCleanFilename ( HeaderPath ) ) ;
}
}
if ( Message . Len ( ) )
{
UE_LOG ( LogCompile , Log , TEXT ( " %s " ) , * Message ) ;
ChangeMessages . AddUnique ( Message ) ;
}
}
}
FString OriginalHeaderLocal ;
FFileHelper : : LoadFileToString ( OriginalHeaderLocal , HeaderPath ) ;
const bool bHasChanged = OriginalHeaderLocal . Len ( ) = = 0 | | FCString : : Strcmp ( * OriginalHeaderLocal , NewHeaderContents ) ;
if ( bHasChanged )
{
if ( bFailIfGeneratedCodeChanges )
{
FString ConflictPath = FString ( HeaderPath ) + TEXT ( " .conflict " ) ;
FFileHelper : : SaveStringToFile ( NewHeaderContents , * ConflictPath ) ;
2014-04-23 18:36:17 -04:00
GCompilationResult = ECompilationResult : : FailedDueToHeaderChange ;
2014-03-14 14:13:41 -04:00
FError : : Throwf ( TEXT ( " ERROR: '%s': Changes to generated code are not allowed - conflicts written to '%s' " ) , HeaderPath , * ConflictPath ) ;
}
// save the updated version to a tmp file so that the user can see what will be changing
const FString TmpHeaderFilename = GenerateTempHeaderName ( HeaderPath , false ) ;
// delete any existing temp file
IFileManager : : Get ( ) . Delete ( * TmpHeaderFilename , false , true ) ;
if ( ! FFileHelper : : SaveStringToFile ( NewHeaderContents , * TmpHeaderFilename ) )
{
UE_LOG ( LogCompile , Warning , TEXT ( " Failed to save header export preview: '%s' " ) , * TmpHeaderFilename ) ;
}
TempHeaderPaths . Add ( TmpHeaderFilename ) ;
}
// Remember this header filename to be able to check for any old (unused) headers later.
2015-03-27 18:10:52 -04:00
PackageHeaderPaths . Add ( FString ( HeaderPath ) . Replace ( TEXT ( " \\ " ) , TEXT ( " / " ) , ESearchCase : : CaseSensitive ) ) ;
2014-03-14 14:13:41 -04:00
return bHasChanged ;
}
/**
* Create a temp header file name from the header name
*
* @ param CurrentFilename The filename off of which the current filename will be generated
* @ param bReverseOperation Get the header from the temp file name instead
*
* @ return The generated string
*/
FString FNativeClassHeaderGenerator : : GenerateTempHeaderName ( FString CurrentFilename , bool bReverseOperation )
{
return bReverseOperation
? CurrentFilename . Replace ( TEXT ( " .tmp " ) , TEXT ( " " ) )
: CurrentFilename + TEXT ( " .tmp " ) ;
}
/**
* Exports the temp header files into the . h files , then deletes the temp files .
*
* @ param PackageName Name of the package being saved
*/
void FNativeClassHeaderGenerator : : ExportUpdatedHeaders ( FString PackageName )
{
for ( auto It = TempHeaderPaths . CreateConstIterator ( ) ; It ; + + It )
{
const FString & TmpFilename = * It ;
FString Filename = GenerateTempHeaderName ( TmpFilename , true ) ;
if ( ! IFileManager : : Get ( ) . Move ( * Filename , * TmpFilename , true , true ) )
{
UE_LOG ( LogCompile , Error , TEXT ( " %s " ) , * FString : : Printf ( TEXT ( " Error exporting %s: couldn't write file '%s' " ) , * PackageName , * Filename ) ) ;
}
else
{
UE_LOG ( LogCompile , Log , TEXT ( " Exported updated C++ header: %s " ) , * Filename ) ;
}
}
}
/**
* Exports protobuffer definitions from boilerplate that was generated for a package .
* They are exported to a file using the name < PackageName > . generated . proto
*/
void FNativeClassHeaderGenerator : : ExportGeneratedProto ( )
{
if ( GeneratedProtoText . Len ( ) )
{
UE_LOG ( LogCompile , Log , TEXT ( " Autogenerating boilerplate proto: %s.proto " ) , * GeneratedProtoFilenameBase ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder ProtoPreamble ;
2014-03-14 14:13:41 -04:00
ProtoPreamble . Logf (
2014-12-07 19:09:38 -05:00
TEXT ( " // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. " ) LINE_TERMINATOR
2014-03-14 14:13:41 -04:00
TEXT ( " /*=========================================================================== " ) LINE_TERMINATOR
TEXT ( " Purpose: The file defines our Google Protocol Buffers which are used in over " ) LINE_TERMINATOR
TEXT ( " the wire messages between servers as well as between clients and servers. " ) LINE_TERMINATOR
TEXT ( " This is automatically generated by UnrealHeaderTool. " ) LINE_TERMINATOR
TEXT ( " DO NOT modify this manually! Edit the corresponding .h files instead! " ) LINE_TERMINATOR
TEXT ( " ===========================================================================*/ " ) LINE_TERMINATOR
LINE_TERMINATOR
TEXT ( " // We care more about speed than code size " ) LINE_TERMINATOR
TEXT ( " option optimize_for = SPEED; " ) LINE_TERMINATOR
TEXT ( " // We don't use the service generation functionality " ) LINE_TERMINATOR
TEXT ( " option cc_generic_services = false; " ) LINE_TERMINATOR
LINE_TERMINATOR
) ;
FString PkgName = FPackageName : : GetShortName ( Package ) ;
FString PkgDir ;
FString GeneratedIncludeDirectory ;
2014-09-18 04:05:01 -04:00
if ( FindPackageLocation ( * PkgName , PkgDir , GeneratedIncludeDirectory ) = = false )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Error , TEXT ( " Failed to find path for package %s " ) , * PkgName ) ;
}
FString HeaderPath = GeneratedIncludeDirectory / GeneratedProtoFilenameBase + TEXT ( " .proto " ) ;
SaveHeaderIfChanged ( * HeaderPath , * ( ProtoPreamble + GeneratedProtoText ) ) ;
}
}
/**
* Exports MCPbuffer definitions from boilerplate that was generated for a package .
* They are exported to a file using the name < PackageName > . generated . MCP
*/
void FNativeClassHeaderGenerator : : ExportGeneratedMCP ( )
{
if ( GeneratedMCPText . Len ( ) )
{
UE_LOG ( LogCompile , Log , TEXT ( " Autogenerating boilerplate MCP: %s.java " ) , * GeneratedMCPFilenameBase ) ;
2015-03-27 18:10:52 -04:00
FUHTStringBuilder MCPPreamble ;
2014-03-14 14:13:41 -04:00
MCPPreamble . Logf (
2014-12-07 19:09:38 -05:00
TEXT ( " // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. " ) LINE_TERMINATOR
2014-03-14 14:13:41 -04:00
TEXT ( " /*=========================================================================== " ) LINE_TERMINATOR
TEXT ( " Purpose: The file defines java heaers for MCP rpc messages. " ) LINE_TERMINATOR
TEXT ( " DO NOT modify this manually! Edit the corresponding .h files instead! " ) LINE_TERMINATOR
TEXT ( " ===========================================================================*/ " ) LINE_TERMINATOR
) ;
FString PkgName = FPackageName : : GetShortName ( Package ) ;
FString PkgDir ;
FString GeneratedIncludeDirectory ;
2014-09-18 04:05:01 -04:00
if ( FindPackageLocation ( * PkgName , PkgDir , GeneratedIncludeDirectory ) = = false )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Error , TEXT ( " Failed to find path for package %s " ) , * PkgName ) ;
}
FString HeaderPath = GeneratedIncludeDirectory / GeneratedMCPFilenameBase + TEXT ( " .java " ) ;
SaveHeaderIfChanged ( * HeaderPath , * ( MCPPreamble + GeneratedMCPText ) ) ;
}
}
/**
* Exports C + + definitions for boilerplate that was generated for a package .
2014-04-23 20:18:55 -04:00
* They are exported to a file using the name < PackageName > . generated . cpp
2014-03-14 14:13:41 -04:00
* @ param ReferencedNames list of function names to export .
*/
void FNativeClassHeaderGenerator : : ExportGeneratedCPP ( )
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder GeneratedCPPPreamble ;
FUHTStringBuilder GeneratedCPPClassesIncludes ;
FUHTStringBuilder GeneratedCPPEpilogue ;
FUHTStringBuilder GeneratedCPPText ;
FUHTStringBuilder GeneratedLinkerFixupFunction ;
2014-03-14 14:13:41 -04:00
2015-03-27 18:10:52 -04:00
TArray < FUHTStringBuilder > GeneratedCPPFiles ;
2014-03-14 14:13:41 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " Autogenerating boilerplate cpp: %s.cpp " ) , * GeneratedCPPFilenameBase ) ;
GeneratedCPPPreamble . Logf (
2014-12-07 19:09:38 -05:00
TEXT ( " // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. " ) LINE_TERMINATOR
2014-03-14 14:13:41 -04:00
TEXT ( " /*=========================================================================== " ) LINE_TERMINATOR
2015-09-21 07:53:49 -04:00
TEXT ( " \t Boilerplate C++ definitions for a single module. " ) LINE_TERMINATOR
TEXT ( " \t This is automatically generated by UnrealHeaderTool. " ) LINE_TERMINATOR
TEXT ( " \t DO NOT modify this manually! Edit the corresponding .h files instead! " ) LINE_TERMINATOR
2014-03-14 14:13:41 -04:00
TEXT ( " ===========================================================================*/ " ) LINE_TERMINATOR
LINE_TERMINATOR
) ;
2014-04-24 15:04:34 -04:00
FString ModulePCHInclude ;
2014-04-23 20:18:55 -04:00
const auto * ModuleInfo = GPackageToManifestModuleMap . FindChecked ( Package ) ;
if ( ModuleInfo - > PCH . Len ( ) )
{
2014-04-28 04:53:09 -04:00
FString PCH = ModuleInfo - > PCH ;
2014-05-19 06:57:00 -04:00
ConvertToBuildIncludePath ( Package , PCH ) ;
2014-04-28 04:53:09 -04:00
ModulePCHInclude = FString : : Printf ( TEXT ( " #include \" %s \" " ) LINE_TERMINATOR , * PCH ) ;
2014-04-23 20:18:55 -04:00
}
// Write out the ordered class dependencies into a single header that we can easily include
FString DepHeaderPathname = ModuleInfo - > GeneratedCPPFilenameBase + TEXT ( " .dep.h " ) ;
SaveHeaderIfChanged ( * DepHeaderPathname , * ( GeneratedCPPPreamble + ListOfPublicClassesUObjectHeaderModuleIncludes ) ) ;
// Write out our include to the .dep.h file
GeneratedCPPClassesIncludes . Logf ( TEXT ( " #include \" %s \" " ) LINE_TERMINATOR , * FPaths : : GetCleanFilename ( DepHeaderPathname ) ) ;
2014-03-14 14:13:41 -04:00
2014-06-12 08:08:47 -04:00
GeneratedLinkerFixupFunction . Logf ( TEXT ( " void EmptyLinkFunctionForGeneratedCode%s() {} " ) LINE_TERMINATOR , * ModuleInfo - > Name ) ;
2014-03-14 14:13:41 -04:00
GeneratedCPPText . Log ( * GeneratedPackageCPP ) ;
2015-04-10 06:02:22 -04:00
2014-03-14 14:13:41 -04:00
// Add all names marked for export to a list (for sorting)
TArray < FString > Names ;
for ( TSet < FName > : : TIterator It ( ReferencedNames ) ; It ; + + It )
{
Names . Add ( It - > ToString ( ) ) ;
}
// Autogenerate names (alphabetically sorted).
Names . Sort ( ) ;
for ( int32 NameIndex = 0 ; NameIndex < Names . Num ( ) ; NameIndex + + )
{
GeneratedCPPText . Logf ( TEXT ( " FName %s_%s = FName(TEXT( \" %s \" )); " ) LINE_TERMINATOR , * API , * Names [ NameIndex ] , * Names [ NameIndex ] ) ;
}
GeneratedCPPEpilogue . Logf (
LINE_TERMINATOR
) ;
2015-03-10 08:24:59 -04:00
FString EnableDeprecationWarnings = FString ( TEXT ( " PRAGMA_ENABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ) ;
FString DisableDeprecationWarnings = FString ( TEXT ( " PRAGMA_DISABLE_DEPRECATION_WARNINGS " ) LINE_TERMINATOR ) ;
2014-03-14 14:13:41 -04:00
FString PkgName = FPackageName : : GetShortName ( Package ) ;
FString PkgDir ;
if ( GeneratedFunctionDeclarations . Len ( ) | | CrossModuleGeneratedFunctionDeclarations . Len ( ) )
{
ExportGeneratedPackageInitCode ( Package ) ;
}
TArray < FString > NumberedHeaderNames ;
2014-04-23 20:18:55 -04:00
// Generate each of the .generated.cpp files
2014-03-14 14:13:41 -04:00
for ( int32 FileIdx = 0 ; FileIdx < GeneratedFunctionBodyTextSplit . Num ( ) ; FileIdx + + )
{
2015-03-27 18:10:52 -04:00
FUHTStringBuilder FileText ;
2014-03-14 14:13:41 -04:00
// The first file has all of the GeneratedCPPText, only the functions are split.
if ( FileIdx = = 0 )
{
FileText = GeneratedCPPText ;
}
if ( GeneratedFunctionDeclarations . Len ( ) | | CrossModuleGeneratedFunctionDeclarations . Len ( ) )
{
FileText . Logf ( TEXT ( " #if USE_COMPILED_IN_NATIVES \r \n " ) ) ;
if ( CrossModuleGeneratedFunctionDeclarations . Len ( ) )
{
FileText . Logf ( TEXT ( " // Cross Module References \r \n " ) ) ;
FileText . Log ( CrossModuleGeneratedFunctionDeclarations ) ;
FileText . Logf ( TEXT ( " \r \n " ) ) ;
}
FileText . Log ( GeneratedFunctionDeclarations ) ;
2015-04-14 08:03:34 -04:00
FileText . Log ( GeneratedFunctionBodyTextSplit [ FileIdx ] . Get ( ) ) ;
2014-03-14 14:13:41 -04:00
FileText . Logf ( TEXT ( " #endif \r \n " ) ) ;
}
2014-05-02 14:40:02 -04:00
FString CppPath = ModuleInfo - > GeneratedCPPFilenameBase + ( GeneratedFunctionBodyTextSplit . Num ( ) > 1 ? * FString : : Printf ( TEXT ( " .%d.cpp " ) , FileIdx + 1 ) : TEXT ( " .cpp " ) ) ;
2015-03-10 08:24:59 -04:00
SaveHeaderIfChanged ( * CppPath , * ( GeneratedCPPPreamble + ModulePCHInclude + GeneratedCPPClassesIncludes + DisableDeprecationWarnings + ( ( FileIdx > 0 ) ? FString ( ) : GeneratedLinkerFixupFunction ) + FileText + GeneratedCPPEpilogue + EnableDeprecationWarnings ) ) ;
2014-03-14 14:13:41 -04:00
if ( GeneratedFunctionBodyTextSplit . Num ( ) > 1 )
{
2014-05-02 14:40:02 -04:00
NumberedHeaderNames . Add ( FPaths : : GetCleanFilename ( CppPath ) ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-09-22 09:46:58 -04:00
// delete the old .cpp file that will cause link errors if it's left around (Engine.generated.cpp and Engine.generated.1.cpp will
// conflict now that we no longer use Engine.generated.cpp to #include Engine.generated.1.cpp, and UBT would compile all 3)
// @todo: This is a temp measure so we don't force everyone to require a Clean
2015-03-31 09:33:11 -04:00
if ( GeneratedFunctionBodyTextSplit . Num ( ) > 1 )
{
FString CppPath = ModuleInfo - > GeneratedCPPFilenameBase + TEXT ( " .cpp " ) ;
2014-09-22 09:46:58 -04:00
IFileManager : : Get ( ) . Delete ( * CppPath ) ;
2015-03-31 09:33:11 -04:00
}
// Delete old generated .cpp files which we don't need because we generated less code than last time.
{
TArray < FString > FoundFiles ;
IFileManager : : Get ( ) . FindFiles ( FoundFiles , * ( ModuleInfo - > GeneratedCPPFilenameBase + TEXT ( " .*.cpp " ) ) , true , false ) ;
FString BaseDir = FPaths : : GetPath ( ModuleInfo - > GeneratedCPPFilenameBase ) ;
for ( FString & File : FoundFiles )
{
if ( ! NumberedHeaderNames . Contains ( File ) )
{
IFileManager : : Get ( ) . Delete ( * FPaths : : Combine ( * BaseDir , * File ) ) ;
}
}
}
2014-03-14 14:13:41 -04:00
}
2015-03-27 18:10:52 -04:00
2014-04-29 06:45:18 -04:00
/** Get all script plugins based on ini setting */
void GetScriptPlugins ( TArray < IScriptGeneratorPluginInterface * > & ScriptPlugins )
{
2015-03-27 17:16:51 -04:00
FScopedDurationTimer PluginTimeTracker ( GPluginOverheadTime ) ;
2015-05-27 11:12:26 -04:00
ScriptPlugins = IModularFeatures : : Get ( ) . GetModularFeatureImplementations < IScriptGeneratorPluginInterface > ( TEXT ( " ScriptGenerator " ) ) ;
UE_LOG ( LogCompile , Log , TEXT ( " Found %d script generator plugins. " ) , ScriptPlugins . Num ( ) ) ;
2014-04-30 07:58:33 -04:00
// Check if we can use these plugins and initialize them
for ( int32 PluginIndex = ScriptPlugins . Num ( ) - 1 ; PluginIndex > = 0 ; - - PluginIndex )
{
auto ScriptGenerator = ScriptPlugins [ PluginIndex ] ;
bool bSupportedPlugin = ScriptGenerator - > SupportsTarget ( GManifest . TargetName ) ;
if ( bSupportedPlugin )
{
2015-11-18 16:20:49 -05:00
// Find the right output directory for this plugin base on its target (Engine-side) plugin name.
2014-06-23 06:27:04 -04:00
FString GeneratedCodeModuleName = ScriptGenerator - > GetGeneratedCodeModuleName ( ) ;
const FManifestModule * GeneratedCodeModule = NULL ;
2014-04-30 07:58:33 -04:00
FString OutputDirectory ;
2014-06-23 06:27:04 -04:00
FString IncludeBase ;
2015-11-18 16:20:49 -05:00
for ( const FManifestModule & Module : GManifest . Modules )
2014-04-30 07:58:33 -04:00
{
2014-06-23 06:27:04 -04:00
if ( Module . Name = = GeneratedCodeModuleName )
2014-04-30 07:58:33 -04:00
{
2014-06-23 06:27:04 -04:00
GeneratedCodeModule = & Module ;
2014-04-30 07:58:33 -04:00
}
}
2014-06-23 06:27:04 -04:00
if ( GeneratedCodeModule )
2014-04-30 07:58:33 -04:00
{
2015-05-27 11:12:26 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " Initializing script generator \' %s \' " ) , * ScriptGenerator - > GetGeneratorName ( ) ) ;
2014-06-23 06:27:04 -04:00
ScriptGenerator - > Initialize ( GManifest . RootLocalPath , GManifest . RootBuildPath , GeneratedCodeModule - > GeneratedIncludeDirectory , GeneratedCodeModule - > IncludeBase ) ;
2014-04-30 07:58:33 -04:00
}
else
{
// Can't use this plugin
2015-05-27 11:12:26 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " Unable to determine output directory for %s. Cannot export script glue with \' %s \' " ) , * GeneratedCodeModuleName , * ScriptGenerator - > GetGeneratorName ( ) ) ;
2014-04-30 07:58:33 -04:00
bSupportedPlugin = false ;
}
}
if ( ! bSupportedPlugin )
{
2015-05-27 11:12:26 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " Script generator \' %s \' not supported for target: %s " ) , * ScriptGenerator - > GetGeneratorName ( ) , * GManifest . TargetName ) ;
2014-04-30 07:58:33 -04:00
ScriptPlugins . RemoveAt ( PluginIndex ) ;
}
}
2014-04-29 06:45:18 -04:00
}
2014-03-14 14:13:41 -04:00
2015-06-02 02:12:11 -04:00
/**
* Tries to resolve super classes for classes defined in the given
* module .
*
* @ param Package Modules package .
*/
void ResolveSuperClasses ( UPackage * Package )
{
TArray < UObject * > Objects ;
GetObjectsWithOuter ( Package , Objects ) ;
for ( auto * Object : Objects )
{
if ( ! Object - > IsA < UClass > ( ) )
{
continue ;
}
UClass * DefinedClass = Cast < UClass > ( Object ) ;
if ( DefinedClass - > HasAnyClassFlags ( CLASS_Intrinsic | CLASS_NoExport ) )
{
continue ;
}
const FSimplifiedParsingClassInfo & ParsingInfo = GTypeDefinitionInfoMap [ DefinedClass ] - > GetUnrealSourceFile ( )
. GetDefinedClassParsingInfo ( DefinedClass ) ;
const FString & BaseClassNameStripped = GetClassNameWithPrefixRemoved ( ParsingInfo . GetBaseClassName ( ) ) ;
if ( ! BaseClassNameStripped . IsEmpty ( ) & & ! DefinedClass - > GetSuperClass ( ) )
{
UClass * FoundBaseClass = FindObject < UClass > ( Package , * BaseClassNameStripped ) ;
if ( FoundBaseClass = = nullptr )
{
FoundBaseClass = FindObject < UClass > ( ANY_PACKAGE , * BaseClassNameStripped ) ;
}
if ( FoundBaseClass = = nullptr )
{
// Don't know its parent class. Raise error.
2015-07-14 06:27:34 -04:00
FError : : Throwf ( TEXT ( " Couldn't find parent type for '%s' named '%s' in current module or any other module parsed so far. " ) ,
2015-06-02 02:12:11 -04:00
* DefinedClass - > GetName ( ) , * ParsingInfo . GetBaseClassName ( ) ) ;
}
2015-07-14 06:27:34 -04:00
DefinedClass - > SetSuperStruct ( FoundBaseClass ) ;
DefinedClass - > ClassCastFlags | = FoundBaseClass - > ClassCastFlags ;
2015-06-02 02:12:11 -04:00
}
}
}
2015-11-18 16:20:49 -05:00
ECompilationResult : : Type PreparseModules ( FUHTMakefile & UHTMakefile , const FString & ModuleInfoPath , int32 & NumFailures )
2014-03-14 14:13:41 -04:00
{
// Three passes. 1) Public 'Classes' headers (legacy) 2) Public headers 3) Private headers
2014-04-25 16:05:52 -04:00
enum EHeaderFolderTypes
2014-03-14 14:13:41 -04:00
{
2014-04-25 16:05:52 -04:00
PublicClassesHeaders = 0 ,
PublicHeaders = 1 ,
PrivateHeaders ,
2014-03-14 14:13:41 -04:00
2014-04-25 16:05:52 -04:00
FolderType_Count
} ;
2014-03-14 14:13:41 -04:00
2015-11-18 16:20:49 -05:00
ECompilationResult : : Type Result = ECompilationResult : : Succeeded ;
for ( FManifestModule & Module : GManifest . Modules )
2014-04-25 16:05:52 -04:00
{
if ( Result ! = ECompilationResult : : Succeeded )
{
break ;
2014-03-14 14:13:41 -04:00
}
2015-11-18 16:20:49 -05:00
FName ModuleName = FName ( * Module . Name ) ;
UHTMakefile . SetCurrentModuleName ( ModuleName ) ;
bool bLoadFromMakefile = UHTMakefile . CanLoadModule ( Module ) ;
if ( bLoadFromMakefile )
{
// Load module data from makefile.
UHTMakefile . LoadModuleData ( ModuleName , Module ) ;
continue ;
}
UHTMakefile . AddModule ( ModuleName ) ;
// Mark that we'll need to append newly constructed objects to ones loaded from makefile.
UHTMakefile . SetShouldMoveNewObjects ( ) ;
// Force regeneration of all subsequent modules, otherwise data will get corrupted.
Module . ForceRegeneration ( ) ;
2015-03-27 17:16:51 -04:00
2014-04-25 16:05:52 -04:00
UPackage * Package = Cast < UPackage > ( StaticFindObjectFast ( UPackage : : StaticClass ( ) , NULL , FName ( * Module . LongPackageName ) , false , false ) ) ;
if ( Package = = NULL )
2014-03-14 14:13:41 -04:00
{
2014-04-25 16:05:52 -04:00
Package = CreatePackage ( NULL , * Module . LongPackageName ) ;
}
// Set some package flags for indicating that this package contains script
// NOTE: We do this even if we didn't have to create the package, because CoreUObject is compiled into UnrealHeaderTool and we still
// want to make sure our flags get set
Copying //UE4/Dev-Framework to Dev-Main (//UE4/Dev-Main)
#lockdown Nick.Penwarden
==========================
MAJOR FEATURES + CHANGES
==========================
Change 2720406 on 2015/10/07 by Aaron.McLeran
Audio optimization
Don't search for nearest listener if there's only 1 listener.
Change 2720411 on 2015/10/07 by Aaron.McLeran
Fixing HRTF spatialization code with recent changes to stereo spatialization.
HRTF emitter posiition doesn't need to be converted to XAudio2 coordinates.
Change 2723829 on 2015/10/09 by Mieszko.Zielinski
Fixed NavigationSystem trying to set label of newly spawned navigation data #UE4
UE-21880
Change 2723873 on 2015/10/09 by Mieszko.Zielinski
Fixed a bug in FNavAgentProperties::IsEquivalent resulting in failing the test for FNavAgentProperties instances having default AgentStepHeight value (-1) #UE4
UE-21977
Change 2724834 on 2015/10/12 by Ori.Cohen
PR #1634: Add PxVehicleDriveNW support to PhysXVehicleManager.cpp (Contributed by zeduk)
Change 2724850 on 2015/10/12 by Marc.Audy
Fix sound not restarting in matinee preview when jumping back along timeline after reaching end
#codereview Nick.Darnell
Change 2726499 on 2015/10/13 by Ori.Cohen
Fix edge case where sphyl length and radius are 0 and they are not properly clamped to 0.1
Change 2726689 on 2015/10/13 by Marc.Audy
Make UPackage::PackageFlags private
Add debugging for UE-21181 to try and track down when EditorWorld's PackageFlags are getting flagged as PlayInEditor
#codereview Mike.Fricker
Change 2726862 on 2015/10/13 by Lukasz.Furman
removed unused code from DetourNavMeshQuery
#ue4 UE-21988
Change 2726888 on 2015/10/13 by Lukasz.Furman
fixed observer abort: both mode in behavior tree's cone check decorator
#ue4 UE-19375
Change 2726913 on 2015/10/13 by Lukasz.Furman
navmesh raycast will use nearest poly containing ray origin instead of just closest one
#ue4 UE-19334
Change 2726920 on 2015/10/13 by Marc.Audy
Re-unify ULevelStreaming::GetWorldAssetPackageName and GetWorldAssetPackageFName
#codereview Dmitriy.Dyomin, Bob.Tellez
Change 2726931 on 2015/10/13 by Lukasz.Furman
fixed missing Tick event in aborting behavior tree tasks from abandoned subtree
#ue4 UE-21777
Change 2728093 on 2015/10/14 by Ori.Cohen
Fix edge case of sphyl scale take two. The previous approach did double scaling
Change 2728577 on 2015/10/14 by Mieszko.Zielinski
Improved navmesh labeling condition #UE4
Change suggested by github user
#rb Lukasz.Furman
Change 2728587 on 2015/10/14 by Lukasz.Furman
fixed crowd simulation for auto possessed pawns placed on level
#ue4
#rb Mieszko.Zielinski
Change 2728629 on 2015/10/14 by Lukasz.Furman
fixed influence of navmesh edges on crowd simulation near end of path
#ue4 UE-21380
#rb Mieszko.Zielinski
Change 2728678 on 2015/10/14 by Lukasz.Furman
added Z check to detour's crowd avoidance segment gathering
#ue4 UE-20889
#rb Mieszko.Zielinski
Change 2728745 on 2015/10/14 by Lukasz.Furman
fixed copy&paste operation in behavior tree's composite decorators subgraphs
#ue4 UE-18740
Change 2729276 on 2015/10/14 by Stan.Melax
ensure all actors get recreated with new collision shape specification.
this wasn't being done for a couple of editing methods.
todo: this should be merged into 4.10
#UE-20961
#rb ori.cohen
Change 2730709 on 2015/10/15 by Marc.Audy
Prevent memory corruption when an invalid controller ID is passed in to the forcefeedback channel functions
#rb Lina.Halper
Change 2733590 on 2015/10/19 by Benn.Gallagher
Fixed various crashes when using undo and redo while manipulating state machines UE 22088
Change 2735143 on 2015/10/20 by Lukasz.Furman
clearing behavior tree debugger's state when displayed subtree becomes inactive
#ue4
#rb Mieszko.Zielinski
Change 2735144 on 2015/10/20 by Lukasz.Furman
rebuilding behavior tree graph node order when node is being moved
#ue4
#rb Mieszko.Zielinski
Change 2735403 on 2015/10/20 by sebastian.kowalczyk
Integrated fix for issue UE-18594 "Gameplay Debugger is hijacking the Canvas" issue from 4.10 (2735391). Extended previous fix to care about OSX users - it's possible to configure shortcuts in engine config file now (little different ones for osx platform).
Change 2736406 on 2015/10/21 by sebastian.kowalczyk
Added new GameplayDebugger as a plugin. Old gameplay debugger is still here to keep backward compatibility but it's deprecated now. Current projects should be moved to use new plugin soon.
Change 2736436 on 2015/10/21 by sebastian.kowalczyk
Fixed crash in gameplay debugger with player set as debug target.
Change 2736437 on 2015/10/21 by sebastian.kowalczyk
Added visual indicator around selected pawn to fix FORT-10273 issue. (FN is not using new gd plugin yet).
Change 2736489 on 2015/10/21 by sebastian.kowalczyk
Hide internal and debug hud classes from drop down lists.
Change 2736504 on 2015/10/21 by sebastian.kowalczyk
Fix for UE-18548 "EnableGDT does not work correctly in PIE".
Change 2736529 on 2015/10/21 by sebastian.kowalczyk
Fixed UE-18548 "EnableGDT does not work correctly in PIE"
Change 2736588 on 2015/10/21 by sebastian.kowalczyk
Removed old log visualizer classes.
Change 2736700 on 2015/10/21 by sebastian.kowalczyk
Fixed UE-19256 "Perception debug data doesn't get replicated by Gameplay Debuger" for old gameplay debugger module.
Change 2737180 on 2015/10/21 by Zak.Middleton
#ue4 - Fix UPrimitiveComponent::GetCollisionShape not correctly enforcing bounds limits.
#rb Aaron.Mcleran
#jira UE-22436
Change 2738084 on 2015/10/22 by sebastian.kowalczyk
Better indication of selected pawn for Gameplay Debugger.
Change 2738413 on 2015/10/22 by Marc.Audy
Disable duplication of worlds/maps via the content browser
#jira UE-22200
#rb James.Golding
Change 2739743 on 2015/10/23 by bruce.nesbit
UE-18707 - Issue with drawing material triangle on canvas #1387
Added DrawTriangleUsingVertexColor
Change 2739751 on 2015/10/23 by bruce.nesbit
Revised bShowDebugForReticleTarget should not be static #1539
Change 2739788 on 2015/10/23 by bruce.nesbit
Revised the 2 functions that used FTriangleRenderer::DrawTriangle to use FTriangleRenderer::DrawTriangleUsingVertexColor
Fixed compile error
Change 2739870 on 2015/10/23 by Marc.Audy
Avoid issues while detaching child components if OnAttachmentChange were to remove a sibling component itself.
#jira UE-22362
#rb Zak.Middleton
Change 2739882 on 2015/10/23 by sebastian.kowalczyk
Fix for UE-20901 "VisualLog redirections are broken after PIE finishes" issue.
Change 2740140 on 2015/10/23 by Marc.Audy
Ensure that components reregister tick functions after seamless travel
#jira UE-20892
#rb Zak.Middleton
Change 2740614 on 2015/10/23 by Ori.Cohen
Fix linker issues for people wanting to use physics lock lambdas
Change 2740674 on 2015/10/23 by Aaron.McLeran
Sound Focus Feature
Added new parameters to SoundAttenuation settings to allow audio to change behavior based on its angle to the listener
- Define the min/max azimuth angle to establish in-focus and non-focus regions
- Can scale the priority of a sound based on focus angle
- Can attenuate the volume of a sound based on focus angle
- Can scale the listener-emitter distance based on focus angle
- Distance scale is applied when determining max audible distance for USoundBase
- Can opt-out of focus effects for a sound at the USoundBase level
#rb Ryan.Vance
Change 2741542 on 2015/10/26 by Lukasz.Furman
lowered min value clamping in navigation filter properties
#ue4
#rb Mieszko.Zielinski
Change 2743227 on 2015/10/27 by Marc.Audy
Make ASceneCaptureCube subclassable outside of Engine module
#jira UE-22609
Make USceneCaptureComponentCube::UpdateContent callable outside of Engine module
#jira UE-22610
#rb Jeff.Farris
Change 2743255 on 2015/10/27 by Marc.Audy
Wrap FActorSpawnParameters class with deprecation warning disable pragma instead of hand implementing copy constructor
#rb Jeff.Farris
Change 2743729 on 2015/10/27 by Ori.Cohen
Fix case where we spawn and adjust location which gives us implicit velocity.
#codereview Stan.Melax
Change 2746135 on 2015/10/29 by sebastian.kowalczyk
Fixed UE-21668 "Saving log filters selected in LogVisualizer causes insane ini file sizes! And doesn't really work."
Change 2746437 on 2015/10/29 by Lukasz.Furman
pass on verifying behavior tree stack before accessing its elements
#ue4
#rb Mieszko.Zielinski
Change 2748028 on 2015/10/30 by sebastian.kowalczyk
Changed GameplayDebugger's console variable from gd.EQSOnHUD to ai.gd.EQSOnHUD" after suggestion with MieszkoZ.
Change 2748184 on 2015/10/30 by Aaron.McLeran
UE-22693 Fix for streaming bug
- 3rd decoded buffer in initial 3 buffers was not getting submitted to xaudio2 voice resulting in garbled/skipped audio.
- Wasn't able to repro the 'cannot read chunk' part of the bug
#rb ryan.vance
Change 2749255 on 2015/10/31 by sebastian.kowalczyk
Fixed ai.gd.EQSOnHUD console variable after rename from gd.EQSOnHUD.
Change 2749276 on 2015/10/31 by sebastian.kowalczyk
Added switch to toggle highlight of selected actor to GameplayDebugger.
Change 2749318 on 2015/10/31 by sebastian.kowalczyk
New Gameplay Debugger plugin can be used with old module simultaneously. It's best to configure different keyboard binding for plugin when using old module (it can be set in project settings, for new gameplay debugger plugin - when activated for project).
Change 2749337 on 2015/10/31 by sebastian.kowalczyk
Fixed GameplayDebugger compilation in shipping/test builds.
Change 2749376 on 2015/10/31 by sebastian.kowalczyk
Small clean-up in gameplay debugger class for BT.
Change 2749931 on 2015/11/02 by James.Golding
Add stats to ProcMeshComp
Change 2749932 on 2015/11/02 by James.Golding
Remove PhysicsThrusterComponent.h from Engine.h
Change 2749960 on 2015/11/02 by James.Golding
- Fix PS4 compile errors in ActiveSound.cpp
- Constructor order of FActiveSound
- Shadowed AudioComponent var in CheckOcclusion
#RB thomas.sarkanen
#codereview aaron.mcleran
Change 2749961 on 2015/11/02 by James.Golding
Fix PS4 compile errors in GameplayDebuggerBaseObject.cpp
- Shadowed DefaultContext function param, now just Context, which matches declaration
#RB thomas.sarkanen
#codereview sebastian.kowalczyk
Change 2750026 on 2015/11/02 by Thomas.Sarkanen
Anim Multithreading: thread-safety refactor
Segregated access to various parts of anim update data by spitting off a new proxy class (FAnimInstanceProxy) containing all data accessed in Update() and Evaluate() passes. Gated access to the proxy data on the game thread in a number of ways:
- Explicit access via GetValueOnGameThread() - this blocks on any existing task, completes and then allows control to return to the accessing function. This allows stuff like Blueprints to continue to operate as normal.
- Explicit access via GetValueOnAnyThread() - this ensures that in the limited set of circumstances we need this (Blueprint pure functions mostly) that conditions are met about concurrent access.
- Deprecating many APIs on UAnimInstance that should not be used (and in fact are not used at present, happily).
Derived classes of UAnimInstance can override the creation of the proxy class to create their own type. We do this for UAnimSingleNodeInstance etc.
Any API deprecation should continue to function - no functions have been removed yet. The only things that are not backwards-compatible are direct access to some public member variables for which there is no way to support (e.g. via references, for example UngroupedActivePlayerArrays).
Some APIs have been changed to more specifically represent the dependencies involved. For example TickAssetPlayerInstance() used to take a UAnimInstance*, only to use it to simply queue notifies. This has been deprecated and replaced with a new FNotifyQueue API. FNotifyQueue also uses a thread-safe FRandomStream instead of FMath::Rand.
Many changes are due to substituting accessor functions for direct variable access.
Removed 'service' tick group as we no longer need to segregate the running of our parallel update.
Anim nodes that need to do some game thread-side update should register for a pre-update callback delegate in the proxy. See FAnimNode_AnimDynamics for an example of this.
Moved UpdateActiveVertexAnims into FAnimRuntime so I can subsume some of the code that was in USkeletalMeshComponent::EvaluateAnimation into UAnimInstance (and hence keep the proxy access private).
#rb Martin.Wilson,Lina.Halper
#codereview Michael.Noland
Change 2750077 on 2015/11/02 by Marc.Audy
Expose UInputComponent::BindAction that supports WithKey delegate signature
Change 2751767 on 2015/11/03 by Thomas.Sarkanen
Added extra support to Anim Blueprint 'fast-path'
Added support for negated bools (value gets negated during copy).
Added support for copying from struct members (via break struct) and split struct pins.
Removed potentially troublesome references to BP-constructed UProperties, replacing them with the property FName. This adds some extra Initialize() overhead, but prevents various crash-on load issues (one when generating the class CRC). Added guard to prevent multiple initialization to save this more expensive work being done more often.
#rb Martin.Wilson
Change 2752158 on 2015/11/03 by Jeff.Farris
Fixed UGameplayStatics::SpawnEmitterAttached() to register the ParticleSystemComponent after it spawns.
#rb marc.audy
Change 2752159 on 2015/11/03 by Jeff.Farris
Improvements to camera lens effects to (EmitterCameraLensEffectBase)
- can now specify a transform to align the emitter with the camera
- exposed several key parameters to Blueprints
- ENGINE_API now applies to the entire class
#rb marc.audy
Change 2753454 on 2015/11/04 by Thomas.Sarkanen
Fixup deprecation warnings fallout from multithreaded update changes.
Fixed up use of AnimInstance in Vicon plugin.
Fixed up use of AnimInstance in slope warping node.
Un-deprecated some APIs to become warning free (these APIs are safe to call but just a 'bad idea if you want to do it right').
Also an extra API to allow for smoother transition: Allow custom allocation/deallocation (including using a proxy member struct) by providing an override point for proxy destruction.
#rb Martin.Wilson
Change 2754099 on 2015/11/04 by Ori.Cohen
Fix for task threads dropping stats (from Gil)
#rb Gil.Gribb
Change 2754449 on 2015/11/04 by Marc.Audy
Ensure that components created from an Actor's blueprint BeginPlay implementation get BeginPlay called on them and register their component ticks
#jira UE-20853
Reorganize some booleans to get better bit packing
#rb Jeff.Farris
#codereview Mieszko.Zielinski
Change 2754573 on 2015/11/04 by Aaron.McLeran
Fixing audio component PostLoad code to not set all LowPassFilterFrequency values to 0.0f
Change 2755345 on 2015/11/05 by Thomas.Sarkanen
Added deprecated constructors for various animation contexts
Allows existing code to compile if it creates its own contexts from UAnimInstance.
#rb James.Golding
Change 2755348 on 2015/11/05 by James.Golding
Add BP-exposed SetBoundsScale function to PrimitiveComponent
#RB thomas.sarkanen
Change 2755437 on 2015/11/05 by Marc.Audy
Fix compile errors
#codereview Thomas.Sarkanen, Mieszko.Zielinski, Aaron.McLeran
Change 2755982 on 2015/11/05 by Marc.Audy
Move HeaderParse changes for deprecation macro from Core
Fix world settings warning
Change 2756028 on 2015/11/05 by Marc.Audy
Fix shadow variable issue
Change 2756090 on 2015/11/05 by Ori.Cohen
Improve budget tool so that task threads are computed automatically.
#rb Gil.Gribb
Change 2756120 on 2015/11/05 by Mieszko.Zielinski
Fixed AIController::MoveTo not using DefaultQueryExtent of its navigation data #UE4
#rb Lukasz.Furman
Change 2756243 on 2015/11/05 by Mieszko.Zielinski
Fixed AI perception sight's "auto-visibility" mechanism totally skipping distance and vision cone checks #UE4
The old way was resulting in false positives when for example observer teleported somewhere far
#rb Lukasz.Furman
#codereview John.Abercrombie
Change 2756280 on 2015/11/05 by Mieszko.Zielinski
Minor VLog code cleanup and dumb-fixing visual logger accessing timer manager off of game thread #UE4
#rb Lukasz.Furman
Change 2756500 on 2015/11/05 by Mieszko.Zielinski
Added sanity-checking to BlueprintNodeHelpers::HasBlueprintFunction and cleaned up its usage #UE4
Also, refactored its parameters into references over pointers.
#rb Lukasz.Furman
Change 2757041 on 2015/11/06 by Thomas.Sarkanen
Removed check() in UAnimInstance::GetProxyOnAnyThread()
The check was no longer needed as if we are on the game thread we block until tasks are completed below, and if we are on any other thread we are 'safe' anyway.
#rb James.Golding
Change 2757207 on 2015/11/06 by Ori.Cohen
Fix incorrect root body cache which causes a single frame "freak out" when simulating physics from an animation
#rb Lina.Halper
Change 2757238 on 2015/11/06 by Marc.Audy
Force compiler generated functions to be generated for FHierarchicalSimplification in WorldSettings.h so that they are generated while the deprecation warnings are disabled.
#rb Mike.Fricker
Change 2757284 on 2015/11/06 by Stan.Melax
tapered capsule drawing
cloth collision happens with spheres and for the hull or tapered capsule goemetry between any specified pair of spheres.
(this was already code reviewed before, but missed the check-in window before streamtime)
#rb ori.cohen
Change 2757743 on 2015/11/06 by Lukasz.Furman
fixed node memory allocations for injected behavior tree decorators
#ue4 UE-22783
#rb Mieszko.Zielinski
Change 2757772 on 2015/11/06 by Lukasz.Furman
added setters for crowd avoidance
#ue4 UE-22785
#rb Mieszko.Zielinski
Change 2758422 on 2015/11/07 by Lina.Halper
Potential fix for invalid root bone index input
#jira :/UE-23086
#code review: Ori.Cohen
Change 2758429 on 2015/11/07 by Mieszko.Zielinski
Reimplemented a fix for AI Sight's "auto seeing" mechanics in a more flexible way #UE4
#jira UE-23089
Change 2758571 on 2015/11/08 by Mieszko.Zielinski
Modified ensure condition in UAIPerceptionComponent::OnRegister so it doesn't go off when BP does it's magic when components are being added to a BP actor class #UE4
#jira UE-23080
Change 2758821 on 2015/11/09 by Thomas.Sarkanen
Fixed animations no longer playing when using a dedicated server.
Uses correct logic to determine whether we are running as a server or not.
#rb Martin.Wilson
Change 2758920 on 2015/11/09 by Marc.Audy
Don't dereference weak object pointers repeatedly in FBoneContainer::Initialize
#rb Lina.Halper
Change 2758944 on 2015/11/09 by Ori.Cohen
Fix crash when stats are only on one thread and budget mode is used
Change 2758967 on 2015/11/09 by Benn.Gallagher
Fix for crash undoing notify socket changes in Persona, needed to recache the notify track data after the transaction had reserialized the sequence.
#jira UE-22963
Change 2758973 on 2015/11/09 by Benn.Gallagher
Added new 'Random Player' node for anim graphs allowing the user to play a selection of animations in a random order with certain randomised paramers. Also allows 'Shuffle Mode' to act more like a playlist in that it will play everything on the list before repeating.
#rb Bruce.Nesbit
Change 2759219 on 2015/11/09 by Ori.Cohen
Character perf test is now looking at stats directly and sending to analytics
#RB Ben.Salem
Change 2759398 on 2015/11/09 by Lina.Halper
Fix issue where placed montages are not playing.
- the issue is that IsPlaying does not consider montage, but SetPlaying does. It is asymmetry, so I made it same. However, there are other functions that need to be re-looked at wr.t. montage
#code review: Thomas.Sarkanen
#RB: Marc.Audy
Change 2759491 on 2015/11/09 by Lina.Halper
#Anim: Fix not getting input correctly for Copy Pose node
#RB: Marc.Audy
Change 2759602 on 2015/11/09 by Marc.Audy
Fix imporperly named struct
Change 2759795 on 2015/11/09 by Aaron.McLeran
UE-23145 Adding a Priority value to USoundBase to use in concurrency evaluation and sorting wave instances for voice stealing.
#rb zak.middleton
Change 2760081 on 2015/11/09 by Aaron.McLeran
UE-23091 Adding more logging for NaN checks and fixing one source of NaNs for audio.
OmniDirectional Math Explanation:
For XAudio2, because we do our own distance-attenuation calculations, we use the X3dAudio2 API to simply compute a speaker-map for spatialization and force the listener to be at the origin and the emitter to be on the unit-circle. Thus, from XAudio2's perspective, all distances for every listener-emitter pair will be 1.0.
So in order to use the InnerRadius blending feature, we need to trick it into doing a an inner radius blend relative to a distance of 1.0. For example, if OmniRadius and Distance are the same, then the "NormalizedOmniRadius" is 1.0 and XAudio2 will begin its "blend" of the sound to an omni-directional speaker map.
If Emitter-listener distance is less than the OmniRadius, we'll want to do more blending to an omni-directional speaker map, but we need to set the InnerRadius to something greater than 1.0 (i.e. so that the normalized distance of 1.0 will be treated as less than the InnerRadius). To do "full" omni-directional blending, the emitter-listener distance will be 0 or close to zero, and the NormalizedOmniRadius will be very large (i.e. close to infiinity).
The previous math just set the NormalizedOmniRadius to FLT_MAX which is fine but that number is eventually squared before making the API call. FLT_MAX squared is INF.
Note: I do not think we need to square the OmniRadius in:
Emitter.InnerRadius = OmniRadius*OmniRadius;
But I am keeping it t here because of legacy content which depends on that behavior.
#rb zak.middleton
hange 2760401 on 2015/11/10 by Thomas.Sarkanen@Thomas.Sarkanen-Dev-Framework
Re-instated deleted protected functions in UAnimInstance.
Fixed access of UAnimInstance in FAnimNode_StateMachine.
#rb Martin.Wilson
Change 2760407 on 2015/11/10 by Jurre.deBaare
Construct raw meshes for spline meshes now uses the render data instead of original model data (preserves tangents/normals)
Change 2760468 on 2015/11/10 by Benn.Gallagher
Anim Dynamics optimizations, cached iteration independant data to reduce footprint of iteration on limits.
#rb Graeme.Thornton
Change 2760613 on 2015/11/10 by Jeff.Farris
Fixed async collision completion delegate potentially firing repeatedly. (UE-23149)
#cr marc.audy
#codereview lina.halper
Change 2760795 on 2015/11/10 by Marc.Audy
Don't compile in pointless AddReferencedObjects when with editoronly data not defined
Minor coding standard cleanup (NULL and auto)
Change 2760848 on 2015/11/10 by Benn.Gallagher
Fix to anim instance proxy to not rely on state machine initialization to bind native delegates as nested state machines are not guaranteed to be initialized. This was fixed in UAnimInstance originally but broken again by the proxy instance code.
#jira UE-23164
#rb Martin.Wilson
Change 2760866 on 2015/11/10 by Marc.Audy
Manage transient visualization components for camera component in the same way that sprite component for other actor components are
#rb Mike.Beach
Change 2760963 on 2015/11/10 by Marc.Audy
Since construction script can cause actors to be spawned don't use a ranged for to iterate
#jira UE-22639
#rb Jeff.Farris
#codereview Dmitriy.Dyomin
Change 2762297 on 2015/11/11 by James.Golding
UE-23086 Don't ensure in SetRootBodyIndex when Bodies array is empty (ie no physics state created)
#rb martin.wilson
#codereview ori.cohen, lina.halper
Change 2763566 on 2015/11/11 by Lina.Halper
FAnimNode_CopyPoseFromMesh::Evaluate - was accessing skeleton joint, not mesh joint.
#RB: Laurent.Delayen
Change 2763926 on 2015/11/12 by Thomas.Sarkanen
Fix anim notifies not firing from single anim instances
UE-23248 - Anim Notifies are not working for Animation Sequences
UE-23249 - Anim Notifies using Sound Cues do not work
#rb James.Golding
Change 2764039 on 2015/11/12 by Jurre.deBaare
Fix for issue with incorrect material indices after reducing a skeletal mesh with non LOD0 mesh as BaseLOD (OR-9243) #rb Lina.Halper
Change 2764307 on 2015/11/12 by Jurre.deBaare
VS2015 SSF library
Change 2764314 on 2015/11/12 by Stan.Melax
crashfix was putting bad bodies to sleep at start
Fatal error!
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x00000000
UE4Editor-Engine.dll!USkeletalMeshComponent::InitArticulated() [...\\engine\\source\\runtime\\engine\\private\\skeletalmeshcomponentphysics.cpp:875]
On some skeletalmeshcomponent, some bodies aren't getting created correctly. Trying to force them to sleep was causing a crash - it expected instantiated physx bodies. Seems that all the rest of the code is able to tolerate bad bodies.
Added check to ensure physx body exists before trying to force it to sleep.
not sure if bad bodies are the norm or if this fix is just more "kicking the can down the road".
#codereview ori.cohen
Change 2764343 on 2015/11/12 by Jurre.deBaare
- Fixed crash when building a LOD with SubActors.Num < 2
- Force HLOD level slider is now always enabled, however won't show complete image if not all HLODs are build
- LODActor tree view item now scrolls into view if selected in the world
- Set bAllowCullDistanceVolume to false for LODActor's static mesh components by default
- Added 7zip files
- Fixed issue with WinINet complaining about http-request without 'http://' prefix
- Changed % reduced or original triangles display string, now uses float instead of int (for < 1% reductions)
- Override texture sizes and automatic texture bias
- Fixed issue with incorrect material merging, not picking up it required mesh-data during baking. Added extra conditions for rendering with mesh-data.
- Now incorporate static meshes with opague materials into HLOD merging
- Fixed issue with incorrect normals after merging meshes who's owning components had been negatively scaled
- Fixed issue with incorrect texture size being set from MergeActor window (was only changing .X component)
- Fixed issue with material merging when meshes with multiple LODs are merged, right now only merges LOD0's together if we are also merging the materials (otherwise, merge each LOD)
- Added ENUM for texture scaling/resizing type that has to be applied while merging the materials
- Added detail customization class for FMaterialProxySettings
#rb James.Golding
[CL 2765024 by Marc Audy in Main branch]
2015-11-12 18:11:48 -05:00
Package - > SetPackageFlags ( PKG_ContainsScript | PKG_Compiling ) ;
Package - > ClearPackageFlags ( PKG_ClientOptional | PKG_ServerSideOnly ) ;
2015-08-20 06:52:43 -04:00
if ( Module . ModuleType = = EBuildModuleType : : Editor )
{
Copying //UE4/Dev-Framework to Dev-Main (//UE4/Dev-Main)
#lockdown Nick.Penwarden
==========================
MAJOR FEATURES + CHANGES
==========================
Change 2720406 on 2015/10/07 by Aaron.McLeran
Audio optimization
Don't search for nearest listener if there's only 1 listener.
Change 2720411 on 2015/10/07 by Aaron.McLeran
Fixing HRTF spatialization code with recent changes to stereo spatialization.
HRTF emitter posiition doesn't need to be converted to XAudio2 coordinates.
Change 2723829 on 2015/10/09 by Mieszko.Zielinski
Fixed NavigationSystem trying to set label of newly spawned navigation data #UE4
UE-21880
Change 2723873 on 2015/10/09 by Mieszko.Zielinski
Fixed a bug in FNavAgentProperties::IsEquivalent resulting in failing the test for FNavAgentProperties instances having default AgentStepHeight value (-1) #UE4
UE-21977
Change 2724834 on 2015/10/12 by Ori.Cohen
PR #1634: Add PxVehicleDriveNW support to PhysXVehicleManager.cpp (Contributed by zeduk)
Change 2724850 on 2015/10/12 by Marc.Audy
Fix sound not restarting in matinee preview when jumping back along timeline after reaching end
#codereview Nick.Darnell
Change 2726499 on 2015/10/13 by Ori.Cohen
Fix edge case where sphyl length and radius are 0 and they are not properly clamped to 0.1
Change 2726689 on 2015/10/13 by Marc.Audy
Make UPackage::PackageFlags private
Add debugging for UE-21181 to try and track down when EditorWorld's PackageFlags are getting flagged as PlayInEditor
#codereview Mike.Fricker
Change 2726862 on 2015/10/13 by Lukasz.Furman
removed unused code from DetourNavMeshQuery
#ue4 UE-21988
Change 2726888 on 2015/10/13 by Lukasz.Furman
fixed observer abort: both mode in behavior tree's cone check decorator
#ue4 UE-19375
Change 2726913 on 2015/10/13 by Lukasz.Furman
navmesh raycast will use nearest poly containing ray origin instead of just closest one
#ue4 UE-19334
Change 2726920 on 2015/10/13 by Marc.Audy
Re-unify ULevelStreaming::GetWorldAssetPackageName and GetWorldAssetPackageFName
#codereview Dmitriy.Dyomin, Bob.Tellez
Change 2726931 on 2015/10/13 by Lukasz.Furman
fixed missing Tick event in aborting behavior tree tasks from abandoned subtree
#ue4 UE-21777
Change 2728093 on 2015/10/14 by Ori.Cohen
Fix edge case of sphyl scale take two. The previous approach did double scaling
Change 2728577 on 2015/10/14 by Mieszko.Zielinski
Improved navmesh labeling condition #UE4
Change suggested by github user
#rb Lukasz.Furman
Change 2728587 on 2015/10/14 by Lukasz.Furman
fixed crowd simulation for auto possessed pawns placed on level
#ue4
#rb Mieszko.Zielinski
Change 2728629 on 2015/10/14 by Lukasz.Furman
fixed influence of navmesh edges on crowd simulation near end of path
#ue4 UE-21380
#rb Mieszko.Zielinski
Change 2728678 on 2015/10/14 by Lukasz.Furman
added Z check to detour's crowd avoidance segment gathering
#ue4 UE-20889
#rb Mieszko.Zielinski
Change 2728745 on 2015/10/14 by Lukasz.Furman
fixed copy&paste operation in behavior tree's composite decorators subgraphs
#ue4 UE-18740
Change 2729276 on 2015/10/14 by Stan.Melax
ensure all actors get recreated with new collision shape specification.
this wasn't being done for a couple of editing methods.
todo: this should be merged into 4.10
#UE-20961
#rb ori.cohen
Change 2730709 on 2015/10/15 by Marc.Audy
Prevent memory corruption when an invalid controller ID is passed in to the forcefeedback channel functions
#rb Lina.Halper
Change 2733590 on 2015/10/19 by Benn.Gallagher
Fixed various crashes when using undo and redo while manipulating state machines UE 22088
Change 2735143 on 2015/10/20 by Lukasz.Furman
clearing behavior tree debugger's state when displayed subtree becomes inactive
#ue4
#rb Mieszko.Zielinski
Change 2735144 on 2015/10/20 by Lukasz.Furman
rebuilding behavior tree graph node order when node is being moved
#ue4
#rb Mieszko.Zielinski
Change 2735403 on 2015/10/20 by sebastian.kowalczyk
Integrated fix for issue UE-18594 "Gameplay Debugger is hijacking the Canvas" issue from 4.10 (2735391). Extended previous fix to care about OSX users - it's possible to configure shortcuts in engine config file now (little different ones for osx platform).
Change 2736406 on 2015/10/21 by sebastian.kowalczyk
Added new GameplayDebugger as a plugin. Old gameplay debugger is still here to keep backward compatibility but it's deprecated now. Current projects should be moved to use new plugin soon.
Change 2736436 on 2015/10/21 by sebastian.kowalczyk
Fixed crash in gameplay debugger with player set as debug target.
Change 2736437 on 2015/10/21 by sebastian.kowalczyk
Added visual indicator around selected pawn to fix FORT-10273 issue. (FN is not using new gd plugin yet).
Change 2736489 on 2015/10/21 by sebastian.kowalczyk
Hide internal and debug hud classes from drop down lists.
Change 2736504 on 2015/10/21 by sebastian.kowalczyk
Fix for UE-18548 "EnableGDT does not work correctly in PIE".
Change 2736529 on 2015/10/21 by sebastian.kowalczyk
Fixed UE-18548 "EnableGDT does not work correctly in PIE"
Change 2736588 on 2015/10/21 by sebastian.kowalczyk
Removed old log visualizer classes.
Change 2736700 on 2015/10/21 by sebastian.kowalczyk
Fixed UE-19256 "Perception debug data doesn't get replicated by Gameplay Debuger" for old gameplay debugger module.
Change 2737180 on 2015/10/21 by Zak.Middleton
#ue4 - Fix UPrimitiveComponent::GetCollisionShape not correctly enforcing bounds limits.
#rb Aaron.Mcleran
#jira UE-22436
Change 2738084 on 2015/10/22 by sebastian.kowalczyk
Better indication of selected pawn for Gameplay Debugger.
Change 2738413 on 2015/10/22 by Marc.Audy
Disable duplication of worlds/maps via the content browser
#jira UE-22200
#rb James.Golding
Change 2739743 on 2015/10/23 by bruce.nesbit
UE-18707 - Issue with drawing material triangle on canvas #1387
Added DrawTriangleUsingVertexColor
Change 2739751 on 2015/10/23 by bruce.nesbit
Revised bShowDebugForReticleTarget should not be static #1539
Change 2739788 on 2015/10/23 by bruce.nesbit
Revised the 2 functions that used FTriangleRenderer::DrawTriangle to use FTriangleRenderer::DrawTriangleUsingVertexColor
Fixed compile error
Change 2739870 on 2015/10/23 by Marc.Audy
Avoid issues while detaching child components if OnAttachmentChange were to remove a sibling component itself.
#jira UE-22362
#rb Zak.Middleton
Change 2739882 on 2015/10/23 by sebastian.kowalczyk
Fix for UE-20901 "VisualLog redirections are broken after PIE finishes" issue.
Change 2740140 on 2015/10/23 by Marc.Audy
Ensure that components reregister tick functions after seamless travel
#jira UE-20892
#rb Zak.Middleton
Change 2740614 on 2015/10/23 by Ori.Cohen
Fix linker issues for people wanting to use physics lock lambdas
Change 2740674 on 2015/10/23 by Aaron.McLeran
Sound Focus Feature
Added new parameters to SoundAttenuation settings to allow audio to change behavior based on its angle to the listener
- Define the min/max azimuth angle to establish in-focus and non-focus regions
- Can scale the priority of a sound based on focus angle
- Can attenuate the volume of a sound based on focus angle
- Can scale the listener-emitter distance based on focus angle
- Distance scale is applied when determining max audible distance for USoundBase
- Can opt-out of focus effects for a sound at the USoundBase level
#rb Ryan.Vance
Change 2741542 on 2015/10/26 by Lukasz.Furman
lowered min value clamping in navigation filter properties
#ue4
#rb Mieszko.Zielinski
Change 2743227 on 2015/10/27 by Marc.Audy
Make ASceneCaptureCube subclassable outside of Engine module
#jira UE-22609
Make USceneCaptureComponentCube::UpdateContent callable outside of Engine module
#jira UE-22610
#rb Jeff.Farris
Change 2743255 on 2015/10/27 by Marc.Audy
Wrap FActorSpawnParameters class with deprecation warning disable pragma instead of hand implementing copy constructor
#rb Jeff.Farris
Change 2743729 on 2015/10/27 by Ori.Cohen
Fix case where we spawn and adjust location which gives us implicit velocity.
#codereview Stan.Melax
Change 2746135 on 2015/10/29 by sebastian.kowalczyk
Fixed UE-21668 "Saving log filters selected in LogVisualizer causes insane ini file sizes! And doesn't really work."
Change 2746437 on 2015/10/29 by Lukasz.Furman
pass on verifying behavior tree stack before accessing its elements
#ue4
#rb Mieszko.Zielinski
Change 2748028 on 2015/10/30 by sebastian.kowalczyk
Changed GameplayDebugger's console variable from gd.EQSOnHUD to ai.gd.EQSOnHUD" after suggestion with MieszkoZ.
Change 2748184 on 2015/10/30 by Aaron.McLeran
UE-22693 Fix for streaming bug
- 3rd decoded buffer in initial 3 buffers was not getting submitted to xaudio2 voice resulting in garbled/skipped audio.
- Wasn't able to repro the 'cannot read chunk' part of the bug
#rb ryan.vance
Change 2749255 on 2015/10/31 by sebastian.kowalczyk
Fixed ai.gd.EQSOnHUD console variable after rename from gd.EQSOnHUD.
Change 2749276 on 2015/10/31 by sebastian.kowalczyk
Added switch to toggle highlight of selected actor to GameplayDebugger.
Change 2749318 on 2015/10/31 by sebastian.kowalczyk
New Gameplay Debugger plugin can be used with old module simultaneously. It's best to configure different keyboard binding for plugin when using old module (it can be set in project settings, for new gameplay debugger plugin - when activated for project).
Change 2749337 on 2015/10/31 by sebastian.kowalczyk
Fixed GameplayDebugger compilation in shipping/test builds.
Change 2749376 on 2015/10/31 by sebastian.kowalczyk
Small clean-up in gameplay debugger class for BT.
Change 2749931 on 2015/11/02 by James.Golding
Add stats to ProcMeshComp
Change 2749932 on 2015/11/02 by James.Golding
Remove PhysicsThrusterComponent.h from Engine.h
Change 2749960 on 2015/11/02 by James.Golding
- Fix PS4 compile errors in ActiveSound.cpp
- Constructor order of FActiveSound
- Shadowed AudioComponent var in CheckOcclusion
#RB thomas.sarkanen
#codereview aaron.mcleran
Change 2749961 on 2015/11/02 by James.Golding
Fix PS4 compile errors in GameplayDebuggerBaseObject.cpp
- Shadowed DefaultContext function param, now just Context, which matches declaration
#RB thomas.sarkanen
#codereview sebastian.kowalczyk
Change 2750026 on 2015/11/02 by Thomas.Sarkanen
Anim Multithreading: thread-safety refactor
Segregated access to various parts of anim update data by spitting off a new proxy class (FAnimInstanceProxy) containing all data accessed in Update() and Evaluate() passes. Gated access to the proxy data on the game thread in a number of ways:
- Explicit access via GetValueOnGameThread() - this blocks on any existing task, completes and then allows control to return to the accessing function. This allows stuff like Blueprints to continue to operate as normal.
- Explicit access via GetValueOnAnyThread() - this ensures that in the limited set of circumstances we need this (Blueprint pure functions mostly) that conditions are met about concurrent access.
- Deprecating many APIs on UAnimInstance that should not be used (and in fact are not used at present, happily).
Derived classes of UAnimInstance can override the creation of the proxy class to create their own type. We do this for UAnimSingleNodeInstance etc.
Any API deprecation should continue to function - no functions have been removed yet. The only things that are not backwards-compatible are direct access to some public member variables for which there is no way to support (e.g. via references, for example UngroupedActivePlayerArrays).
Some APIs have been changed to more specifically represent the dependencies involved. For example TickAssetPlayerInstance() used to take a UAnimInstance*, only to use it to simply queue notifies. This has been deprecated and replaced with a new FNotifyQueue API. FNotifyQueue also uses a thread-safe FRandomStream instead of FMath::Rand.
Many changes are due to substituting accessor functions for direct variable access.
Removed 'service' tick group as we no longer need to segregate the running of our parallel update.
Anim nodes that need to do some game thread-side update should register for a pre-update callback delegate in the proxy. See FAnimNode_AnimDynamics for an example of this.
Moved UpdateActiveVertexAnims into FAnimRuntime so I can subsume some of the code that was in USkeletalMeshComponent::EvaluateAnimation into UAnimInstance (and hence keep the proxy access private).
#rb Martin.Wilson,Lina.Halper
#codereview Michael.Noland
Change 2750077 on 2015/11/02 by Marc.Audy
Expose UInputComponent::BindAction that supports WithKey delegate signature
Change 2751767 on 2015/11/03 by Thomas.Sarkanen
Added extra support to Anim Blueprint 'fast-path'
Added support for negated bools (value gets negated during copy).
Added support for copying from struct members (via break struct) and split struct pins.
Removed potentially troublesome references to BP-constructed UProperties, replacing them with the property FName. This adds some extra Initialize() overhead, but prevents various crash-on load issues (one when generating the class CRC). Added guard to prevent multiple initialization to save this more expensive work being done more often.
#rb Martin.Wilson
Change 2752158 on 2015/11/03 by Jeff.Farris
Fixed UGameplayStatics::SpawnEmitterAttached() to register the ParticleSystemComponent after it spawns.
#rb marc.audy
Change 2752159 on 2015/11/03 by Jeff.Farris
Improvements to camera lens effects to (EmitterCameraLensEffectBase)
- can now specify a transform to align the emitter with the camera
- exposed several key parameters to Blueprints
- ENGINE_API now applies to the entire class
#rb marc.audy
Change 2753454 on 2015/11/04 by Thomas.Sarkanen
Fixup deprecation warnings fallout from multithreaded update changes.
Fixed up use of AnimInstance in Vicon plugin.
Fixed up use of AnimInstance in slope warping node.
Un-deprecated some APIs to become warning free (these APIs are safe to call but just a 'bad idea if you want to do it right').
Also an extra API to allow for smoother transition: Allow custom allocation/deallocation (including using a proxy member struct) by providing an override point for proxy destruction.
#rb Martin.Wilson
Change 2754099 on 2015/11/04 by Ori.Cohen
Fix for task threads dropping stats (from Gil)
#rb Gil.Gribb
Change 2754449 on 2015/11/04 by Marc.Audy
Ensure that components created from an Actor's blueprint BeginPlay implementation get BeginPlay called on them and register their component ticks
#jira UE-20853
Reorganize some booleans to get better bit packing
#rb Jeff.Farris
#codereview Mieszko.Zielinski
Change 2754573 on 2015/11/04 by Aaron.McLeran
Fixing audio component PostLoad code to not set all LowPassFilterFrequency values to 0.0f
Change 2755345 on 2015/11/05 by Thomas.Sarkanen
Added deprecated constructors for various animation contexts
Allows existing code to compile if it creates its own contexts from UAnimInstance.
#rb James.Golding
Change 2755348 on 2015/11/05 by James.Golding
Add BP-exposed SetBoundsScale function to PrimitiveComponent
#RB thomas.sarkanen
Change 2755437 on 2015/11/05 by Marc.Audy
Fix compile errors
#codereview Thomas.Sarkanen, Mieszko.Zielinski, Aaron.McLeran
Change 2755982 on 2015/11/05 by Marc.Audy
Move HeaderParse changes for deprecation macro from Core
Fix world settings warning
Change 2756028 on 2015/11/05 by Marc.Audy
Fix shadow variable issue
Change 2756090 on 2015/11/05 by Ori.Cohen
Improve budget tool so that task threads are computed automatically.
#rb Gil.Gribb
Change 2756120 on 2015/11/05 by Mieszko.Zielinski
Fixed AIController::MoveTo not using DefaultQueryExtent of its navigation data #UE4
#rb Lukasz.Furman
Change 2756243 on 2015/11/05 by Mieszko.Zielinski
Fixed AI perception sight's "auto-visibility" mechanism totally skipping distance and vision cone checks #UE4
The old way was resulting in false positives when for example observer teleported somewhere far
#rb Lukasz.Furman
#codereview John.Abercrombie
Change 2756280 on 2015/11/05 by Mieszko.Zielinski
Minor VLog code cleanup and dumb-fixing visual logger accessing timer manager off of game thread #UE4
#rb Lukasz.Furman
Change 2756500 on 2015/11/05 by Mieszko.Zielinski
Added sanity-checking to BlueprintNodeHelpers::HasBlueprintFunction and cleaned up its usage #UE4
Also, refactored its parameters into references over pointers.
#rb Lukasz.Furman
Change 2757041 on 2015/11/06 by Thomas.Sarkanen
Removed check() in UAnimInstance::GetProxyOnAnyThread()
The check was no longer needed as if we are on the game thread we block until tasks are completed below, and if we are on any other thread we are 'safe' anyway.
#rb James.Golding
Change 2757207 on 2015/11/06 by Ori.Cohen
Fix incorrect root body cache which causes a single frame "freak out" when simulating physics from an animation
#rb Lina.Halper
Change 2757238 on 2015/11/06 by Marc.Audy
Force compiler generated functions to be generated for FHierarchicalSimplification in WorldSettings.h so that they are generated while the deprecation warnings are disabled.
#rb Mike.Fricker
Change 2757284 on 2015/11/06 by Stan.Melax
tapered capsule drawing
cloth collision happens with spheres and for the hull or tapered capsule goemetry between any specified pair of spheres.
(this was already code reviewed before, but missed the check-in window before streamtime)
#rb ori.cohen
Change 2757743 on 2015/11/06 by Lukasz.Furman
fixed node memory allocations for injected behavior tree decorators
#ue4 UE-22783
#rb Mieszko.Zielinski
Change 2757772 on 2015/11/06 by Lukasz.Furman
added setters for crowd avoidance
#ue4 UE-22785
#rb Mieszko.Zielinski
Change 2758422 on 2015/11/07 by Lina.Halper
Potential fix for invalid root bone index input
#jira :/UE-23086
#code review: Ori.Cohen
Change 2758429 on 2015/11/07 by Mieszko.Zielinski
Reimplemented a fix for AI Sight's "auto seeing" mechanics in a more flexible way #UE4
#jira UE-23089
Change 2758571 on 2015/11/08 by Mieszko.Zielinski
Modified ensure condition in UAIPerceptionComponent::OnRegister so it doesn't go off when BP does it's magic when components are being added to a BP actor class #UE4
#jira UE-23080
Change 2758821 on 2015/11/09 by Thomas.Sarkanen
Fixed animations no longer playing when using a dedicated server.
Uses correct logic to determine whether we are running as a server or not.
#rb Martin.Wilson
Change 2758920 on 2015/11/09 by Marc.Audy
Don't dereference weak object pointers repeatedly in FBoneContainer::Initialize
#rb Lina.Halper
Change 2758944 on 2015/11/09 by Ori.Cohen
Fix crash when stats are only on one thread and budget mode is used
Change 2758967 on 2015/11/09 by Benn.Gallagher
Fix for crash undoing notify socket changes in Persona, needed to recache the notify track data after the transaction had reserialized the sequence.
#jira UE-22963
Change 2758973 on 2015/11/09 by Benn.Gallagher
Added new 'Random Player' node for anim graphs allowing the user to play a selection of animations in a random order with certain randomised paramers. Also allows 'Shuffle Mode' to act more like a playlist in that it will play everything on the list before repeating.
#rb Bruce.Nesbit
Change 2759219 on 2015/11/09 by Ori.Cohen
Character perf test is now looking at stats directly and sending to analytics
#RB Ben.Salem
Change 2759398 on 2015/11/09 by Lina.Halper
Fix issue where placed montages are not playing.
- the issue is that IsPlaying does not consider montage, but SetPlaying does. It is asymmetry, so I made it same. However, there are other functions that need to be re-looked at wr.t. montage
#code review: Thomas.Sarkanen
#RB: Marc.Audy
Change 2759491 on 2015/11/09 by Lina.Halper
#Anim: Fix not getting input correctly for Copy Pose node
#RB: Marc.Audy
Change 2759602 on 2015/11/09 by Marc.Audy
Fix imporperly named struct
Change 2759795 on 2015/11/09 by Aaron.McLeran
UE-23145 Adding a Priority value to USoundBase to use in concurrency evaluation and sorting wave instances for voice stealing.
#rb zak.middleton
Change 2760081 on 2015/11/09 by Aaron.McLeran
UE-23091 Adding more logging for NaN checks and fixing one source of NaNs for audio.
OmniDirectional Math Explanation:
For XAudio2, because we do our own distance-attenuation calculations, we use the X3dAudio2 API to simply compute a speaker-map for spatialization and force the listener to be at the origin and the emitter to be on the unit-circle. Thus, from XAudio2's perspective, all distances for every listener-emitter pair will be 1.0.
So in order to use the InnerRadius blending feature, we need to trick it into doing a an inner radius blend relative to a distance of 1.0. For example, if OmniRadius and Distance are the same, then the "NormalizedOmniRadius" is 1.0 and XAudio2 will begin its "blend" of the sound to an omni-directional speaker map.
If Emitter-listener distance is less than the OmniRadius, we'll want to do more blending to an omni-directional speaker map, but we need to set the InnerRadius to something greater than 1.0 (i.e. so that the normalized distance of 1.0 will be treated as less than the InnerRadius). To do "full" omni-directional blending, the emitter-listener distance will be 0 or close to zero, and the NormalizedOmniRadius will be very large (i.e. close to infiinity).
The previous math just set the NormalizedOmniRadius to FLT_MAX which is fine but that number is eventually squared before making the API call. FLT_MAX squared is INF.
Note: I do not think we need to square the OmniRadius in:
Emitter.InnerRadius = OmniRadius*OmniRadius;
But I am keeping it t here because of legacy content which depends on that behavior.
#rb zak.middleton
hange 2760401 on 2015/11/10 by Thomas.Sarkanen@Thomas.Sarkanen-Dev-Framework
Re-instated deleted protected functions in UAnimInstance.
Fixed access of UAnimInstance in FAnimNode_StateMachine.
#rb Martin.Wilson
Change 2760407 on 2015/11/10 by Jurre.deBaare
Construct raw meshes for spline meshes now uses the render data instead of original model data (preserves tangents/normals)
Change 2760468 on 2015/11/10 by Benn.Gallagher
Anim Dynamics optimizations, cached iteration independant data to reduce footprint of iteration on limits.
#rb Graeme.Thornton
Change 2760613 on 2015/11/10 by Jeff.Farris
Fixed async collision completion delegate potentially firing repeatedly. (UE-23149)
#cr marc.audy
#codereview lina.halper
Change 2760795 on 2015/11/10 by Marc.Audy
Don't compile in pointless AddReferencedObjects when with editoronly data not defined
Minor coding standard cleanup (NULL and auto)
Change 2760848 on 2015/11/10 by Benn.Gallagher
Fix to anim instance proxy to not rely on state machine initialization to bind native delegates as nested state machines are not guaranteed to be initialized. This was fixed in UAnimInstance originally but broken again by the proxy instance code.
#jira UE-23164
#rb Martin.Wilson
Change 2760866 on 2015/11/10 by Marc.Audy
Manage transient visualization components for camera component in the same way that sprite component for other actor components are
#rb Mike.Beach
Change 2760963 on 2015/11/10 by Marc.Audy
Since construction script can cause actors to be spawned don't use a ranged for to iterate
#jira UE-22639
#rb Jeff.Farris
#codereview Dmitriy.Dyomin
Change 2762297 on 2015/11/11 by James.Golding
UE-23086 Don't ensure in SetRootBodyIndex when Bodies array is empty (ie no physics state created)
#rb martin.wilson
#codereview ori.cohen, lina.halper
Change 2763566 on 2015/11/11 by Lina.Halper
FAnimNode_CopyPoseFromMesh::Evaluate - was accessing skeleton joint, not mesh joint.
#RB: Laurent.Delayen
Change 2763926 on 2015/11/12 by Thomas.Sarkanen
Fix anim notifies not firing from single anim instances
UE-23248 - Anim Notifies are not working for Animation Sequences
UE-23249 - Anim Notifies using Sound Cues do not work
#rb James.Golding
Change 2764039 on 2015/11/12 by Jurre.deBaare
Fix for issue with incorrect material indices after reducing a skeletal mesh with non LOD0 mesh as BaseLOD (OR-9243) #rb Lina.Halper
Change 2764307 on 2015/11/12 by Jurre.deBaare
VS2015 SSF library
Change 2764314 on 2015/11/12 by Stan.Melax
crashfix was putting bad bodies to sleep at start
Fatal error!
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x00000000
UE4Editor-Engine.dll!USkeletalMeshComponent::InitArticulated() [...\\engine\\source\\runtime\\engine\\private\\skeletalmeshcomponentphysics.cpp:875]
On some skeletalmeshcomponent, some bodies aren't getting created correctly. Trying to force them to sleep was causing a crash - it expected instantiated physx bodies. Seems that all the rest of the code is able to tolerate bad bodies.
Added check to ensure physx body exists before trying to force it to sleep.
not sure if bad bodies are the norm or if this fix is just more "kicking the can down the road".
#codereview ori.cohen
Change 2764343 on 2015/11/12 by Jurre.deBaare
- Fixed crash when building a LOD with SubActors.Num < 2
- Force HLOD level slider is now always enabled, however won't show complete image if not all HLODs are build
- LODActor tree view item now scrolls into view if selected in the world
- Set bAllowCullDistanceVolume to false for LODActor's static mesh components by default
- Added 7zip files
- Fixed issue with WinINet complaining about http-request without 'http://' prefix
- Changed % reduced or original triangles display string, now uses float instead of int (for < 1% reductions)
- Override texture sizes and automatic texture bias
- Fixed issue with incorrect material merging, not picking up it required mesh-data during baking. Added extra conditions for rendering with mesh-data.
- Now incorporate static meshes with opague materials into HLOD merging
- Fixed issue with incorrect normals after merging meshes who's owning components had been negatively scaled
- Fixed issue with incorrect texture size being set from MergeActor window (was only changing .X component)
- Fixed issue with material merging when meshes with multiple LODs are merged, right now only merges LOD0's together if we are also merging the materials (otherwise, merge each LOD)
- Added ENUM for texture scaling/resizing type that has to be applied while merging the materials
- Added detail customization class for FMaterialProxySettings
#rb James.Golding
[CL 2765024 by Marc Audy in Main branch]
2015-11-12 18:11:48 -05:00
Package - > SetPackageFlags ( PKG_EditorOnly ) ;
2015-08-20 06:52:43 -04:00
}
2014-04-25 16:05:52 -04:00
2015-11-18 16:20:49 -05:00
// Add new module or overwrite whatever we had loaded, that data is obsolete.
UHTMakefile . AddPackage ( Package ) ;
2014-04-25 16:05:52 -04:00
GPackageToManifestModuleMap . Add ( Package , & Module ) ;
2015-11-18 16:20:49 -05:00
double ThisModulePreparseTime = 0.0 ;
int32 NumHeadersPreparsed = 0 ;
FDurationTimer ThisModuleTimer ( ThisModulePreparseTime ) ;
ThisModuleTimer . Start ( ) ;
2015-03-27 17:16:51 -04:00
// Pre-parse the headers
2014-04-25 16:05:52 -04:00
for ( int32 PassIndex = 0 ; PassIndex < FolderType_Count & & Result = = ECompilationResult : : Succeeded ; + + PassIndex )
{
EHeaderFolderTypes CurrentlyProcessing = ( EHeaderFolderTypes ) PassIndex ;
2014-03-14 14:13:41 -04:00
// We'll make an ordered list of all UObject headers we care about.
// @todo uht: Ideally 'dependson' would not be allowed from public -> private, or NOT at all for new style headers
2014-04-23 20:18:55 -04:00
const TArray < FString > & UObjectHeaders =
( CurrentlyProcessing = = PublicClassesHeaders ) ? Module . PublicUObjectClassesHeaders :
( CurrentlyProcessing = = PublicHeaders ) ? Module . PublicUObjectHeaders :
Module . PrivateUObjectHeaders ;
if ( ! UObjectHeaders . Num ( ) )
2015-03-10 06:14:19 -04:00
{
2014-04-23 20:18:55 -04:00
continue ;
2015-03-10 06:14:19 -04:00
}
2014-04-23 20:18:55 -04:00
2015-03-27 17:16:51 -04:00
NumHeadersPreparsed + = UObjectHeaders . Num ( ) ;
for ( const FString & RawFilename : UObjectHeaders )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
# if !PLATFORM_EXCEPTIONS_DISABLED
try
# endif
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
// Import class.
2015-03-27 17:16:51 -04:00
const FString FullFilename = FPaths : : ConvertRelativePathToFull ( ModuleInfoPath , RawFilename ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 20:18:55 -04:00
FString HeaderFile ;
2015-03-27 17:16:51 -04:00
if ( ! FFileHelper : : LoadFileToString ( HeaderFile , * FullFilename ) )
2014-04-29 06:45:18 -04:00
{
2015-03-27 17:16:51 -04:00
FError : : Throwf ( TEXT ( " UnrealHeaderTool was unable to load source file '%s' " ) , * FullFilename ) ;
2014-04-29 06:45:18 -04:00
}
2014-03-14 14:13:41 -04:00
2015-11-18 16:20:49 -05:00
TSharedRef < FUnrealSourceFile > UnrealSourceFile = PerformInitialParseOnHeader ( Package , RawFilename , RF_Public | RF_Standalone , * HeaderFile , UHTMakefile ) ;
FUnrealSourceFile * UnrealSourceFilePtr = & UnrealSourceFile . Get ( ) ;
TArray < UClass * > DefinedClasses = UnrealSourceFile - > GetDefinedClasses ( ) ;
for ( UClass * DefinedClass : DefinedClasses )
{
UHTMakefile . AddClass ( UnrealSourceFilePtr , DefinedClass ) ;
}
2015-03-27 17:16:51 -04:00
GUnrealSourceFilesMap . Add ( RawFilename , UnrealSourceFile ) ;
2015-11-18 16:20:49 -05:00
UHTMakefile . AddUnrealSourceFilesMapEntry ( UnrealSourceFilePtr , RawFilename ) ;
2015-01-20 09:33:54 -05:00
if ( CurrentlyProcessing = = PublicClassesHeaders )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
for ( auto * Class : UnrealSourceFile - > GetDefinedClasses ( ) )
{
GPublicClassSet . Add ( Class ) ;
2015-11-18 16:20:49 -05:00
UHTMakefile . AddPublicClassSetEntry ( UnrealSourceFilePtr , Class ) ;
2015-01-20 09:33:54 -05:00
}
2015-11-18 16:20:49 -05:00
GPublicSourceFileSet . Add ( UnrealSourceFilePtr ) ;
2014-04-23 20:18:55 -04:00
}
2014-03-14 14:13:41 -04:00
2014-04-23 20:18:55 -04:00
// Save metadata for the class path, both for it's include path and relative to the module base directory
2015-03-27 17:16:51 -04:00
if ( FullFilename . StartsWith ( Module . BaseDirectory ) )
2014-04-23 20:18:55 -04:00
{
// Get the path relative to the module directory
2015-03-27 17:16:51 -04:00
const TCHAR * ModuleRelativePath = * FullFilename + Module . BaseDirectory . Len ( ) ;
2015-01-20 09:33:54 -05:00
UnrealSourceFile - > SetModuleRelativePath ( ModuleRelativePath ) ;
2014-03-14 14:13:41 -04:00
2014-05-07 05:38:15 -04:00
// Calculate the include path
2015-03-27 17:16:51 -04:00
const TCHAR * IncludePath = ModuleRelativePath ;
2014-05-07 05:38:15 -04:00
// Walk over the first potential slash
2015-03-27 17:16:51 -04:00
if ( * IncludePath = = TEXT ( ' / ' ) )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:18:55 -04:00
IncludePath + + ;
2014-03-14 14:13:41 -04:00
}
2014-05-07 05:38:15 -04:00
// Does this module path start with a known include path location? If so, we can cut that part out of the include path
static const TCHAR PublicFolderName [ ] = TEXT ( " Public/ " ) ;
static const TCHAR PrivateFolderName [ ] = TEXT ( " Private/ " ) ;
static const TCHAR ClassesFolderName [ ] = TEXT ( " Classes/ " ) ;
2015-03-27 17:16:51 -04:00
if ( FCString : : Strnicmp ( IncludePath , PublicFolderName , ARRAY_COUNT ( PublicFolderName ) - 1 ) = = 0 )
2014-03-14 14:13:41 -04:00
{
2014-05-07 06:23:29 -04:00
IncludePath + = ( ARRAY_COUNT ( PublicFolderName ) - 1 ) ;
2014-04-23 20:18:55 -04:00
}
2015-03-27 17:16:51 -04:00
else if ( FCString : : Strnicmp ( IncludePath , PrivateFolderName , ARRAY_COUNT ( PrivateFolderName ) - 1 ) = = 0 )
2014-04-23 20:18:55 -04:00
{
2014-05-07 06:23:29 -04:00
IncludePath + = ( ARRAY_COUNT ( PrivateFolderName ) - 1 ) ;
2014-05-07 05:38:15 -04:00
}
2015-03-27 17:16:51 -04:00
else if ( FCString : : Strnicmp ( IncludePath , ClassesFolderName , ARRAY_COUNT ( ClassesFolderName ) - 1 ) = = 0 )
2014-05-07 05:38:15 -04:00
{
2014-05-07 06:23:29 -04:00
IncludePath + = ( ARRAY_COUNT ( ClassesFolderName ) - 1 ) ;
2014-05-07 05:38:15 -04:00
}
// Add the include path
2015-03-27 17:16:51 -04:00
if ( * IncludePath ! = 0 )
2014-05-07 05:38:15 -04:00
{
2015-01-20 09:33:54 -05:00
UnrealSourceFile - > SetIncludePath ( MoveTemp ( IncludePath ) ) ;
2014-03-14 14:13:41 -04:00
}
}
}
2014-04-23 20:18:55 -04:00
# if !PLATFORM_EXCEPTIONS_DISABLED
2015-03-27 17:16:51 -04:00
catch ( TCHAR * ErrorMsg )
2014-04-23 18:36:17 -04:00
{
2014-04-23 20:18:55 -04:00
TGuardValue < ELogTimes : : Type > DisableLogTimes ( GPrintLogTimes , ELogTimes : : None ) ;
2015-07-14 06:27:34 -04:00
FString AbsFilename = IFileManager : : Get ( ) . ConvertToAbsolutePathForExternalAppForRead ( * RawFilename ) ;
FString Prefix = FString : : Printf ( TEXT ( " %s(1): " ) , * AbsFilename ) ;
2014-04-23 20:18:55 -04:00
FString FormattedErrorMessage = FString : : Printf ( TEXT ( " %sError: %s \r \n " ) , * Prefix , ErrorMsg ) ;
Result = GCompilationResult ;
UE_LOG ( LogCompile , Log , TEXT ( " %s " ) , * FormattedErrorMessage ) ;
GWarn - > Log ( ELogVerbosity : : Error , FormattedErrorMessage ) ;
+ + NumFailures ;
2014-04-23 18:36:17 -04:00
}
2014-04-23 20:18:55 -04:00
# endif
}
2014-04-25 16:05:52 -04:00
if ( Result = = ECompilationResult : : Succeeded & & NumFailures ! = 0 )
2014-04-23 20:18:55 -04:00
{
Result = ECompilationResult : : OtherCompilationError ;
2014-03-14 14:13:41 -04:00
}
}
2015-03-27 17:16:51 -04:00
2015-11-18 16:20:49 -05:00
// Don't resolve superclasses for module when loading from makefile.
// Data is only partially loaded at this point.
if ( ! bLoadFromMakefile )
{
2015-07-14 06:27:34 -04:00
# if !PLATFORM_EXCEPTIONS_DISABLED
try
# endif
{
ResolveSuperClasses ( Package ) ;
}
# if !PLATFORM_EXCEPTIONS_DISABLED
catch ( TCHAR * ErrorMsg )
{
TGuardValue < ELogTimes : : Type > DisableLogTimes ( GPrintLogTimes , ELogTimes : : None ) ;
FString FormattedErrorMessage = FString : : Printf ( TEXT ( " Error: %s \r \n " ) , ErrorMsg ) ;
Result = GCompilationResult ;
UE_LOG ( LogCompile , Log , TEXT ( " %s " ) , * FormattedErrorMessage ) ;
GWarn - > Log ( ELogVerbosity : : Error , FormattedErrorMessage ) ;
+ + NumFailures ;
}
# endif
2015-06-02 02:12:11 -04:00
2015-03-27 17:16:51 -04:00
ThisModuleTimer . Stop ( ) ;
UE_LOG ( LogCompile , Log , TEXT ( " Preparsed module %s containing %i files(s) in %.2f secs. " ) , * Module . LongPackageName , NumHeadersPreparsed , ThisModulePreparseTime ) ;
2014-03-14 14:13:41 -04:00
}
2015-11-18 16:20:49 -05:00
}
2014-03-14 14:13:41 -04:00
2015-11-18 16:20:49 -05:00
return Result ;
}
ECompilationResult : : Type UnrealHeaderTool_Main ( const FString & ModuleInfoFilename )
{
check ( GIsUCCMakeStandaloneHeaderGenerator ) ;
ECompilationResult : : Type Result = ECompilationResult : : Succeeded ;
if ( ! FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " IgnoreWarnings " ) ) )
{
GWarn - > TreatWarningsAsErrors = true ;
}
FString ModuleInfoPath = FPaths : : GetPath ( ModuleInfoFilename ) ;
// Load the manifest file, giving a list of all modules to be processed, pre-sorted by dependency ordering
# if !PLATFORM_EXCEPTIONS_DISABLED
try
# endif
{
GManifest = FManifest : : LoadFromFile ( ModuleInfoFilename ) ;
}
# if !PLATFORM_EXCEPTIONS_DISABLED
catch ( const TCHAR * Ex )
{
UE_LOG ( LogCompile , Error , TEXT ( " Failed to load manifest file '%s': %s " ) , * ModuleInfoFilename , Ex ) ;
return GCompilationResult ;
}
# endif
// Counters.
int32 NumFailures = 0 ;
double TotalModulePreparseTime = 0.0 ;
double TotalParseAndCodegenTime = 0.0 ;
// Check if makefiles should be used. If not, only makefile serialization is skipped.
// as the rest of code doesn't impact performance and we don't want to add ifs around
// every makefile related piece of code.
bool bUseMakefile = FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " UseMakefiles " ) ) ;
FUHTMakefile UHTMakefile ;
UHTMakefile . SetNameLookupCPP ( & NameLookupCPP ) ;
UHTMakefile . SetManifest ( & GManifest ) ;
// Declaring outside of bUseMakefile scope as the same value is used when saving makefile.
FString MakefilePath ;
if ( bUseMakefile )
{
MakefilePath = FPaths : : Combine ( * ModuleInfoPath , TEXT ( " UHT.makefile " ) ) ;
UHTMakefile . LoadFromFile ( * MakefilePath , & GManifest ) ;
}
UHTMakefile . StartPreloading ( ) ;
{
FDurationTimer TotalModulePreparseTimer ( TotalModulePreparseTime ) ;
TotalModulePreparseTimer . Start ( ) ;
PreparseModules ( UHTMakefile , ModuleInfoPath , NumFailures ) ;
TotalModulePreparseTimer . Stop ( ) ;
}
UHTMakefile . StopPreloading ( ) ;
2015-03-27 17:16:51 -04:00
// Do the actual parse of the headers and generate for them
if ( Result = = ECompilationResult : : Succeeded )
2014-03-14 14:13:41 -04:00
{
2015-03-27 17:16:51 -04:00
FScopedDurationTimer ParseAndCodeGenTimer ( TotalParseAndCodegenTime ) ;
2014-03-14 14:13:41 -04:00
// Verify that all script declared superclasses exist.
2014-04-23 20:18:55 -04:00
for ( const UClass * ScriptClass : TObjectRange < UClass > ( ) )
2014-03-14 14:13:41 -04:00
{
const UClass * ScriptSuperClass = ScriptClass - > GetSuperClass ( ) ;
2015-01-20 09:33:54 -05:00
if ( ScriptSuperClass & & ! ScriptSuperClass - > HasAnyClassFlags ( CLASS_Intrinsic ) & & GTypeDefinitionInfoMap . Contains ( ScriptClass ) & & ! GTypeDefinitionInfoMap . Contains ( ScriptSuperClass ) )
2014-03-14 14:13:41 -04:00
{
2014-05-19 03:21:12 -04:00
class FSuperClassContextSupplier : public FContextSupplier
{
public :
2015-01-20 09:33:54 -05:00
FSuperClassContextSupplier ( const UClass * Class )
: DefinitionInfo ( GTypeDefinitionInfoMap [ Class ] )
2014-05-19 03:21:12 -04:00
{ }
2014-06-13 06:14:46 -04:00
virtual FString GetContext ( ) override
2014-05-19 03:21:12 -04:00
{
2015-01-20 09:33:54 -05:00
FString Filename = IFileManager : : Get ( ) . ConvertToAbsolutePathForExternalAppForRead ( * DefinitionInfo - > GetUnrealSourceFile ( ) . GetFilename ( ) ) ;
int32 LineNumber = DefinitionInfo - > GetLineNumber ( ) ;
2014-05-19 03:21:12 -04:00
return FString : : Printf ( TEXT ( " %s(%i) " ) , * Filename , LineNumber ) ;
}
private :
2015-01-20 09:33:54 -05:00
TSharedRef < FUnrealTypeDefinitionInfo > DefinitionInfo ;
2014-05-19 03:21:12 -04:00
} ContextSupplier ( ScriptClass ) ;
auto OldContext = GWarn - > GetContext ( ) ;
TGuardValue < ELogTimes : : Type > DisableLogTimes ( GPrintLogTimes , ELogTimes : : None ) ;
GWarn - > SetContext ( & ContextSupplier ) ;
GWarn - > Log ( ELogVerbosity : : Error , FString : : Printf ( TEXT ( " Error: Superclass %s of class %s not found " ) , * ScriptSuperClass - > GetName ( ) , * ScriptClass - > GetName ( ) ) ) ;
GWarn - > SetContext ( OldContext ) ;
2014-04-23 18:36:17 -04:00
Result = ECompilationResult : : OtherCompilationError ;
2014-03-14 14:13:41 -04:00
+ + NumFailures ;
}
}
2014-04-23 18:36:17 -04:00
if ( Result = = ECompilationResult : : Succeeded )
2014-03-14 14:13:41 -04:00
{
2014-04-29 06:45:18 -04:00
TArray < IScriptGeneratorPluginInterface * > ScriptPlugins ;
2014-04-30 07:58:33 -04:00
// Can only export scripts for game targets
if ( GManifest . IsGameTarget )
{
GetScriptPlugins ( ScriptPlugins ) ;
2014-04-29 09:36:01 -04:00
}
2015-11-18 16:20:49 -05:00
if ( UHTMakefile . ShouldMoveNewObjects ( ) )
{
UHTMakefile . MoveNewObjects ( ) ;
}
for ( const FManifestModule & Module : GManifest . Modules )
2014-04-29 09:36:01 -04:00
{
if ( UPackage * Package = Cast < UPackage > ( StaticFindObjectFast ( UPackage : : StaticClass ( ) , NULL , FName ( * Module . LongPackageName ) , false , false ) ) )
{
2014-06-02 07:02:29 -04:00
// Object which represents all parsed classes
FClasses AllClasses ( Package ) ;
AllClasses . Validate ( ) ;
2015-03-02 06:44:04 -05:00
# if WITH_HOT_RELOAD_CTORS
static struct FUseVTableConstructorsCache
{
FUseVTableConstructorsCache ( )
{
bUseVTableConstructors = false ;
GConfig - > GetBool ( TEXT ( " Core.System " ) , TEXT ( " UseVTableConstructors " ) , bUseVTableConstructors , GEngineIni ) ;
}
bool bUseVTableConstructors ;
} UseVTableConstructorsCache ;
Result = FHeaderParser : : ParseAllHeadersInside ( AllClasses , GWarn , Package , Module , ScriptPlugins ,
2015-11-18 16:20:49 -05:00
Module . ModuleType ! = EBuildModuleType : : Game | | UseVTableConstructorsCache . bUseVTableConstructors , UHTMakefile ) ;
2015-03-02 06:44:04 -05:00
# else // WITH_HOT_RELOAD_CTORS
2015-11-18 16:20:49 -05:00
Result = FHeaderParser : : ParseAllHeadersInside ( AllClasses , GWarn , Package , Module , ScriptPlugins , UHTMakefile ) ;
2015-03-02 06:44:04 -05:00
# endif // WITH_HOT_RELOAD_CTORS
2014-04-29 09:36:01 -04:00
if ( Result ! = ECompilationResult : : Succeeded )
{
+ + NumFailures ;
break ;
}
}
}
2014-04-29 06:45:18 -04:00
{
2015-03-27 17:16:51 -04:00
FScopedDurationTimer PluginTimeTracker ( GPluginOverheadTime ) ;
2015-11-18 16:20:49 -05:00
for ( IScriptGeneratorPluginInterface * ScriptGenerator : ScriptPlugins )
2015-03-27 17:16:51 -04:00
{
ScriptGenerator - > FinishExport ( ) ;
}
2014-03-14 14:13:41 -04:00
}
}
}
// Avoid TArray slack for meta data.
2014-06-02 07:02:29 -04:00
GScriptHelper . Shrink ( ) ;
2014-03-14 14:13:41 -04:00
2015-07-17 13:48:35 -04:00
UE_LOG ( LogCompile , Log , TEXT ( " Preparsing %i modules took %.2f seconds " ) , GManifest . Modules . Num ( ) , TotalModulePreparseTime ) ;
UE_LOG ( LogCompile , Log , TEXT ( " Parsing took %.2f seconds " ) , TotalParseAndCodegenTime - GHeaderCodeGenTime ) ;
UE_LOG ( LogCompile , Log , TEXT ( " Code generation took %.2f seconds " ) , GHeaderCodeGenTime ) ;
UE_LOG ( LogCompile , Log , TEXT ( " ScriptPlugin overhead was %.2f seconds " ) , GPluginOverheadTime ) ;
UE_LOG ( LogCompile , Log , TEXT ( " Macroize time was %.2f seconds " ) , GMacroizeTime ) ;
2015-03-27 17:16:51 -04:00
if ( bWriteContents )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Log , TEXT ( " ********************************* Wrote reference generated code to ReferenceGeneratedCode. " ) ) ;
}
2015-03-27 17:16:51 -04:00
else if ( bVerifyContents )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Log , TEXT ( " ********************************* Wrote generated code to VerifyGeneratedCode and compared to ReferenceGeneratedCode " ) ) ;
for ( FString & Msg : ChangeMessages )
{
UE_LOG ( LogCompile , Error , TEXT ( " %s " ) , * Msg ) ;
}
TArray < FString > RefFileNames ;
IFileManager : : Get ( ) . FindFiles ( RefFileNames , * ( FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " ReferenceGeneratedCode/*.* " ) ) , true , false ) ;
TArray < FString > VerFileNames ;
IFileManager : : Get ( ) . FindFiles ( VerFileNames , * ( FString ( FPaths : : GameSavedDir ( ) ) / TEXT ( " VerifyGeneratedCode/*.* " ) ) , true , false ) ;
if ( RefFileNames . Num ( ) ! = VerFileNames . Num ( ) )
{
UE_LOG ( LogCompile , Error , TEXT ( " Number of generated files mismatch ref=%d, ver=%d " ) , RefFileNames . Num ( ) , VerFileNames . Num ( ) ) ;
}
}
2015-11-18 16:20:49 -05:00
2014-03-14 14:13:41 -04:00
TheFlagAudit . WriteResults ( ) ;
GIsRequestingExit = true ;
2014-04-23 18:36:17 -04:00
2015-11-18 16:20:49 -05:00
if ( ( Result ! = ECompilationResult : : Succeeded ) | | ( NumFailures > 0 ) )
2014-04-23 18:36:17 -04:00
{
2015-11-18 16:20:49 -05:00
// Makefile might be corrupted, it's safer to delete it now.
IFileManager : : Get ( ) . Delete ( * MakefilePath ) ;
2014-04-23 18:36:17 -04:00
return ECompilationResult : : OtherCompilationError ;
}
2014-03-14 14:13:41 -04:00
2015-11-18 16:20:49 -05:00
if ( bUseMakefile )
{
UHTMakefile . SaveToFile ( * MakefilePath ) ;
}
2014-04-23 18:36:17 -04:00
return Result ;
2014-03-14 14:13:41 -04:00
}
2015-01-20 09:33:54 -05:00
UClass * ProcessParsedClass ( bool bClassIsAnInterface , TArray < FHeaderProvider > & DependentOn , const FString & ClassName , const FString & BaseClassName , UObject * InParent , EObjectFlags Flags )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
FString ClassNameStripped = GetClassNameWithPrefixRemoved ( * ClassName ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 13:06:35 -05:00
// All classes must start with a valid unreal prefix
if ( ! FHeaderParser : : ClassNameHasValidPrefix ( ClassName , ClassNameStripped ) )
{
FError : : Throwf ( TEXT ( " Invalid class name '%s'. The class name must have an appropriate prefix added (A for Actors, U for other classes). " ) , * ClassName ) ;
}
2014-03-14 14:13:41 -04:00
// Ensure the base class has any valid prefix and exists as a valid class. Checking for the 'correct' prefix will occur during compilation
FString BaseClassNameStripped ;
if ( ! BaseClassName . IsEmpty ( ) )
{
2014-04-23 18:42:01 -04:00
BaseClassNameStripped = GetClassNameWithPrefixRemoved ( BaseClassName ) ;
2015-01-20 09:33:54 -05:00
if ( ! FHeaderParser : : ClassNameHasValidPrefix ( BaseClassName , BaseClassNameStripped ) )
FError : : Throwf ( TEXT ( " No prefix or invalid identifier for base class %s. \n Class names must match Unreal prefix specifications (e.g., \" UObject \" or \" AActor \" ) " ) , * BaseClassName ) ;
2014-03-14 14:13:41 -04:00
2015-01-20 09:33:54 -05:00
if ( DependentOn . ContainsByPredicate ( [ & ] ( const FHeaderProvider & Dependency ) { FString DependencyStr = Dependency . GetId ( ) ; return ! DependencyStr . Contains ( TEXT ( " .generated.h " ) ) & & FPaths : : GetBaseFilename ( DependencyStr ) = = ClassNameStripped ; } ) )
2014-03-14 14:13:41 -04:00
FError : : Throwf ( TEXT ( " Class '%s' contains a dependency (#include or DependsOn) to itself " ) , * ClassName ) ;
}
//UE_LOG(LogCompile, Log, TEXT("Class: %s extends %s"),*ClassName,*BaseClassName);
// Handle failure and non-class headers.
if ( BaseClassName . IsEmpty ( ) & & ( ClassName ! = TEXT ( " UObject " ) ) )
{
2015-01-20 09:33:54 -05:00
FError : : Throwf ( TEXT ( " Class '%s' must inherit UObject or a UObject-derived class " ) , * ClassName ) ;
2014-03-14 14:13:41 -04:00
}
if ( ClassName = = BaseClassName )
{
2015-01-20 09:33:54 -05:00
FError : : Throwf ( TEXT ( " Class '%s' cannot inherit from itself " ) , * ClassName ) ;
2014-03-14 14:13:41 -04:00
}
// In case the file system and the class disagree on the case of the
// class name replace the fname with the one from the script class file
// This is needed because not all source control systems respect the
// original filename's case
2015-01-20 09:33:54 -05:00
FName ClassNameReplace ( * ClassName , FNAME_Replace_Not_Safe_For_Threading ) ;
2014-03-14 14:13:41 -04:00
// Use stripped class name for processing and replace as we did above
FName ClassNameStrippedReplace ( * ClassNameStripped , FNAME_Replace_Not_Safe_For_Threading ) ;
UClass * ResultClass = FindObject < UClass > ( InParent , * ClassNameStripped ) ;
// if we aren't generating headers, then we shouldn't set misaligned object, since it won't get cleared
const static bool bVerboseOutput = FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " VERBOSE " ) ) ;
2015-11-18 16:20:49 -05:00
if ( ResultClass = = nullptr | | ! ResultClass - > IsNative ( ) )
2014-03-14 14:13:41 -04:00
{
// detect if the same class name is used in multiple packages
2015-01-20 09:33:54 -05:00
if ( ResultClass = = nullptr )
2014-03-14 14:13:41 -04:00
{
UClass * ConflictingClass = FindObject < UClass > ( ANY_PACKAGE , * ClassNameStripped , true ) ;
2015-01-20 09:33:54 -05:00
if ( ConflictingClass ! = nullptr )
2014-03-14 14:13:41 -04:00
{
UE_LOG ( LogCompile , Warning , TEXT ( " Duplicate class name: %s also exists in file %s " ) , * ClassName , * ConflictingClass - > GetOutermost ( ) - > GetName ( ) ) ;
}
}
// Create new class.
2015-01-30 08:30:03 -05:00
ResultClass = new ( EC_InternalUseOnlyConstructor , InParent , * ClassNameStripped , Flags ) UClass ( FObjectInitializer ( ) , nullptr ) ;
2014-03-14 14:13:41 -04:00
GClassHeaderNameWithNoPathMap . Add ( ResultClass , ClassNameStripped ) ;
// add CLASS_Interface flag if the class is an interface
// NOTE: at this pre-parsing/importing stage, we cannot know if our super class is an interface or not,
// we leave the validation to the main header parser
if ( bClassIsAnInterface )
{
ResultClass - > ClassFlags | = CLASS_Interface ;
}
2015-01-20 09:33:54 -05:00
if ( bVerboseOutput )
2014-03-14 14:13:41 -04:00
{
2015-01-20 09:33:54 -05:00
UE_LOG ( LogCompile , Log , TEXT ( " Imported: %s " ) , * ResultClass - > GetFullName ( ) ) ;
}
}
2014-03-14 14:13:41 -04:00
if ( bVerboseOutput )
{
for ( const auto & Dependency : DependentOn )
{
UE_LOG ( LogCompile , Log , TEXT ( " \t Adding %s as a dependency " ) , * Dependency . ToString ( ) ) ;
}
}
return ResultClass ;
}
2015-01-20 09:33:54 -05:00
2015-11-18 16:20:49 -05:00
TSharedRef < FUnrealSourceFile > PerformInitialParseOnHeader ( UPackage * InParent , const FString & FileName , EObjectFlags Flags , const TCHAR * Buffer , FUHTMakefile & UHTMakefile )
2015-01-20 09:33:54 -05:00
{
const TCHAR * InBuffer = Buffer ;
// is the parsed class name an interface?
bool bClassIsAnInterface = false ;
TArray < FHeaderProvider > DependsOn ;
// Parse the header to extract the information needed
2015-03-27 18:10:52 -04:00
FUHTStringBuilder ClassHeaderTextStrippedOfCppText ;
2015-01-20 09:33:54 -05:00
TArray < FSimplifiedParsingClassInfo > ParsedClassArray ;
FHeaderParser : : SimplifiedClassParse ( Buffer , /*out*/ ParsedClassArray , /*out*/ DependsOn , ClassHeaderTextStrippedOfCppText ) ;
2015-11-18 16:20:49 -05:00
FUnrealSourceFile * UnrealSourceFilePtr = new FUnrealSourceFile ( InParent , FileName , ClassHeaderTextStrippedOfCppText ) ;
TSharedRef < FUnrealSourceFile > UnrealSourceFile = MakeShareable ( UnrealSourceFilePtr ) ;
UHTMakefile . AddUnrealSourceFile ( UnrealSourceFilePtr ) ;
UHTMakefile . AddToHeaderOrder ( UnrealSourceFilePtr ) ;
2015-01-20 09:33:54 -05:00
for ( auto & ParsedClassInfo : ParsedClassArray )
{
UClass * ResultClass = ProcessParsedClass ( ParsedClassInfo . IsInterface ( ) , DependsOn , ParsedClassInfo . GetClassName ( ) , ParsedClassInfo . GetBaseClassName ( ) , InParent , Flags ) ;
2015-11-18 16:20:49 -05:00
FScope : : AddTypeScope ( ResultClass , & UnrealSourceFile - > GetScope ( ) . Get ( ) , UnrealSourceFilePtr , UHTMakefile ) ;
2015-01-20 09:33:54 -05:00
2015-11-18 16:20:49 -05:00
AddTypeDefinition ( UHTMakefile , UnrealSourceFilePtr , ResultClass , ParsedClassInfo . GetClassDefLine ( ) ) ;
2015-06-02 02:12:11 -04:00
UnrealSourceFile - > AddDefinedClass ( ResultClass , MoveTemp ( ParsedClassInfo ) ) ;
2015-01-20 09:33:54 -05:00
}
2015-11-18 16:20:49 -05:00
for ( auto & DependsOnElement : DependsOn )
2015-01-20 09:33:54 -05:00
{
UnrealSourceFile - > GetIncludes ( ) . Add ( DependsOnElement ) ;
}
return UnrealSourceFile ;
}