mirror of
https://github.com/kevinporetti/UnrealImGui.git
synced 2025-02-22 04:00:32 +00:00
Improved hot-reload stability and support for reloading after recompiling outside of the editor:
- Hot-reloading from inside of the editor and after recompiling from the outside should be equally supported and work together. - Improved robustness of the delegates redirections. There should be no lost delegates when reloading (either after in-editor or outside recompilation). - Refactored code to use the same redirection template for context and delegates container.
This commit is contained in:
parent
9eed8f93b9
commit
a76f4bc451
@ -8,6 +8,8 @@ Change History
|
||||
Version: 1.21 (2020/07)
|
||||
Improving stability
|
||||
- Fixed a crash in the input handler caused by invalidated by hot-reload instance trying to unregister a delegate.
|
||||
- Improved hot-reload stability and support for reloading after recompiling outside of the editor. Both methods should be equally supported and work together.
|
||||
- Improved behaviour of delegates when hot-reloading.
|
||||
|
||||
Version: 1.20 (2020/06)
|
||||
Transition to IWYU and maintenance:
|
||||
|
@ -2,25 +2,49 @@
|
||||
|
||||
#include "ImGuiDelegatesContainer.h"
|
||||
|
||||
#include "ImGuiModule.h"
|
||||
#include "Utilities/RedirectingHandle.h"
|
||||
#include "Utilities/WorldContextIndex.h"
|
||||
|
||||
|
||||
FImGuiDelegatesContainer FImGuiDelegatesContainer::DefaultInstance;
|
||||
// Redirecting handle which will automatically bind to another one, if a different instance of the module is loaded.
|
||||
struct FImGuiDelegatesContainerHandle : Utilities::TRedirectingHandle<FImGuiDelegatesContainer>
|
||||
{
|
||||
FImGuiDelegatesContainerHandle(FImGuiDelegatesContainer& InDefaultContainer)
|
||||
: Utilities::TRedirectingHandle<FImGuiDelegatesContainer>(InDefaultContainer)
|
||||
{
|
||||
if (FImGuiModule* Module = FModuleManager::GetModulePtr<FImGuiModule>("ImGui"))
|
||||
{
|
||||
SetParent(&Module->GetDelegatesContainerHandle());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
FImGuiDelegatesContainer* FImGuiDelegatesContainer::InstancePtr = &FImGuiDelegatesContainer::DefaultInstance;
|
||||
static FImGuiDelegatesContainer DelegatesContainer;
|
||||
static FImGuiDelegatesContainerHandle DelegatesHandle(DelegatesContainer);
|
||||
|
||||
void FImGuiDelegatesContainer::MoveContainer(FImGuiDelegatesContainer& Dst)
|
||||
FImGuiDelegatesContainer& FImGuiDelegatesContainer::Get()
|
||||
{
|
||||
return GetHandle().Get();
|
||||
}
|
||||
|
||||
FImGuiDelegatesContainerHandle& FImGuiDelegatesContainer::GetHandle()
|
||||
{
|
||||
return DelegatesHandle;
|
||||
}
|
||||
|
||||
void FImGuiDelegatesContainer::MoveContainer(FImGuiDelegatesContainerHandle& OtherContainerHandle)
|
||||
{
|
||||
// Only move data if pointer points to default instance, otherwise our data has already been moved and we only
|
||||
// keep pointer to a more recent version.
|
||||
if (InstancePtr == &DefaultInstance)
|
||||
if (GetHandle().IsDefault())
|
||||
{
|
||||
Dst = MoveTemp(DefaultInstance);
|
||||
DefaultInstance.Clear();
|
||||
OtherContainerHandle.Get() = MoveTemp(GetHandle().Get());
|
||||
GetHandle().Get().Clear();
|
||||
}
|
||||
|
||||
// Update pointer to the most recent version.
|
||||
InstancePtr = &Dst;
|
||||
GetHandle().SetParent(&OtherContainerHandle);
|
||||
}
|
||||
|
||||
int32 FImGuiDelegatesContainer::GetContextIndex(UWorld* World)
|
||||
|
@ -6,15 +6,20 @@
|
||||
#include <Delegates/Delegate.h>
|
||||
|
||||
|
||||
struct FImGuiDelegatesContainerHandle;
|
||||
|
||||
struct FImGuiDelegatesContainer
|
||||
{
|
||||
public:
|
||||
|
||||
// Get the current instance (can change during hot-reloading).
|
||||
static FImGuiDelegatesContainer& Get() { return *InstancePtr; }
|
||||
static FImGuiDelegatesContainer& Get();
|
||||
|
||||
// If this is an active container move its data to a destination and redirect all future calls to that instance.
|
||||
static void MoveContainer(FImGuiDelegatesContainer& Dst);
|
||||
// Get the handle to the container instance (can attach to other handles in hot-reloaded modules).
|
||||
static FImGuiDelegatesContainerHandle& GetHandle();
|
||||
|
||||
// Redirect to the other container and if this one is still active move its data to the other one.
|
||||
static void MoveContainer(FImGuiDelegatesContainerHandle& OtherContainerHandle);
|
||||
|
||||
// Get delegate to ImGui world early debug event from known world instance.
|
||||
FSimpleMulticastDelegate& OnWorldEarlyDebug(UWorld* World) { return OnWorldEarlyDebug(GetContextIndex(World)); }
|
||||
@ -44,10 +49,4 @@ private:
|
||||
TMap<int32, FSimpleMulticastDelegate> WorldDebugDelegates;
|
||||
FSimpleMulticastDelegate MultiContextEarlyDebugDelegate;
|
||||
FSimpleMulticastDelegate MultiContextDebugDelegate;
|
||||
|
||||
// Default container instance.
|
||||
static FImGuiDelegatesContainer DefaultInstance;
|
||||
|
||||
// Pointer to the container instance that can be overwritten during hot-reloading.
|
||||
static FImGuiDelegatesContainer* InstancePtr;
|
||||
};
|
||||
|
@ -18,12 +18,28 @@
|
||||
#endif // PLATFORM_WINDOWS
|
||||
|
||||
#if WITH_EDITOR
|
||||
// Global ImGui context pointer.
|
||||
ImGuiContext* GImGuiContextPtr = nullptr;
|
||||
// Handle to the global ImGui context pointer.
|
||||
ImGuiContext** GImGuiContextPtrHandle = &GImGuiContextPtr;
|
||||
|
||||
#include "ImGuiModule.h"
|
||||
#include "Utilities/RedirectingHandle.h"
|
||||
|
||||
// Redirecting handle which will automatically bind to another one, if a different instance of the module is loaded.
|
||||
struct FImGuiContextHandle : public Utilities::TRedirectingHandle<ImGuiContext*>
|
||||
{
|
||||
FImGuiContextHandle(ImGuiContext*& InDefaultContext)
|
||||
: Utilities::TRedirectingHandle<ImGuiContext*>(InDefaultContext)
|
||||
{
|
||||
if (FImGuiModule* Module = FModuleManager::GetModulePtr<FImGuiModule>("ImGui"))
|
||||
{
|
||||
SetParent(&Module->GetImGuiContextHandle());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static ImGuiContext* ImGuiContextPtr = nullptr;
|
||||
static FImGuiContextHandle ImGuiContextPtrHandle(ImGuiContextPtr);
|
||||
|
||||
// Get the global ImGui context pointer (GImGui) indirectly to allow redirections in obsolete modules.
|
||||
#define GImGui (*GImGuiContextPtrHandle)
|
||||
#define GImGui (ImGuiContextPtrHandle.Get())
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
#include "imgui.cpp"
|
||||
@ -41,14 +57,14 @@ ImGuiContext** GImGuiContextPtrHandle = &GImGuiContextPtr;
|
||||
namespace ImGuiImplementation
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
ImGuiContext** GetImGuiContextHandle()
|
||||
FImGuiContextHandle& GetContextHandle()
|
||||
{
|
||||
return GImGuiContextPtrHandle;
|
||||
return ImGuiContextPtrHandle;
|
||||
}
|
||||
|
||||
void SetImGuiContextHandle(ImGuiContext** Handle)
|
||||
void SetParentContextHandle(FImGuiContextHandle& Parent)
|
||||
{
|
||||
GImGuiContextPtrHandle = Handle;
|
||||
ImGuiContextPtrHandle.SetParent(&Parent);
|
||||
}
|
||||
#endif // WITH_EDITOR
|
||||
}
|
||||
|
@ -2,16 +2,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ImGuiContext;
|
||||
struct FImGuiContextHandle;
|
||||
|
||||
// Gives access to selected ImGui implementation features.
|
||||
namespace ImGuiImplementation
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
// Get the handle to the ImGui Context pointer.
|
||||
ImGuiContext** GetImGuiContextHandle();
|
||||
FImGuiContextHandle& GetContextHandle();
|
||||
|
||||
// Set the ImGui Context pointer handle.
|
||||
void SetImGuiContextHandle(ImGuiContext** Handle);
|
||||
void SetParentContextHandle(FImGuiContextHandle& Parent);
|
||||
#endif // WITH_EDITOR
|
||||
}
|
||||
|
@ -149,9 +149,9 @@ void FImGuiModule::ShutdownModule()
|
||||
if (&LoadedModule != this)
|
||||
{
|
||||
// Statically bound functions will be still made to the obsolete module so we need to
|
||||
ImGuiImplementation::SetImGuiContextHandle(LoadedModule.GetImGuiContextHandle());
|
||||
ImGuiImplementation::SetParentContextHandle(LoadedModule.GetImGuiContextHandle());
|
||||
|
||||
FImGuiDelegatesContainer::MoveContainer(LoadedModule.GetDelegatesContainer());
|
||||
FImGuiDelegatesContainer::MoveContainer(LoadedModule.GetDelegatesContainerHandle());
|
||||
|
||||
if (bMoveProperties)
|
||||
{
|
||||
@ -170,14 +170,14 @@ void FImGuiModule::SetProperties(const FImGuiModuleProperties& Properties)
|
||||
ImGuiModuleManager->GetProperties() = Properties;
|
||||
}
|
||||
|
||||
ImGuiContext** FImGuiModule::GetImGuiContextHandle()
|
||||
FImGuiContextHandle& FImGuiModule::GetImGuiContextHandle()
|
||||
{
|
||||
return ImGuiImplementation::GetImGuiContextHandle();
|
||||
return ImGuiImplementation::GetContextHandle();
|
||||
}
|
||||
|
||||
FImGuiDelegatesContainer& FImGuiModule::GetDelegatesContainer()
|
||||
FImGuiDelegatesContainerHandle& FImGuiModule::GetDelegatesContainerHandle()
|
||||
{
|
||||
return FImGuiDelegatesContainer::Get();
|
||||
return FImGuiDelegatesContainer::GetHandle();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
96
Source/ImGui/Private/Utilities/RedirectingHandle.h
Normal file
96
Source/ImGui/Private/Utilities/RedirectingHandle.h
Normal file
@ -0,0 +1,96 @@
|
||||
// Distributed under the MIT License (MIT) (see accompanying LICENSE file)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Delegates/Delegate.h>
|
||||
#include <Delegates/DelegateCombinations.h>
|
||||
|
||||
|
||||
namespace Utilities
|
||||
{
|
||||
// Handle initialized as a pointer to a default value, but once attached it will follow the parent handle.
|
||||
// When detached it will revert back to the default value. Intended for cross-module redirections.
|
||||
template<typename T>
|
||||
struct TRedirectingHandle
|
||||
{
|
||||
TRedirectingHandle(T& InDefaultValue)
|
||||
: Handle(&InDefaultValue)
|
||||
, DefaultHandle(&InDefaultValue)
|
||||
{
|
||||
}
|
||||
|
||||
~TRedirectingHandle()
|
||||
{
|
||||
// Broadcast null pointer as a request to detach.
|
||||
OnRedirectionUpdate.Broadcast(nullptr);
|
||||
}
|
||||
|
||||
// Check whether this handle points to the default value.
|
||||
bool IsDefault() const
|
||||
{
|
||||
return (Handle == DefaultHandle);
|
||||
}
|
||||
|
||||
// Get the current value.
|
||||
T& Get() const
|
||||
{
|
||||
return *Handle;
|
||||
}
|
||||
|
||||
// Set the other handle as a parent to this one. Passing null or itself will result with detaching from
|
||||
// the current parent (if any) and reverting back to the default value.
|
||||
void SetParent(TRedirectingHandle* InParent)
|
||||
{
|
||||
if (InParent != Parent)
|
||||
{
|
||||
if (Parent)
|
||||
{
|
||||
Parent->OnRedirectionUpdate.RemoveAll(this);
|
||||
}
|
||||
|
||||
// Protecting from setting itself as a parent.
|
||||
Parent = (Parent != this) ? InParent : nullptr;
|
||||
|
||||
if (Parent)
|
||||
{
|
||||
Parent->OnRedirectionUpdate.AddRaw(this, &TRedirectingHandle::UpdateRedirection);
|
||||
}
|
||||
|
||||
SetHandle((Parent) ? Parent->Handle : DefaultHandle);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void UpdateRedirection(T* InHandle)
|
||||
{
|
||||
if (InHandle)
|
||||
{
|
||||
SetHandle(InHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Interpreting null as a signal to detach.
|
||||
SetParent(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void SetHandle(T* InHandle)
|
||||
{
|
||||
if (InHandle != Handle)
|
||||
{
|
||||
Handle = InHandle;
|
||||
OnRedirectionUpdate.Broadcast(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
T* Handle;
|
||||
T* DefaultHandle;
|
||||
|
||||
TRedirectingHandle* Parent = nullptr;
|
||||
|
||||
// Event with a new handle value or null pointer as a signal to detach.
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FRedirectionUpdateDelegate, T*);
|
||||
FRedirectionUpdateDelegate OnRedirectionUpdate;
|
||||
};
|
||||
}
|
@ -164,11 +164,13 @@ public:
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
|
||||
private:
|
||||
private:
|
||||
|
||||
#if WITH_EDITOR
|
||||
friend struct FImGuiContextHandle;
|
||||
friend struct FImGuiDelegatesContainerHandle;
|
||||
virtual void SetProperties(const FImGuiModuleProperties& Properties);
|
||||
virtual struct ImGuiContext** GetImGuiContextHandle();
|
||||
virtual struct FImGuiDelegatesContainer& GetDelegatesContainer();
|
||||
virtual FImGuiContextHandle& GetImGuiContextHandle();
|
||||
virtual FImGuiDelegatesContainerHandle& GetDelegatesContainerHandle();
|
||||
#endif
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user