Advertisement
heapcleaner

TraceObject in Unreal Engine

Jun 25th, 2016
1,147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.34 KB | None | 0 0
  1. [DECLARATION]
  2.  
  3. //////////////////////////////////////////////////////////////////////////
  4. // Macro to simplify UE_LOG for debugging
  5. //////////////////////////////////////////////////////////////////////////
  6.  
  7. #ifndef TRACE_LOG_CATEGORY
  8. #define TRACE_LOG_CATEGORY LogTemp
  9. #endif
  10.  
  11. #ifndef TRACE_LOG_VERBOSITY
  12. #define TRACE_LOG_VERBOSITY Log
  13. #endif
  14.  
  15. #ifdef UE_BUILD_DEBUG
  16.     #define TraceNoCurLine(Format, ...) UE_LOG( TRACE_LOG_CATEGORY, TRACE_LOG_VERBOSITY, TEXT(Format), ##__VA_ARGS__ )
  17. #else
  18.     #define TraceNoCurLine(Format, ...)
  19. #endif
  20.  
  21. //////////////////////////////////////////////////////////////////////////
  22. // Debug Utilities
  23. //////////////////////////////////////////////////////////////////////////
  24.  
  25. /** Convert object flags to string. */
  26. FString ObjectFlagsToString( EObjectFlags ObjectFlags );
  27.  
  28. /** Convert class flags to string. */
  29. FString ClassFlagsToString( uint32 ClassFlags );
  30.  
  31. /** Convert property flags to string. */
  32. FString PropertyFlagsToString( uint64 PropertyFlags );
  33.  
  34. // Flags for TraceObject
  35. #define TOF_OBJECT_DETAILS      0x01
  36. #define TOF_CLASS_DETAILS       0x02
  37. #define TOF_PROPERTY_DETAILS    0x08
  38.  
  39. #define TOF_ALL_DETAILS         0xff
  40. #define TOF_NONE                0x00
  41. // End of flags for TraceObject
  42.  
  43. /**
  44. * Print information of an object to the log.
  45. * @note: This function only works in debug builds (DebugGame or DebugGameEditor), it does nothing in Development or Shipping build.
  46. * @param    Object                  The object whose information will be written to the log.
  47. * @param    Title                   The title that will be added at the beginning of the information.
  48. * @param    PropertyNameToTrace     List of property names to be included in the the information.
  49. * @param    TraceObjectFlags        Bit flags of what details to be added to the information, the default value is to print all details.
  50. */
  51. void TraceObject( const UObject* Object, const FString& Title = TEXT(""), const TArray<FName>& PropertyNamesToTrace = TArray<FName>(), int32 TraceObjectFlags = TOF_ALL_DETAILS  );
  52.  
  53. [DEFINITION]
  54.  
  55. #define TestAndAddFlag(Result, Flags, Flag) {\
  56.     if ( Flags & Flag ) \
  57.     { \
  58.         Result += TEXT(#Flag); \
  59.         Result += TEXT(" "); \
  60.     } \
  61. }
  62.  
  63. FString ObjectFlagsToString( EObjectFlags ObjectFlags )
  64. {
  65.     FString Result;
  66.  
  67.     // This first group of flags mostly has to do with what kind of object it is. Other than transient, these are the persistent object flags.
  68.     // The garbage collector also tends to look at these.
  69.     TestAndAddFlag(Result, ObjectFlags, RF_Public); ///< Object is visible outside its package.
  70.     TestAndAddFlag(Result, ObjectFlags, RF_Standalone); ///< Keep object around for editing even if unreferenced.
  71.     TestAndAddFlag(Result, ObjectFlags, RF_MarkAsNative);   ///< Object (UField) will be marked as native on construction (DO NOT USE THIS FLAG in HasAnyFlags() etc)
  72.     TestAndAddFlag(Result, ObjectFlags, RF_Transactional);  ///< Object is transactional.
  73.     TestAndAddFlag(Result, ObjectFlags, RF_ClassDefaultObject); ///< This object is its class's default object
  74.     TestAndAddFlag(Result, ObjectFlags, RF_ArchetypeObject);    ///< This object is a template for another object - treat like a class default object
  75.     TestAndAddFlag(Result, ObjectFlags, RF_Transient);  ///< Don't save object.
  76.  
  77.     // This group of flags is primarily concerned with garbage collection.
  78.     TestAndAddFlag(Result, ObjectFlags, RF_MarkAsRootSet);  ///< Object will be marked as root set on construction and not be garbage collected, even if unreferenced (DO NOT USE THIS FLAG in HasAnyFlags() etc)
  79.     TestAndAddFlag(Result, ObjectFlags, RF_TagGarbageTemp); ///< This is a temp user flag for various utilities that need to use the garbage collector. The garbage collector itself does not interpret it.
  80.  
  81.     // The group of flags tracks the stages of the lifetime of a uobject
  82.     TestAndAddFlag(Result, ObjectFlags, RF_NeedLoad);   ///< During load, indicates object needs loading.
  83.     TestAndAddFlag(Result, ObjectFlags, RF_NeedPostLoad);   ///< Object needs to be postloaded.
  84.     TestAndAddFlag(Result, ObjectFlags, RF_NeedPostLoadSubobjects); ///< During load, indicates that the object still needs to instance subobjects and fixup serialized component references
  85.     TestAndAddFlag(Result, ObjectFlags, RF_BeginDestroyed); ///< BeginDestroy has been called on the object.
  86.     TestAndAddFlag(Result, ObjectFlags, RF_FinishDestroyed);    ///< FinishDestroy has been called on the object.
  87.  
  88.     // Misc. Flags
  89.     TestAndAddFlag(Result, ObjectFlags, RF_BeingRegenerated);   ///< Flagged on UObjects that are used to create UClasses (e.g. Blueprints) while they are regenerating their UClass on load (See FLinkerLoad::CreateExport())
  90.     TestAndAddFlag(Result, ObjectFlags, RF_DefaultSubObject);   ///< Flagged on subobjects that are defaults
  91.     TestAndAddFlag(Result, ObjectFlags, RF_WasLoaded);  ///< Flagged on UObjects that were loaded
  92.     TestAndAddFlag(Result, ObjectFlags, RF_TextExportTransient);    ///< Do not export object to text form (e.g. copy/paste). Generally used for sub-objects that can be regenerated from data in their parent object.
  93.     TestAndAddFlag(Result, ObjectFlags, RF_LoadCompleted);  ///< Object has been completely serialized by linkerload at least once. DO NOT USE THIS FLAG, It should be replaced with RF_WasLoaded.
  94.     TestAndAddFlag(Result, ObjectFlags, RF_InheritableComponentTemplate); ///< Archetype of the object can be in its super class
  95.     TestAndAddFlag(Result, ObjectFlags, RF_StrongRefOnFrame);   ///< References to this object from persistent function frame are handled as strong ones.
  96.     TestAndAddFlag(Result, ObjectFlags, RF_Dynamic); //< Field Only. Dynamic field - doesn't get constructed during static initialization, can be constructed multiple times
  97.  
  98.     return Result;
  99. }
  100.  
  101. FString ClassFlagsToString( uint32 ClassFlags )
  102. {
  103.     FString Result;
  104.  
  105.     /** Class is abstract and can't be instantiated directly. */
  106.     TestAndAddFlag(Result, ClassFlags, CLASS_Abstract);
  107.     /** Save object configuration only to Default INIs, never to local INIs. Must be combined with CLASS_Config */
  108.     TestAndAddFlag(Result, ClassFlags, CLASS_DefaultConfig);
  109.     /** Load object configuration at construction time. */
  110.     TestAndAddFlag(Result, ClassFlags, CLASS_Config);
  111.     /** This object type can't be saved; null it out at save time. */
  112.     TestAndAddFlag(Result, ClassFlags, CLASS_Transient);
  113.     /** Successfully parsed. */
  114.     TestAndAddFlag(Result, ClassFlags, CLASS_Parsed);
  115.     /** */
  116.     //CLASS_                  = 0x00000020,
  117.     /** All the properties on the class are shown in the advanced section (which is hidden by default) unless SimpleDisplay is specified on the property */
  118.     TestAndAddFlag(Result, ClassFlags, CLASS_AdvancedDisplay);
  119.     /** Class is a native class - native interfaces will have CLASS_Native set, but not RF_MarkAsNative */
  120.     TestAndAddFlag(Result, ClassFlags, CLASS_Native);
  121.     /** Don't export to C++ header. */
  122.     TestAndAddFlag(Result, ClassFlags, CLASS_NoExport);
  123.     /** Do not allow users to create in the editor. */
  124.     TestAndAddFlag(Result, ClassFlags, CLASS_NotPlaceable);
  125.     /** Handle object configuration on a per-object basis, rather than per-class. */
  126.     TestAndAddFlag(Result, ClassFlags, CLASS_PerObjectConfig);
  127.    
  128.     /** pointers to this class default to weak. */
  129.     TestAndAddFlag(Result, ClassFlags, CLASS_PointersDefaultToWeak);
  130.    
  131.     /** Class can be constructed from editinline New button. */
  132.     TestAndAddFlag(Result, ClassFlags, CLASS_EditInlineNew);
  133.     /** Display properties in the editor without using categories. */
  134.     TestAndAddFlag(Result, ClassFlags, CLASS_CollapseCategories);
  135.     /** Class is an interface **/
  136.     TestAndAddFlag(Result, ClassFlags, CLASS_Interface);
  137.     /**  Do not export a constructor for this class, assuming it is in the cpptext **/
  138.     TestAndAddFlag(Result, ClassFlags, CLASS_CustomConstructor);
  139.     /** all properties and functions in this class are const and should be exported as const */
  140.     TestAndAddFlag(Result, ClassFlags, CLASS_Const);
  141.  
  142.     /** pointers to this class default to weak. */
  143.     TestAndAddFlag(Result, ClassFlags, CLASS_PointersDefaultToAutoWeak);
  144.    
  145.     /** Indicates that the class was created from blueprint source material */
  146.     TestAndAddFlag(Result, ClassFlags, CLASS_CompiledFromBlueprint);
  147.  
  148.     /** Indicates that only the bare minimum bits of this class should be DLL exported/imported */
  149.     TestAndAddFlag(Result, ClassFlags, CLASS_MinimalAPI);
  150.    
  151.     /** Indicates this class must be DLL exported/imported (along with all of it's members) */
  152.     TestAndAddFlag(Result, ClassFlags, CLASS_RequiredAPI);
  153.  
  154.     /** Indicates that references to this class default to instanced. Used to be subclasses of UComponent, but now can be any UObject */
  155.     TestAndAddFlag(Result, ClassFlags, CLASS_DefaultToInstanced);
  156.  
  157.     /** Indicates that the parent token stream has been merged with ours. */
  158.     TestAndAddFlag(Result, ClassFlags, CLASS_TokenStreamAssembled);
  159.     /** Class has component properties. */
  160.     TestAndAddFlag(Result, ClassFlags, CLASS_HasInstancedReference);
  161.     /** Don't show this class in the editor class browser or edit inline new menus. */
  162.     TestAndAddFlag(Result, ClassFlags, CLASS_Hidden);
  163.     /** Don't save objects of this class when serializing */
  164.     TestAndAddFlag(Result, ClassFlags, CLASS_Deprecated);
  165.     /** Class not shown in editor drop down for class selection */
  166.     TestAndAddFlag(Result, ClassFlags, CLASS_HideDropDown);
  167.     /** Class settings are saved to <AppData>/..../Blah.ini (as opposed to CLASS_DefaultConfig) */
  168.     TestAndAddFlag(Result, ClassFlags, CLASS_GlobalUserConfig);
  169.     /** Class was declared directly in C++ and has no boilerplate generated by UnrealHeaderTool */
  170.     TestAndAddFlag(Result, ClassFlags, CLASS_Intrinsic);
  171.     /** Class has already been constructed (maybe in a previous DLL version before hot-reload). */
  172.     TestAndAddFlag(Result, ClassFlags, CLASS_Constructed);
  173.     /** Indicates that object configuration will not check against ini base/defaults when serialized */
  174.     TestAndAddFlag(Result, ClassFlags, CLASS_ConfigDoNotCheckDefaults);
  175.     /** Class has been consigned to oblivion as part of a blueprint recompile, and a newer version currently exists. */
  176.     TestAndAddFlag(Result, ClassFlags, CLASS_NewerVersionExists);
  177.  
  178.     return Result;
  179. }
  180.  
  181. FString PropertyFlagsToString( uint64 PropertyFlags )
  182. {
  183.     FString Result;
  184.     TestAndAddFlag(Result, PropertyFlags, CPF_Edit);
  185.     TestAndAddFlag(Result, PropertyFlags, CPF_ConstParm);
  186.     TestAndAddFlag(Result, PropertyFlags, CPF_BlueprintVisible);
  187.     TestAndAddFlag(Result, PropertyFlags, CPF_ExportObject);
  188.     TestAndAddFlag(Result, PropertyFlags, CPF_BlueprintReadOnly);              
  189.     TestAndAddFlag(Result, PropertyFlags, CPF_Net);                            
  190.     TestAndAddFlag(Result, PropertyFlags, CPF_EditFixedSize);                  
  191.     TestAndAddFlag(Result, PropertyFlags, CPF_Parm);                           
  192.     TestAndAddFlag(Result, PropertyFlags, CPF_OutParm);                        
  193.     TestAndAddFlag(Result, PropertyFlags, CPF_ZeroConstructor);                
  194.     TestAndAddFlag(Result, PropertyFlags, CPF_ReturnParm);                     
  195.     TestAndAddFlag(Result, PropertyFlags, CPF_DisableEditOnTemplate);          
  196.     TestAndAddFlag(Result, PropertyFlags, CPF_Transient);                      
  197.     TestAndAddFlag(Result, PropertyFlags, CPF_Config);                         
  198.     TestAndAddFlag(Result, PropertyFlags, CPF_DisableEditOnInstance);          
  199.     TestAndAddFlag(Result, PropertyFlags, CPF_EditConst);                      
  200.     TestAndAddFlag(Result, PropertyFlags, CPF_GlobalConfig);                   
  201.     TestAndAddFlag(Result, PropertyFlags, CPF_InstancedReference);             
  202.     TestAndAddFlag(Result, PropertyFlags, CPF_DuplicateTransient);             
  203.     TestAndAddFlag(Result, PropertyFlags, CPF_SubobjectReference);             
  204.     TestAndAddFlag(Result, PropertyFlags, CPF_SaveGame);                       
  205.     TestAndAddFlag(Result, PropertyFlags, CPF_NoClear);                        
  206.     TestAndAddFlag(Result, PropertyFlags, CPF_ReferenceParm);                  
  207.     TestAndAddFlag(Result, PropertyFlags, CPF_BlueprintAssignable);            
  208.     TestAndAddFlag(Result, PropertyFlags, CPF_Deprecated);                     
  209.     TestAndAddFlag(Result, PropertyFlags, CPF_IsPlainOldData);
  210.     TestAndAddFlag(Result, PropertyFlags, CPF_RepSkip);
  211.     TestAndAddFlag(Result, PropertyFlags, CPF_RepNotify);
  212.     TestAndAddFlag(Result, PropertyFlags, CPF_Interp);
  213.     TestAndAddFlag(Result, PropertyFlags, CPF_NonTransactional);
  214.     TestAndAddFlag(Result, PropertyFlags, CPF_EditorOnly);
  215.     TestAndAddFlag(Result, PropertyFlags, CPF_NoDestructor);
  216.     TestAndAddFlag(Result, PropertyFlags, CPF_AutoWeak);
  217.     TestAndAddFlag(Result, PropertyFlags, CPF_ContainsInstancedReference);
  218.     TestAndAddFlag(Result, PropertyFlags, CPF_AssetRegistrySearchable);
  219.     TestAndAddFlag(Result, PropertyFlags, CPF_SimpleDisplay);
  220.     TestAndAddFlag(Result, PropertyFlags, CPF_AdvancedDisplay);
  221.     TestAndAddFlag(Result, PropertyFlags, CPF_Protected);
  222.     TestAndAddFlag(Result, PropertyFlags, CPF_BlueprintCallable);
  223.     TestAndAddFlag(Result, PropertyFlags, CPF_BlueprintAuthorityOnly);
  224.     TestAndAddFlag(Result, PropertyFlags, CPF_TextExportTransient);
  225.     TestAndAddFlag(Result, PropertyFlags, CPF_NonPIEDuplicateTransient);
  226.     TestAndAddFlag(Result, PropertyFlags, CPF_ExposeOnSpawn);
  227.     TestAndAddFlag(Result, PropertyFlags, CPF_PersistentInstance);
  228.     TestAndAddFlag(Result, PropertyFlags, CPF_UObjectWrapper);
  229.     TestAndAddFlag(Result, PropertyFlags, CPF_HasGetValueTypeHash);
  230.     TestAndAddFlag(Result, PropertyFlags, CPF_NativeAccessSpecifierPublic);
  231.     TestAndAddFlag(Result, PropertyFlags, CPF_NativeAccessSpecifierProtected);
  232.     TestAndAddFlag(Result, PropertyFlags, CPF_NativeAccessSpecifierPrivate);
  233.  
  234.     return Result;
  235. }
  236.  
  237.  
  238. void TraceObject( const UObject* Object, const FString& Title, const TArray<FName>& PropertyNamesToTrace, int32 TraceObjectFlags )
  239. {
  240.     // Object validity check
  241.     if ( !Object )
  242.     {
  243.         return;
  244.     }
  245.  
  246.     // Title
  247.     TraceNoCurLine( "%s [%s] : ", Title.IsEmpty() ? TEXT("TraceObject") : *Title, *Object->GetName() );
  248.  
  249.     // Trace object details
  250.     if ( TraceObjectFlags & TOF_OBJECT_DETAILS )
  251.     {
  252.         TraceNoCurLine( "  Object URL   : %s", *Object->GetFullName() );
  253.         TraceNoCurLine( "  Object Flags : %s", *ObjectFlagsToString( Object->GetFlags() ) );
  254.     }
  255.  
  256.     // Trace class
  257.     UClass* Class = Object->GetClass();
  258.     if ( Class && TraceObjectFlags & TOF_CLASS_DETAILS)
  259.     {
  260.         TArray<FString> ClassNames;
  261.         ClassNames.Add( Class->GetName() );
  262.         UClass* SuperClass = Class->GetSuperClass();
  263.         while (SuperClass)
  264.         {
  265.             ClassNames.Insert( SuperClass->GetName(), 0 );
  266.             SuperClass = SuperClass->GetSuperClass();
  267.         }
  268.  
  269.         TraceNoCurLine( "  Class URL      : %s", *Class->GetFullName() );
  270.         TraceNoCurLine( "  Class Flags    : %s", *ClassFlagsToString(Class->GetClassFlags()) );
  271.         TraceNoCurLine( "  Class Hierarchy: %s", *FString::Join( ClassNames, TEXT("->") ) );
  272.     }
  273.  
  274.     // Trace property
  275.     if ( PropertyNamesToTrace.Num() > 0 )
  276.     {
  277.         for ( const FName& PropertyName : PropertyNamesToTrace )
  278.         {
  279.             const void* ObjectPtr = reinterpret_cast<const void *>( Object );
  280.  
  281.             UProperty* Property = Class->FindPropertyByName(PropertyName);
  282.             if ( !Property )
  283.             {
  284.                 TraceNoCurLine("    (no property with name : '%s')", *PropertyName.ToString() );
  285.                 continue;
  286.             }
  287.            
  288.             uint64 PropertyFlags = Property->GetPropertyFlags();
  289.  
  290.             FString PropertyValueString;
  291.             const void* PropertyValuePtr = Property->ContainerPtrToValuePtr<const void*>( ObjectPtr );
  292.             Property->ExportTextItem( PropertyValueString, PropertyValuePtr, nullptr, nullptr, PPF_None );
  293.            
  294.             if ( TraceObjectFlags & TOF_PROPERTY_DETAILS )
  295.             {
  296.                 TraceNoCurLine( "  Property : %s", *PropertyName.ToString() );
  297.                 TraceNoCurLine( "    URL    : %s", *Property->GetFullName() );
  298.                 TraceNoCurLine( "    Flags  : %s", *PropertyFlagsToString( Property->GetPropertyFlags() ) );
  299.                 TraceNoCurLine( "    Value  : %s", *PropertyValueString );
  300.             }
  301.             else
  302.             {
  303.                 TraceNoCurLine( "    %s = %s", *PropertyName.ToString(), *PropertyValueString );
  304.             }          
  305.         }
  306.     }
  307. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement