--- title: Unreal Engine tips and tricks tags: engine description: Unreal Engine tips and tricks breaks: false --- <style>.markdown-body { max-width: 1200px; }</style> <!-- {%hackmd theme-dark %} --> # Unreal Engine [TOC] # Paths ## Windows - https://nerivec.github.io/old-ue4-wiki/pages/packaged-game-paths-obtain-directories-based-on-executable-location.html **Shipping**: ``` c:\Users\%USERNAME%\AppData\Local\<Project Name>\Saved\ ``` ## Mac **Config:** ``` ~/Library/Preferences/Unreal Engine/ ~/Library/Preferences/<packaged project name>/ ``` **Logs:** ``` ~/Library/Logs/Unreal Engine/ ~/Library/Logs/<packaged project name>/ ``` **Save games/Rest:** ``` ~/Library/Application Support/Epic/ ``` **Crashes:** ``` ~/Library/Application Support/Epic/UnrealEngine/<Engine Version>/Saved/Crashes ``` # [Advanced Debugging in Unreal Engine](https://dev.epicgames.com/community/learning/tutorials/dXl5/advanced-debugging-in-unreal-engine) # USTRUCT/UCLASS/UFUNCTION/UPARAM/UPROPERTY - [USTRUCT](https://benui.ca/unreal/ustruct/) - [UCLASS](https://benui.ca/unreal/uclass/) - [UFUNCTION](https://benui.ca/unreal/ufunction/) - [UPARAM](https://benui.ca/unreal/uparam/) - [UPROPERTY](https://benui.ca/unreal/uproperty/) # [UMG](https://docs.unrealengine.com/en-US/Engine/UMG/index.html) Resourcces: - http://benhumphreys.ca/unreal/ - [A Compendium Information Guide for UMG and Slate in Unreal Engine.](https://github.com/YawLighthouse/UMG-Slate-Compendium#table-of-contents) # [GPU](https://docs.unrealengine.com/en-US/Engine/Performance/GPU) # [CPU](https://docs.unrealengine.com/en-us/Engine/Performance/CPU) # [Configuration Files](https://docs.unrealengine.com/en-US/Programming/Basics/ConfigurationFiles/#filehierarchy) The configuration file hierarchy is read in starting with `Base.ini`, with values in later files in the hierarchy overriding earlier values. All files in the Engine folder will be applied to all projects, while project-specific settings should be in files in the project directory. Finally, all project-specific and platform-specific differences are saved out to `[ProjectDirectory]/Saved/Config/[Platform]/[Category].ini` The below file hierarchy example is for the Engine category of configuration files. 1. `Engine/Config/Base.ini` Base.ini is usually empty. 2. `Engine/Config/BaseEngine.ini` 3. `Engine/Config/[Platform]/[Platform]Engine.ini` 4. `[ProjectDirectory]/Config/DefaultEngine.ini` 5. `[ProjectDirectory]/Config/[Platform]/[Platform]Engine.ini` 6. `[ProjectDirectory]/Saved/Config/[Platform]/Engine.ini` The configuration file in the Saved directory only stores the project-specific and platform-specific differences in the stack of configuration files. ## Complete hierarchy ```cpp // Possible entries in a config hierarchy enum class EConfigFileHierarchy : uint8 { // Engine/Config/Base.ini AbsoluteBase = 0, // Engine/Config/*.ini EngineDirBase, // Engine/Config/Platform/BasePlatform* ini EngineDir_BasePlatformParent, EngineDir_BasePlatform, // Engine/Config/NotForLicensees/*.ini EngineDirBase_NotForLicensees, // Engine/Config/NoRedist/*.ini -Not supported at this time. EngineDirBase_NoRedist, // Game/Config/*.ini GameDirDefault, // Game/Config/DedicatedServer*.ini GameDirDedicatedServer, // Game/Config/NotForLicensees/*.ini GameDirDefault_NotForLicensees, // Game/Config/NoRedist*.ini GameDirDefault_NoRedist, // Engine/Config/PlatformName/PlatformName*.ini EngineDir_PlatformParent, EngineDir_Platform, // Engine/Config/NotForLicensees/PlatformName/PlatformName*.ini EngineDir_PlatformParent_NotForLicensees, EngineDir_Platform_NotForLicensees, // Engine/Config/NoRedist/PlatformName/PlatformName*.ini EngineDir_PlatformParent_NoRedist, EngineDir_Platform_NoRedist, // Game/Config/PlatformName/PlatformName*.ini GameDir_PlatformParent, GameDir_Platform, // Game/Config/NotForLicensees/PlatformName/PlatformName*.ini GameDir_PlatformParent_NotForLicensees, GameDir_Platform_NotForLicensees, // Game/Config/NoRedist/PlatformName/PlatformName*.ini GameDir_PlatformParent_NoRedist, GameDir_Platform_NoRedist, // <UserSettingsDir|AppData>/Unreal Engine/Engine/Config/User*.ini UserSettingsDir_EngineDir_User, // <UserDir|Documents>/Unreal Engine/Engine/Config/User*.ini UserDir_User, // Game/Config/User*.ini GameDir_User, // Number of config files in hierarchy. NumHierarchyFiles, }; ``` # [In game console commands](https://digilander.libero.it/ZioYuri78/) What is a Console Variable? [See Docs](https://docs.unrealengine.com/en-US/Programming/Development/Tools/ConsoleManager/#whatisaconsolevariable?) ## [Priority](https://docs.unrealengine.com/en-US/API/Runtime/Core/HAL/EConsoleVariableFlags/index.html) Priority for console commands from lower to higher goes like this: 1. [`SetByConstructor`](#constructor) - When created, default 2. [`SetByScalability`](#Scalability-Config) - From `Scalability.ini` (lower priority than game settings so it's easier to override partially) 3. [`SetByGameSetting`](#Game-Settings) - This is usually set from your Game Settings In Game UI or from a file 4. [`SetByProjectSetting`](#Project-Settings) - Project settings (editor UI or from file, higher priority than game setting to allow to enforce some setting for this project) 5. [`SetByDeviceProfile`](#Device-Profiles) - Per device setting in `DeviceProfiles.ini` (e.g. specific iOS device, higher priority than per project to do device specific settings). 6. [`SetByConsoleVariablesIni`](#Console-Variables-Config) - `Consolevariables.ini` (for multiple projects) set in `Engine/Config` 7. [`SetByCommandline`](#Command-Line) - A minus command e.g. -VSync (very high priority to enforce the setting for the application) 8. [`SetByCode`](#Code) - Least useful, likely a hack, maybe better to find the correct SetBy... 9. [`SetByConsole`](#Console) - Editor UI or console in game or editor ## Constructor See [Creating / Registering a Console Variable](https://docs.unrealengine.com/en-US/Programming/Development/Tools/ConsoleManager/#creating/registeringaconsolevariable) Basically `ECVF_SetByConstructor === ECVF_Default`. Example: ```cpp static TAutoConsoleVariable<int32> CVarNormalMaps( TEXT("r.NormalMapsForStaticLighting"), 0, TEXT("Whether to allow any static lighting to use normal maps for lighting computations."), ECVF_Default ); ``` ## Scalability Config From `Scalability.ini` (lower priority than game settings so it’s easier to override partially). Example: ```ini [ViewDistanceQuality@0] r.SkeletalMeshLODBias=2 r.ViewDistanceScale=0.4 [ViewDistanceQuality@1] r.SkeletalMeshLODBias=1 r.ViewDistanceScale=0.6 ``` ## Game Settings This is usually set from your Game Settings In Game UI or from a file. The config is usually kept inside `GameUserSettings.ini` and see the contents of `UGameUserSettings`. Examples of console variables that might be set by the game user settings: ```ini r.FullScreenMode r.VSync r.HDR.EnableHDROutput ``` ## Project Settings ## Console Variables Config NOTE: Engine Only ## Command Line ## Code ## Device Profiles These console commands can be set in the `DeviceProfiles.ini` file. Example: ```ini [Android DeviceProfile] DeviceType=Android BaseProfileName= +CVars=r.MobileContentScaleFactor=1 +CVars=r.BloomQuality=0 +CVars=r.DepthOfFieldQuality=0 +CVars=r.LightShaftQuality=0 +CVars=r.RefractionQuality=0 +CVars=r.ShadowQuality=2 +CVars=slate.AbsoluteIndices=1 +CVars=r.Vulkan.DelayAcquireBackBuffer=0 +CVars=r.Vulkan.RobustBufferAccess=1 +CVars=r.Vulkan.DescriptorSetLayoutMode=2 ``` ## Console `` (back tick) ` `` - Open the developer console. This is the highest priority you can set for commands. ```markdown # View modes viewmode <mode> // Where <mode> can be: BrushWireframe - wireframes with brushes (crashes at runtime) Wireframe - wireframes with BSP (crashes at runtime) Unlit - unlit Lit - lit Lit_DetailLighting - lit + detaillighting LightingOnly - lit without materials LightComplexity - colored according to light count ShaderComplexity - colored according to shader complexity LightmapDensity - colored according to world-space LightMap texture density // Colored according to light count LitLightmapDensity ReflectionOverride VisualizeBuffer StationaryLightOverlap - Colored according to stationary light overlap // collision CollisionPawn CollisionVisibility LODColoration - Colored according to the current LOD index QuadOverdraw - Colored according to the quad coverage PrimitiveDistanceAccuracy - Visualize the accuracy of the primitive distance computed for texture streaming MeshUVDensityAccuracy - Visualize the accuracy of the mesh UV densities computed for texture streaming ShaderComplexityWithQuadOverdraw - Colored according to shader complexity, including quad overdraw HLODColoration - Colored according to the current HLOD index GroupLODColoration - Group item for LOD and HLOD coloration MaterialTextureScaleAccuracy - Visualize the accuracy of the material texture scales used for texture streaming RequiredTextureResolution - Compare the required texture resolution to the actual resolution ShowFlag.Bones 1 - shows bones of all stuff that has bones ShowFlag.StationaryLightOverlap 1 - shows the overlap of stationary ligths ShowFlag.Bounds 1 - shows all bounds # Debug debug rendercrash | rendergpf - Crash the renderer debug rendercheck - Crash the renderthread via check(0) at your request debug renderensure - Crash by ensure() condition inside the renderer debug threadcrash - Crash inside worker thread via UE_LOG(Fatal) debug threadcheck - Crash worker thread via check() debug threadgpf - Crash worker thread via invalid memomory assigment debug twothreadcrash - Crash two threads at once via UE_LOG(Fatal) debug twothreadgpf - Crash two threads at once via invalid memomory assigment debug threadensure - Crash worker thread via ensure() debug threadfatal - Crash thread via LowLevelFatalError() debug crash - Crash game via UE_LOG(Fatal) debug check - Crash game via check() debug gpf - Crash game via invalid memomory assigment debug ensure - Crash game via ensure() debug fatal - Crash game via LowLevelFatalError() debug bufferoverrun - Crash via buffer overflow debug crtinvalid - Crash via invalid cast debug eatmem - Fills up all your computer memory debug recurse - Crash via infinite recursion debug threadrecurse - Crash via infinite recursion in a separate thread debug stackoverflow - Crash via stack overflow via infinite recursion debug threadstackoverflow - Crash via stack overflow in a separate thread debug hitch - Hitch the game for 1 second debug renderhitch - Hith the render for 1 second debug softlock - Hands the current thread debug infiniteloop - Hang the CPU forever (infinite loop) debug sleep - Sleep for 1 hour. This should crash after a few seconds in cooked builds. debug audiogpf - Crash auto thread via invalid memomory assigment debug audiocheck - Crash audio thread via check() # Choose graphics card r.GraphicsAdapter - User request to pick a specific graphics adapter (e.g. when using a integrated graphics card with a discrete one) D3D12.GraphicsAdapter - User request to pick a specific graphics adapter (e.g. when using a integrated graphics card with a discrete one) # Other WidgetReflector - opens up the widget reflector (works even in non editor builds) ``` # [Command line arguments](https://docs.unrealengine.com/en-us/Programming/Basics/CommandLineArguments) - https://benui.ca/unreal/command-line-arguments/ When running the game you can append these arguments: ```bash -Windowed - run in windowed mode -FullScreen - run in full screen mode -ForceRes - force the resolution -ResX= | -ResY= - set the X and Y resolution -WinX= | -WinY= - set the position of the game window in X/Y coordinates -SaveWinPos - saves the window position into the game user settings file -Seconds - set the maximum tick time -Verbose - set compiler to use verbose output. -VerifyGC | -NoVerifyGC - enables/disable garbage collection verification every 30s -StatNamedEvents - enable named stat events -LoadTimeStats - enable load time stats, shortcut for some stat gorup commands -LoadTimeFile - enable load time stats to a file, shortcut for some stat gorup commands -LogThreadedParticleTicking - log the thread of the particles ticking -VerifyDDC - verifies the derived data cache (https://docs.unrealengine.com/en-us/Engine/Basics/DerivedDataCache) -Debug - running in debug -NoAmbientActors - mute ambient sound actors -HDR | -NoHDR - enables/disables HDR -CleanCrashReports - clean the crash reports -CrashForUAT - write UAT markers on crash -NotInstalled - similar to NotInstalledEngine -Installed - similar to InstalledEngine -NotInstalledEngine - tells it that the engine is not installed -InstalledEngine - tells that the engine is installed -WaitForDebugger - if was specified, halt startup and wait for a debugger to attach before continuing -PromptRemoteDebug - Prompt Remote Debug -SlateDebug - create slate test windows -ScriptStackOnWarnings - Show blueprint script stack for warnings, same config in Engine.ini -EnableSound | -NoSound - enables/disables sound -VSync | -NoVSync - enables/disables vsync -OneThread - runs with only one thread instead of multi-threading -Threading - enables threading -NoThreading - disables threading -NoThreadTimeout - stop hang detection -NoConsole - disables console ouput -No<OnlineSubsystemName> - disables the <OnlineSubsystemName> -NoTextureStreaming - disable texture streaming. Highest quality textures are always loaded. -NoSplash - Disable use of splash image when loading the game. -CmdLineFile=<cmd.txt> - Only in Non Shipping and Editor. File to give to the executable with command line arguments -Exec=<exec_file.txt> - Executes the specified exec file. -ExecCmds="command1; command2;" - Executes deffered commands -bForceSmokeTests - forces the smoke tests? -Log - show the log -Silent - disables output and feedback -WarningsAsErrors - treat warnings as errors -ForceLogFlush - force a log flus after each line -LogTimes - display the log times in UTC format ELogTimes::UTC -UTCLogTimes - same as LogTimes -NoLogTimes - disable the log times -LocalLogTimes - display the log times in local time format ELogTimes::Local -LogTimeCode - display the log times as timecode -stdout - Enables the stdout device -FullStdOutLogOutput - Display all log levels to stdout -AllowStdOutLogVerbosity = display only ELogVerbosity::Log to stdout -NoScreenMessage - disables the screen messages -NoLoadingScreen - disables the PreLoadingScreen on windows in non shipping builds -NoEpicPortal - disables some parts of the epic games launcher (NOTE does not seem to disable it completly) -EnableAllPlugins - enables all the plugins -ExceptPlugins=<comma separated list> - used in conjuction with -EnableAllPlugins -NoEnginePlugins - disable all the engine plugins -Benchmark -FPS=<int> - Used with the benchmark command, fixed delta time # Curl -NoReuseConn - don't reuse connections -NoTimeouts - don't use timeouts I guess # Linux -UseHyperThreading - enables the use of hyperthreading on linux -WaitAndForkRequireResponse - wait for forks (fork()) # Steam -NoSteam - set steamworks to not be used. # OpenGl/Vulkan -OpenglDebug - debug opengl -Opengl4 - force with opengl 4 -Opengl3 - force with opengl 3 -Opengl - run with opengl -Vulkan - run with vulkan # DirectX -dxdebug | -d3debug | d3ddebug - use a debug device -d3dbreakonwarning - breaks on warning, debug -d3d10 | -dx10 | -sm4 - use directx 10 (default is directx 11) -d3d11 | -dx11 - use directx 11 -d3d12 | -dx12 - use directx 12 -novendordevice - apparently only AMD and directx 11 -AllowSoftwareRendering - allow to use software rendering fallback -PreferAMD - use AMD card -PreferIntel - use Intel card -PreferNvidia - use Nvidia card ``` # [Logs](https://michaeljcole.github.io/wiki.unrealengine.com/Logs,_Printing_Messages_To_Yourself_During_Runtime/) ## [Project logs](https://michaeljcole.github.io/wiki.unrealengine.com/Locating_Project_Logs/) ## [Logging in Shipping Builds](https://stefanperales.com/blog/ue4-quick-tip-logging-in-shipping-builds/) Used by multiple files: ```cpp // inside header DECLARE_LOG_CATEGORY_EXTERN(CategoryName, DefaultVerbosity, CompileTimeVerbosity); // inside cpp DEFINE_LOG_CATEGORY(CategoryName); ``` Used in only one file, `static` log: ```cpp // inside cpp DEFINE_LOG_CATEGORY_STATIC(CategoryName, DefaultVerbosity, CompileTimeVerbosity); ``` Where: - `CategoryName` - is simply the name for the new category you are defining. - `DefaultVerbosity` - is the verbosity level used when one is not specified in the ini files or on the command line. Anything more verbose than this will not be logged. - `CompileTimeVerbosity` - is the maximum verbosity to compile in the code. Anything more verbose than this will not be compiled. Examples: ```cpp // Inside header DECLARE_LOG_CATEGORY_EXTERN(LogMyGame, All, All); // inside cpp DEFINE_LOG_CATEGORY(LogMyGame); // or static used only inside this cpp file DEFINE_LOG_CATEGORY_STATIC(LogUsedOnlyInsideCPP, All, All); ``` # JSON NOTE: There is an issue with this serializer where in editor it converts the field to `Field` but in packaged game it converts the field to `field`. ```cpp #include "IStructSerializerBackend.h" #include "StructSerializer.h" #include "StructDeserializer.h" #include "Backends/JsonStructDeserializerBackend.h" #include "Serialization/BufferArchive.h" #include "Serialization/BufferWriter.h" #include "Backends/JsonStructSerializerBackend.h" // Serializes a given USTRUCT to a JSON string using the default policy. // @return A string holding the serialized object in JSON format template<typename StructType> static void SerializeToJSON(const StructType& Struct, FString& OutString) { SerializeToJSON(&Struct, *Struct.StaticStruct(), OutString); } static void SerializeToJSON(const void* Struct, UStruct& TypeInfo, FString& OutString) { // Read into this FBufferArchive BufferArchive; // Save to JSON const EStructSerializerBackendFlags SerializerFlags = EStructSerializerBackendFlags::Default; FStructSerializerPolicies SerializerPolicies; FJsonStructSerializerBackend Backend(BufferArchive, SerializerFlags); FStructSerializer::Serialize(Struct, TypeInfo, Backend, SerializerPolicies); if (BufferArchive.TotalSize() == 0) { return; } // Add string terminator // NOTE: we need two zeros here otherwise the conversion to string will not be right BufferArchive.Add(0); BufferArchive.Add(0); // Convert to String OutString = FString((TCHAR*)BufferArchive.GetData()); } // Deserializes a given JSON String into a specific struct // @return true if it could deserialize the json string into the struct template<typename StructType> static bool DeserializeFromJSON(const FString& JSONString, StructType& OutStruct) { return DeserializeFromJSON(JSONString, &OutStruct, *StructType::StaticStruct()); } static bool DeserializeFromJSON(const FString& JSONString, void* OutStruct, UStruct& TypeInfo) { // Read from this const bool bInFreeOnClose = false; const bool bIsPersistent = false; FBufferReader BufferReader((void*)*JSONString, JSONString.Len() * sizeof(TCHAR), bInFreeOnClose, bIsPersistent); // Load from JSON FJsonStructDeserializerBackend Backend(BufferReader); FStructDeserializerPolicies DeserializerPolicies; DeserializerPolicies.MissingFields = EStructDeserializerErrorPolicies::Warning; return FStructDeserializer::Deserialize(OutStruct, TypeInfo, Backend, DeserializerPolicies); } ``` # [Performance and profiling](https://docs.unrealengine.com/en-us/Engine/Performance) Resources: - https://docs.unrealengine.com/en-us/Engine/Performance >>> NOTE: that enabling any stats for live viewing affects the game thread performance >>> ## [Stat commands](https://docs.unrealengine.com/en-us/Engine/Performance/StatCommands) >>> NOTE: To open the `*.ue4stats` file use the [SessionFrontend Profiler Tab](https://docs.unrealengine.com/en-US/Engine/Performance/Profiler/index.html) >>> ``` stat <Category> // Most useful categories stat Unit - Overall frame time as well as the game thread, rendering thread, and GPU times. stat UnitGraph - To see a graph with the stat unit data // But to start/stop recording in packaged game // The stats file is located inide [UE4ProjectFolder]\[ProjectName]\Saved\Profiling\UnrealStats. // Open the *.ue4stats file with the SessionFrontend from unreal. stat StartFile - Starts a statistics capture, creating a new file in the Profiling directory. stat StopFile - Finishes statistics capture that was started by the stat StartFile command, closing the file that was created in the Profiling directory. ``` ### Memory profiling https://pzurita.wordpress.com/2015/02/10/limitations-of-memory-tracking-features-in-unreal-engine-4/ ### Adding own stat categories in C++ See whole docs in [`Runtime/Core/Public/Stats/Stats.h`](https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Source/Runtime/Core/Public/Stats/Stats.h) Stats system in the UE4 supports following stats types: - `Cycle Counter` - a generic cycle counter used to counting the number of cycles during the lifetime of the object - `Float/Dword Counter` - a counter that is cleared every frame - `Float/Dword Accumulator` - a counter that is not cleared every frame, persistent stat, but it can be reset - `Memory` - a special type of counter that is optimized for memory tracking Each stat needs to be grouped, this usually corresponds with displaying the specified stat group i.e. 'stat statsystem' which displays stats' related data. To define a stat group you need to use one of the following methods: - `DECLARE_STATS_GROUP(GroupDesc, GroupId, GroupCat)` - declares a stats group which is enabled by default - `DECLARE_STATS_GROUP_VERBOSE(GroupDesc, GroupId ,GroupCat)` - declares a stats group which is disabled by default - `DECLARE_STATS_GROUP_MAYBE_COMPILED_OUT(GroupDesc, GroupId, GroupCat)` - declares a stats group which is disabled by default and may be stripped by the compiler where - `GroupDesc` is a text description of the group - `GroupId` is an UNIQUE id of the group - `GroupCat` is reserved for future use - `CompileIn` if set to true, the compiler may strip it out Example: ```cpp DECLARE_STATS_GROUP(TEXT("Threading"), STATGROUP_Threading, STATCAT_Advanced); ``` Now, you can declare/define a stat. A stat can be used only in one cpp file, in the function scope, in the module scope or can be used in the whole project. For one file scope you need to use one of the following methods depending on the stat type. - `DECLARE_CYCLE_STAT(CounterName, StatId, GroupId)` - declares a cycle counter stat - `DECLARE_SCOPE_CYCLE_COUNTER(CounterName, StatId, GroupId)` - declares a cycle counter stat and uses it at the same time, it is limited to one function scope - `QUICK_SCOPE_CYCLE_COUNTER(StatId)` - declares a cycle counter stat that will belong to stat group called 'Quick' where - `CounterName` is a text description of the stat - `StatId` is an UNIQUE id of the stat - `GroupId` is an id of the group that the stat will belong to, the GroupId from DECLARE_STATS_GROUP* - `Pool` is a platform specific memory pool, more details later - `API` is the *_API of module, can be empty if the stat will be used only in that module Example: ```cpp // Declare the stat grup in the header of the file or at the top of the cpp file DECLARE_STATS_GROUP(TEXT("Threading"), STATGROUP_Threading, STATCAT_Advanced); // You can declare the stat counter at the top of the file as the category like this DECLARE_CYCLE_STAT(TEXT("Threading Test"), STAT_ThreadingTest, STATGROUP_Threading); // In the cpp file Class::Method() { SCOPE_CYCLE_COUNTER(STAT_ThreadingTest); // OR // You can declare and use in the same function with DECLARE_SCOPE_CYCLE_COUNTER(TEXT("Threading Test"), STAT_ThreadingTest, STATGROUP_Threading); } ``` # Debugging ## Useful development `` (back tick) ` `` - Open the developer console. ` (apostrophe) ' ` - Open the gameplay debugger ` F1 - F5 ` - change different view modes Open the WidgetReflector - type in the developer console `WidgetReflector` ## Blueprints - `FFrame::KismetExecutionMessage` - `FMessageLog` - `FBlueprintCoreDelegates::ThrowScriptException` - `FScriptStackTracker` ## C++ - `FStackTracker` - `FDebug::DumpStackTraceToLog(VerbosityLevel)` ## Crashes NOTE: To create a fake crash, type this into the console in game: `debug crash` NOTE: To force log callstacks you can add `-ForceLogCallstacks` to the command line. Steps: 1. Go to `Saved/Crashes/<Crash Folder>` 2. You can ignore the log file from the `Crashes` folder as it is not complete, check instead `Saved/Logs/<Log file>` this will have the call stack at the end. 3. Open the project in Visual Studio then open the `UE4Minidump.dmp` file. 4. Start debugging it via clicking on `Debug with Native Only` ## .dmp files NOTE: if you built the pdb file in another day than the exe was built, use this tool https://web.archive.org/web/20210205095232/https://www.debuginfo.com/tools/chkmatch.html ``` chkmatch -c .\Game-Win64-Shipping.exe .\Game-Win64-Shipping.pdb chkmatch -m .\Game-Win64-Shipping.exe .\Game-Win64-Shipping.pdb ``` ### Visual studio 1. Open the .dmp file inside VS 2. ![](https://i.imgur.com/eNqmRgt.png) Set the pdb/exe file path. 3. Run the file ### WinDBG - https://docs.microsoft.com/en-us/visualstudio/profiling/how-to-specify-symbol-file-locations-from-the-command-line?view=vs-2017 - https://stackoverflow.com/questions/30019889/how-to-set-up-symbols-in-windbg 1. Open the .dmp file inside VS 2. Add the the debug files to the sympath `.sympath+ c:\dev\illuvium\game-client\Packaged\RELEASE-Illuvium-PrivateBeta1-Win_24_May_2022\Illuvium\Binaries\Win64\` 3. `.reload` # Customize Structs - [Custom Struct Serialization for Networking in Unreal Engine](http://www.aclockworkberry.com/custom-struct-serialization-for-networking-in-unreal-engine/) From `Runtime/CoreUObject/Private/UObject/Class.cpp` ```cpp // sample of how to customize structs USTRUCT() struct ENGINE_API FTestStruct { GENERATED_USTRUCT_BODY() TMap<int32, double> Doubles; FTestStruct() { Doubles.Add(1, 1.5); Doubles.Add(2, 2.5); } void AddStructReferencedObjects(class FReferenceCollector& Collector) const { Collector.AddReferencedObject(AActor::StaticClass()); } bool Serialize(FArchive& Ar) { Ar << Doubles; return true; } bool operator==(FTestStruct const& Other) const { if (Doubles.Num() != Other.Doubles.Num()) { return false; } for (TMap<int32, double>::TConstIterator It(Doubles); It; ++It) { double const* OtherVal = Other.Doubles.Find(It.Key()); if (!OtherVal || *OtherVal != It.Value() ) { return false; } } return true; } bool Identical(FTestStruct const& Other, uint32 PortFlags) const { return (*this) == Other; } void operator=(FTestStruct const& Other) { Doubles.Empty(Other.Doubles.Num()); for (TMap<int32, double>::TConstIterator It(Other.Doubles); It; ++It) { Doubles.Add(It.Key(), It.Value()); } } bool ExportTextItem(FString& ValueStr, FTestStruct const& DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope) const { ValueStr += TEXT("("); for (TMap<int32, double>::TConstIterator It(Doubles); It; ++It) { ValueStr += FString::Printf( TEXT("(%d,%f)"),It.Key(), It.Value()); } ValueStr += TEXT(")"); return true; } bool ImportTextItem( const TCHAR*& Buffer, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText ) { check(*Buffer == TEXT('(')); Buffer++; Doubles.Empty(); while (1) { const TCHAR* Start = Buffer; while (*Buffer && *Buffer != TEXT(',')) { if (*Buffer == TEXT(')')) { break; } Buffer++; } if (*Buffer == TEXT(')')) { break; } int32 Key = FCString::Atoi(Start); if (*Buffer) { Buffer++; } Start = Buffer; while (*Buffer && *Buffer != TEXT(')')) { Buffer++; } double Value = FCString::Atod(Start); if (*Buffer) { Buffer++; } Doubles.Add(Key, Value); } if (*Buffer) { Buffer++; } return true; } bool SerializeFromMismatchedTag(struct FPropertyTag const& Tag, FArchive& Ar) { // no example of this provided, doesn't make sense return false; } }; template<> struct TStructOpsTypeTraits<FTestStruct> : public TStructOpsTypeTraitsBase2<FTestStruct> { enum { WithZeroConstructor = true, WithSerializer = true, WithPostSerialize = true, WithCopy = true, WithIdenticalViaEquality = true, //WithIdentical = true, WithExportTextItem = true, WithImportTextItem = true, WithAddStructReferencedObjects = true, WithSerializeFromMismatchedTag = true, }; }; ```