HotReload

HotReload

#Overview

name: HotReload

This variable is created as a Console Variable (cvar).

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:

  1. The Editor
  2. GameplayAbilities system
  3. ReplicationGraph
  4. StageMonitoring for Virtual Production
  5. 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:

  1. GIsHotReload (deprecated in UE5)
  2. EActiveReloadType
  3. GActiveReloadInterface

Developers should be aware of the following when working with HotReload:

  1. It’s primarily intended for development and editor use, not for shipping builds.
  2. Hot reloading can sometimes lead to unexpected behavior if not handled properly.
  3. Not all code changes can be hot reloaded; some may require a full engine restart.

Best practices when using HotReload include:

  1. Use it primarily during development and testing phases.
  2. Be cautious when hot reloading core engine modules or critical game systems.
  3. Always test thoroughly after a hot reload to ensure no unexpected side effects.
  4. Be aware of the limitations of hot reloading and be prepared to do a full engine restart for significant code changes.
  5. 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)
	{