HotReload
HotReload
#Overview
name: HotReload
This variable is created as a Console Variable (cvar).
- type:
Exec
- help:
Sorry: Exec commands have no help
It is referenced in 30
C++ source files.
#Summary
#Usage in the C++ source code
The purpose of HotReload is to provide functionality for recompiling and reloading modules at runtime in Unreal Engine, allowing developers to make code changes without fully restarting the engine or editor.
HotReload is primarily used by the Unreal Engine editor and development tools. It is part of the core engine functionality and is utilized by various subsystems and plugins, including:
- The Editor
- GameplayAbilities system
- ReplicationGraph
- StageMonitoring for Virtual Production
- UnrealEd (Unreal Editor)
The value of this variable is typically set internally by the HotReload module. It’s not directly set by developers but is used to control and manage the hot reload process.
HotReload interacts with several other systems and variables, including:
- GIsHotReload (deprecated in UE5)
- EActiveReloadType
- GActiveReloadInterface
Developers should be aware of the following when working with HotReload:
- It’s primarily intended for development and editor use, not for shipping builds.
- Hot reloading can sometimes lead to unexpected behavior if not handled properly.
- Not all code changes can be hot reloaded; some may require a full engine restart.
Best practices when using HotReload include:
- Use it primarily during development and testing phases.
- Be cautious when hot reloading core engine modules or critical game systems.
- Always test thoroughly after a hot reload to ensure no unexpected side effects.
- Be aware of the limitations of hot reloading and be prepared to do a full engine restart for significant code changes.
- Use the provided interfaces and methods (like RebindPackages) rather than trying to manually manage the hot reload process.
#References in C++ code
#Callsites
This variable is referenced in the following C++ source code:
#Loc: <Workspace>/Engine/Plugins/Editor/EditorDebugTools/Source/EditorDebugTools/Private/SModuleUI.cpp:252
Scope (from outer to inner):
file
function FReply SModuleUI::FModuleListItem::OnRecompileClicked
Source code excerpt:
GWarn->BeginSlowTask( FText::Format( NSLOCTEXT("ModuleUI", "Recompile_SlowTaskName", "Compiling {ModuleName}..."), Args ), bShowProgressDialog, bShowCancelButton );
// Does the module have any UObject classes in it? If so we'll use HotReload to recompile it.
FModuleStatus ModuleStatus;
if( ensure( FModuleManager::Get().QueryModule( ModuleName, ModuleStatus ) ) )
{
//@todo This is for content-only packages that show up in the
// Module UI... don't crash when recompile is clicked
if (FPaths::IsProjectFilePathSet())
#Loc: <Workspace>/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilitiesEditor/Private/GameplayAbilitiesEditorModule.cpp:390
Scope (from outer to inner):
file
function void RecompileGameplayAbilitiesEditor
Source code excerpt:
GWarn->BeginSlowTask( NSLOCTEXT("GameplayAbilities", "BeginRecompileGameplayAbilitiesTask", "Recompiling GameplayAbilitiesEditor Module..."), true);
IHotReloadInterface* HotReload = IHotReloadInterface::GetPtr();
if(HotReload != nullptr)
{
TArray< UPackage* > PackagesToRebind;
UPackage* Package = FindPackage( NULL, TEXT("/Script/GameplayAbilitiesEditor"));
if( Package != NULL )
{
PackagesToRebind.Add( Package );
}
HotReload->RebindPackages(PackagesToRebind, EHotReloadFlags::WaitForCompletion, *GLog);
}
GWarn->EndSlowTask();
}
FAutoConsoleCommand RecompileGameplayAbilitiesEditorCommand(
#Loc: <Workspace>/Engine/Plugins/Runtime/ReplicationGraph/Source/Private/ReplicationGraphModule.cpp:13
Scope (from outer to inner):
file
function void RecompileReplicationGraph
Source code excerpt:
GWarn->BeginSlowTask( FText::FromString(TEXT("Recompiling rep graph")), true);
IHotReloadInterface* HotReload = IHotReloadInterface::GetPtr();
if(HotReload != nullptr)
{
TArray< UPackage* > PackagesToRebind;
UPackage* Package = FindPackage( NULL, TEXT("/Script/ReplicationGraph"));
if( Package != NULL )
{
PackagesToRebind.Add( Package );
}
HotReload->RebindPackages(PackagesToRebind, EHotReloadFlags::WaitForCompletion, *GLog);
}
GWarn->EndSlowTask();
}
FAutoConsoleCommand RecompileReplicationGraphCmd( TEXT("ReplicationGraph.Reload"), TEXT(""), FConsoleCommandWithArgsDelegate::CreateStatic(&RecompileReplicationGraph) );
#Loc: <Workspace>/Engine/Plugins/VirtualProduction/StageMonitoring/Source/StageDataProvider/Private/FramePerformanceProvider.cpp:233
Scope (from outer to inner):
file
function void FFramePerformanceProvider::HandleAssetReload
Source code excerpt:
{
FString Name = InPackageReloadedEvent->GetOldPackage()->GetFullName();
ProviderThread->PushLoadInfo({EStageMonitorNodeStatus::HotReload, Name});
IStageDataProvider::SendMessage<FAssetLoadingStateProviderMessage>(
EStageMessageFlags::Reliable, EStageLoadingState::PreLoad, Name);
}
else if (InPackageReloadPhase == EPackageReloadPhase::PostPackageFixup)
{
TOptional<FFrameProviderRunner::FLoadInfo> Info = ProviderThread->PopLoadInfo();
#Loc: <Workspace>/Engine/Plugins/VirtualProduction/StageMonitoring/Source/StageMonitorCommon/Public/StageMonitorUtils.h:14
Scope: file
Source code excerpt:
LoadingMap,
Ready,
HotReload,
AssetCompiling
};
/**
* Message containing information about frame timings.
#Loc: <Workspace>/Engine/Plugins/VirtualProduction/StageMonitoring/Source/StageMonitorEditor/Private/Widgets/SDataProviderListView.cpp:601
Scope (from outer to inner):
file
function FText SDataProviderTableRow::GetStatus
Source code excerpt:
case EStageMonitorNodeStatus::Ready:
return LOCTEXT("Status_Ready", "Ready");
case EStageMonitorNodeStatus::HotReload:
return LOCTEXT("Status_HotReload", "Reloading");
case EStageMonitorNodeStatus::AssetCompiling:
return LOCTEXT("Status_AssetCompiling", "Asset Compiling");
case EStageMonitorNodeStatus::Unknown:
return LOCTEXT("Status_Unknown", "Unknown");
default:
#Loc: <Workspace>/Engine/Source/Developer/HotReload/Private/HotReload.cpp:58
Scope: file
Source code excerpt:
#define LOCTEXT_NAMESPACE "HotReload"
LLM_DEFINE_TAG(HotReload);
namespace EThreeStateBool
{
enum Type
{
False,
#Loc: <Workspace>/Engine/Source/Developer/HotReload/Private/HotReload.cpp:97
Scope (from outer to inner):
file
class class FScopedHotReload
function FScopedHotReload
Source code excerpt:
: UniquePtr(InUniquePtr)
{
UniquePtr.Reset(new FReload(EActiveReloadType::HotReload, TEXT("HOTRELOAD"), InPackages, *GLog));
}
FScopedHotReload(TUniquePtr<FReload>& InUniquePtr)
: UniquePtr(InUniquePtr)
{
UniquePtr.Reset(new FReload(EActiveReloadType::HotReload, TEXT("HOTRELOAD"), *GLog));
}
~FScopedHotReload()
{
UniquePtr.Reset();
}
#Loc: <Workspace>/Engine/Source/Developer/HotReload/Private/HotReload.cpp:117
Scope: file
Source code excerpt:
/**
* Module for HotReload support
*/
class FHotReloadModule : public IHotReloadModule, FSelfRegisteringExec
{
public:
FHotReloadModule()
{
ModuleCompileReadPipe = nullptr;
#Loc: <Workspace>/Engine/Source/Developer/HotReload/Private/HotReload.cpp:380
Scope: file
Source code excerpt:
};
IMPLEMENT_MODULE(FHotReloadModule, HotReload);
namespace HotReloadDefs
{
static const TCHAR* CompilationInfoConfigSection = TEXT("ModuleFileTracking");
// These strings should match the values of the enum EModuleCompileMethod in ModuleManager.h
#Loc: <Workspace>/Engine/Source/Developer/HotReload/Private/HotReload.cpp:538
Scope (from outer to inner):
file
function void FHotReloadModule::StartupModule
Source code excerpt:
void FHotReloadModule::StartupModule()
{
LLM_SCOPE_BYTAG(HotReload);
UEHotReload_Private::CreateFileThatIndicatesEditorRunIfNeeded();
bIsHotReloadingFromEditor = false;
#if WITH_ENGINE
#Loc: <Workspace>/Engine/Source/Developer/HotReload/Private/HotReload.cpp:611
Scope (from outer to inner):
file
function FString FHotReloadModule::GetModuleCompileMethod
Source code excerpt:
FString FHotReloadModule::GetModuleCompileMethod(FName InModuleName)
{
LLM_SCOPE_BYTAG(HotReload);
if (!ModuleCompileData.Contains(InModuleName))
{
UpdateModuleCompileData(InModuleName);
}
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/EditorEngine.cpp:1433
Scope (from outer to inner):
file
function void UEditorEngine::LoadDefaultEditorModules
Source code excerpt:
FModuleManager::Get().LoadModule(TEXT("LogVisualizer"));
FModuleManager::Get().LoadModule(TEXT("WidgetRegistration"));
FModuleManager::Get().LoadModule(TEXT("HotReload"));
FModuleManager::Get().LoadModuleChecked(TEXT("ClothPainter"));
// Load VR Editor support
FModuleManager::Get().LoadModuleChecked( TEXT( "ViewportInteraction" ) );
FModuleManager::Get().LoadModuleChecked( TEXT( "VREditor" ) );
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/UnrealEdMisc.cpp:699
Scope (from outer to inner):
file
function void FUnrealEdMisc::InitEngineAnalytics
Source code excerpt:
// Record known modules' compilation methods
IHotReloadInterface* HotReload = IHotReloadInterface::GetPtr();
if(HotReload != nullptr)
{
TArray<FModuleStatus> Modules;
FModuleManager::Get().QueryModules(Modules);
for (auto& Module : Modules)
{
// Record only game modules as these are the only ones that should be hot-reloaded
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/UnrealEdMisc.cpp:711
Scope (from outer to inner):
file
function void FUnrealEdMisc::InitEngineAnalytics
Source code excerpt:
TArray< FAnalyticsEventAttribute > ModuleAttributes;
ModuleAttributes.Add(FAnalyticsEventAttribute(FString("ModuleName"), Module.Name));
ModuleAttributes.Add(FAnalyticsEventAttribute(FString("CompilationMethod"), HotReload->GetModuleCompileMethod(*Module.Name)));
EngineAnalytics.RecordEvent(FString("Editor.Usage.Modules"), ModuleAttributes);
}
}
}
}
}
#Loc: <Workspace>/Engine/Source/Runtime/Core/Private/HAL/ConsoleManager.cpp:413
Scope: file
Source code excerpt:
#if WITH_RELOAD
// Unlike HotReload, Live Coding does global initialization outside of the main thread. During global initialization,
// Live Coding does have the main thread stalled so there is a "reduced" chance of threading issues. During global
// initialization with live coding, this code only gets called when a new instance of an existing CVar is created.
// Normally this shouldn't happen unless a source file shuffles between two different unity files.
if (IsInGameThread() || IsReloadActive())
#else
if(IsInGameThread())
#Loc: <Workspace>/Engine/Source/Runtime/Core/Private/HAL/ConsoleManager.cpp:2741
Scope (from outer to inner):
file
function IConsoleObject* FConsoleManager::AddConsoleObject
Source code excerpt:
if( !bCanUpdateOrReplaceObj )
{
// NOTE: The reason we don't assert here is because when using HotReload, locally-initialized static console variables will be
// re-registered, and it's desirable for the new variables to clobber the old ones. Because this happen outside of the
// reload stack frame (IsActiveReload()=true), we can't detect and handle only those cases, so we opt to warn instead.
UE_LOG(LogConsoleManager, Warning, TEXT( "Console object named '%s' already exists but is being registered again, but we weren't expected it to be! (FConsoleManager::AddConsoleObject)"), Name );
}
IConsoleVariable* ExistingVar = ExistingObj->AsVariable();
#Loc: <Workspace>/Engine/Source/Runtime/Core/Private/Modules/ModuleManager.cpp:24
Scope: file
Source code excerpt:
#if WITH_HOT_RELOAD
/** If true, we are reloading a class for HotReload */
CORE_API bool GIsHotReload = false;
#endif
#if WITH_ENGINE
TMap<UClass*, UClass*>& GetClassesToReinstanceForHotReload()
{
#Loc: <Workspace>/Engine/Source/Runtime/Core/Private/Modules/ModuleManager.cpp:1394
Scope (from outer to inner):
file
function void FModuleManager::MakeUniqueModuleFilename
Source code excerpt:
void FModuleManager::MakeUniqueModuleFilename( const FName InModuleName, FString& UniqueSuffix, FString& UniqueModuleFileName ) const
{
// NOTE: Formatting of the module file name must match with the code in HotReload.cs, ReplaceSuffix.
TSharedRef<const FModuleInfo, ESPMode::ThreadSafe> Module = FindModuleChecked(InModuleName);
IFileManager& FileManager = IFileManager::Get();
do
#Loc: <Workspace>/Engine/Source/Runtime/Core/Private/Modules/ModuleManager.cpp:1529
Scope (from outer to inner):
file
function EActiveReloadType GetActiveReloadType
Source code excerpt:
{
check(GActiveReloadInterface);
return EActiveReloadType::HotReload;
}
PRAGMA_ENABLE_DEPRECATION_WARNINGS
#endif
return GActiveReloadType;
}
#Loc: <Workspace>/Engine/Source/Runtime/Core/Private/Modules/ModuleManager.cpp:1542
Scope (from outer to inner):
file
function void BeginReload
Source code excerpt:
#if WITH_HOT_RELOAD
PRAGMA_DISABLE_DEPRECATION_WARNINGS
GIsHotReload = ActiveReloadType == EActiveReloadType::HotReload;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
#endif
GActiveReloadType = ActiveReloadType;
GActiveReloadInterface = &Interface;
}
#Loc: <Workspace>/Engine/Source/Runtime/Core/Public/Modules/ModuleManager.h:32
Scope: file
Source code excerpt:
#if WITH_HOT_RELOAD
/** If true, we are reloading a class for HotReload */
UE_DEPRECATED(5.0, "GIsHotReload has been deprecated, use IsReloadActive to test to see if a reload is in progress.")
extern CORE_API bool GIsHotReload;
#endif
#if WITH_ENGINE
extern CORE_API TMap<UClass*, UClass*>& GetClassesToReinstanceForHotReload();
#Loc: <Workspace>/Engine/Source/Runtime/Core/Public/Modules/ModuleManager.h:1022
Scope: file
Source code excerpt:
Reinstancing,
#if WITH_HOT_RELOAD
HotReload,
#endif
#if WITH_LIVE_CODING
LiveCoding,
#endif
};
#Loc: <Workspace>/Engine/Source/Runtime/CoreUObject/Public/Misc/HotReloadInterface.h:33
Scope: file
Source code excerpt:
/**
* HotReload module interface
*/
class IHotReloadInterface : public IModuleInterface
{
public:
/**
* Tries to gets a pointer to the active HotReload implementation.
*/
static inline IHotReloadInterface* GetPtr()
{
static FName HotReload("HotReload");
return FModuleManager::GetModulePtr<IHotReloadInterface>(HotReload);
}
/**
* Save the current state to disk before quitting.
*/
virtual void SaveConfig() = 0;
#Loc: <Workspace>/Engine/Source/Runtime/CoreUObject/Public/Misc/HotReloadInterface.h:95
Scope: file
Source code excerpt:
/**
* HotReload: Reloads the DLLs for given packages.
*
* @param Package Packages to reload.
* @param Flags Flags which control the hot reload.
* @param Ar Output device for logging compilation status
*
* @return If bWaitForCompletion was set to true, this will return the result of the compilation, otherwise will return ECompilationResult::Unknown
*/
virtual ECompilationResult::Type RebindPackages(const TArray<UPackage*>& Packages, EHotReloadFlags Flags, FOutputDevice &Ar) = 0;
/** Called when a Hot Reload event has completed.
*
* @param bWasTriggeredAutomatically True if the hot reload was invoked automatically by the hot reload system after detecting a changed DLL
*/
DECLARE_MULTICAST_DELEGATE_OneParam(FHotReloadEvent, bool /* bWasTriggeredAutomatically */ );
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/RendererSupport.cpp:100
Scope (from outer to inner):
file
function void RecompileRendererModule
Source code excerpt:
void RecompileRendererModule()
{
IHotReloadInterface* HotReload = IHotReloadInterface::GetPtr();
if(HotReload != nullptr)
{
const FName RendererModuleName = TEXT("Renderer");
// Unload first so that RecompileModule will not using a rolling module name
verify(FModuleManager::Get().UnloadModule(RendererModuleName));
bool bCompiledSuccessfully = false;
do
{
bCompiledSuccessfully = HotReload->RecompileModule(RendererModuleName, *GLog, ERecompileModuleFlags::FailIfGeneratedCodeChanges);
if (!bCompiledSuccessfully)
{
// Pop up a blocking dialog if there were compilation errors
// Compiler output will be in the log
FPlatformMisc::MessageBoxExt(EAppMsgType::Ok, *FText::Format(
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/UnrealEngine.cpp:5231
Scope (from outer to inner):
file
function bool UEngine::Exec_Dev
Source code excerpt:
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) && WITH_HOT_RELOAD
else if (FParse::Command(&Cmd, TEXT("HotReload")))
{
return HandleHotReloadCommand(Cmd, Ar);
}
#endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST) && WITH_HOT_RELOAD
return false;
#Loc: <Workspace>/Engine/Source/Runtime/Launch/Private/LaunchEngineLoop.cpp:5197
Scope (from outer to inner):
file
function void FEngineLoop::Exit
Source code excerpt:
#if WITH_ENGINE
// Save the hot reload state
IHotReloadInterface* HotReload = IHotReloadInterface::GetPtr();
if(HotReload != nullptr)
{
HotReload->SaveConfig();
}
#endif
// Unload all modules. Note that this doesn't actually unload the module DLLs (that happens at
// process exit by the OS), but it does call ShutdownModule() on all loaded modules in the reverse
// order they were loaded in, so that systems can unregister and perform general clean up.
#Loc: <Workspace>/Projects/Lyra/Plugins/Developer/RiderLink/Source/RiderLC/Private/RiderLC.cpp:40
Scope (from outer to inner):
file
lambda-function
lambda-function
lambda-function
Source code excerpt:
{
#if WITH_HOT_RELOAD
IHotReloadInterface* HotReload = FModuleManager::GetModulePtr<IHotReloadInterface>(HotReloadModule);
if (HotReload != nullptr && !HotReload->IsCurrentlyCompiling())
{
HotReload->DoHotReloadFromEditor(EHotReloadFlags::None);
}
#endif
}
});
});
});
#Loc: <Workspace>/Projects/Lyra/Plugins/Developer/RiderLink/Source/RiderLC/Private/RiderLC.cpp:67
Scope (from outer to inner):
file
function bool FRiderLCModule::Tick
Source code excerpt:
{
#if WITH_HOT_RELOAD
const IHotReloadInterface* HotReload = FModuleManager::GetModulePtr<IHotReloadInterface>(HotReloadModule);
if (HotReload != nullptr)
{
bIsAvailable = true;
bIsCompiling = HotReload->IsCurrentlyCompiling();
}
#endif
}
IRiderLinkModule& RiderLinkModule = IRiderLinkModule::Get();
RiderLinkModule.QueueModelAction([bIsAvailable, bIsCompiling](JetBrains::EditorPlugin::RdEditorModel const& RdEditorModel)
{