Has anyone made hot reload truly stable for C++ gameplay in UE5.4? Live Coding works for me, but after about 20–30 reloads I hit vtable/symbol mismatches and end up restarting the editor; looking for a disciplined setup (build flags, reflection boundaries, or a tiny Lua layer for high-churn logic) that preserves code quality and keeps iteration under a second.
I kept hot reload stable in UE5.4 by “freezing” the UCLASS side: push high‑churn logic into free functions in a non‑UObject.cpp, expose a thin UFUNCTION shim, and disable unity for that TU so Live Coding patches just one object — iterations stay under a second and the “vtable/symbol mismatches” stopped. Would you be able to keep those UCLASS shells unchanged for a while?
I’ve had best results by moving hot logic into a tiny no‑UObject gameplay module and building that module with bUseUnityBuild=false and no LTCG; Live Coding then only patches that module, vtables don’t churn, and iter stays under a second. It’s @lwells45’s “freeze the UCLASS” but at module granularity — also toggle off “compile dependent modules” in Live Coding and avoid changing UPROPERTY layout mid‑session. Curious if that fits your setup.
Counterintuitive but freezing vtables helped: mark hot gameplay classes final, stop adding/removing virtuals mid‑session, and route extensibility through delegates or plain funcs; that slashed my “vtable/symbol mismatches” in UE5.4. I also keep templates/inline changes out of public headers so symbols don’t drift and iteration stays about 1s. @lwells45’s split is great — did your blowups line up with introducing a new virtual or moving a UFUNCTION up the hierarchy?
One tweak that helped was aggressively hiding ABI churn: put ‘MinimalAPI’ on gameplay UCLASS/USTRUCT that cross module boundaries, move the hot code out of headers (no inline), and avoid static locals with non‑trivial dtors — kept patching steady and sub‑second, like keeping the shopfront fixed while rearranging shelves; have you tried that, @thewitt99?
@OP The biggest stability win for me was purging function-static caches and other globals that hold UClass*/UFunction*; I moved that state into a UEngineSubsystem and reset it on FCoreDelegates::OnHotReload() (docs: https://docs.unrealengine.com/5.4/en-US/API/Runtime/Core/Delegates/FCoreDelegates/OnHotReload/), which kept about 0.8s iterations solid past 100 reloads in 5.4. Small caveat: if you rely on those statics for perf, gate them behind a lazy init and trigger a Reset from the delegate — do you have many helpers with static TMap/TSet caches?
, I fixed the ‘vtable/symbol mismatches’ spiral by disabling identical COMDAT folding for the hot module — add /OPT:NOICF to its AdditionalLinkerArguments so new symbols don’t alias old ones; paired with /DEBUG:FASTLINK I’m about 0.9s per iter and stable past 100 reloads in 5.4. The tradeoff is a slightly bigger DLL and a minor link hit, but way fewer restarts. Are you able to tweak linker flags, or are you stuck with stock settings?
On UE5.4 I got Live Coding stable by disabling unity just for the gameplay module (bUseUnity = false in the Editor target) — build times tick up a hair, but it killed a bunch of ODR weirdness and kept patches small enough to stay “under a second.” @OP are you building that module with unity on?