Option to replicate client selection to server.

This commit is contained in:
Arnaud Jamin
2025-01-06 13:41:46 -05:00
parent c58126d244
commit 9a1cd48434
9 changed files with 82 additions and 28 deletions
@@ -106,18 +106,35 @@ int32 FCogDebug::GetPieSessionId()
#endif #endif
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogDebug::SetSelection(const UWorld* World, AActor* Value) void FCogDebug::SetSelection(const UWorld* World, AActor* Value)
{ {
Selection[GetPieSessionId()] = Value; Selection[GetPieSessionId()] = Value;
if (World != nullptr && World->GetNetMode() == NM_Client) ReplicateSelection(World, Value);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogDebug::ReplicateSelection(const UWorld* World, AActor* Value)
{
if (World == nullptr)
{ {
if (ACogDebugReplicator* Replicator = ACogDebugReplicator::GetLocalReplicator(*World)) return;
{
Replicator->Server_SetSelection(Value);
}
} }
ACogDebugReplicator* Replicator = ACogDebugReplicator::GetLocalReplicator(*World);
if (Replicator == nullptr)
{
return;
}
if (Replicator->HasAuthority())
{
return;
}
Replicator->Server_SetSelection(Value, Settings.ReplicateSelection);
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
@@ -82,7 +82,7 @@ void ACogDebugReplicator::BeginPlay()
if (OwnerPlayerController != nullptr && OwnerPlayerController->IsLocalController()) if (OwnerPlayerController != nullptr && OwnerPlayerController->IsLocalController())
{ {
Server_RequestAllCategoriesVerbosity(); Server_RequestAllCategoriesVerbosity();
Server_SetSelection(FCogDebug::GetSelection()); Server_SetSelection(FCogDebug::GetSelection(), FCogDebug::Settings.ReplicateSelection);
Server_SetIsFilteringBySelection(FCogDebug::GetIsFilteringBySelection()); Server_SetIsFilteringBySelection(FCogDebug::GetIsFilteringBySelection());
} }
} }
@@ -210,12 +210,22 @@ void ACogDebugReplicator::Server_SetIsFilteringBySelection_Implementation(bool V
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void ACogDebugReplicator::Server_SetSelection_Implementation(AActor* Value) void ACogDebugReplicator::Server_SetSelection_Implementation(AActor* Value, bool ForceSelection)
{ {
#if !UE_BUILD_SHIPPING #if !UE_BUILD_SHIPPING
ServerSelection = Value; ServerSelection = Value;
if (ForceSelection)
{
FCogDebug::SetSelection(GetWorld(), Value);
}
else
{
FCogDebug::SetSelection(GetWorld(), nullptr);
}
#endif // !UE_BUILD_SHIPPING #endif // !UE_BUILD_SHIPPING
} }
@@ -29,6 +29,9 @@ struct FCogDebugSettings
UPROPERTY(Config) UPROPERTY(Config)
bool bIsFilteringBySelection = true; bool bIsFilteringBySelection = true;
UPROPERTY(Config)
bool ReplicateSelection = true;
UPROPERTY(Config) UPROPERTY(Config)
bool Persistent = false; bool Persistent = false;
@@ -429,9 +432,11 @@ private:
static int32 GetPieSessionId(); static int32 GetPieSessionId();
static constexpr uint32 MaxPie = 16; static void ReplicateSelection(const UWorld* World, AActor* Value);
static bool IsDebugActiveForObject_Internal(const UObject* WorldContextObject, const AActor* InSelection, bool InIsFilteringBySelection); static bool IsDebugActiveForObject_Internal(const UObject* WorldContextObject, const AActor* InSelection, bool InIsFilteringBySelection);
static constexpr uint32 MaxPie = 16;
static TWeakObjectPtr<AActor> Selection[MaxPie]; static TWeakObjectPtr<AActor> Selection[MaxPie];
}; };
@@ -88,7 +88,7 @@ public:
AActor* GetServerSelection() const { return ServerSelection.Get(); } AActor* GetServerSelection() const { return ServerSelection.Get(); }
UFUNCTION(Server, Reliable) UFUNCTION(Server, Reliable)
void Server_SetSelection(AActor* Value); void Server_SetSelection(AActor* Value, bool ForceSelection);
bool IsServerFilteringBySelection() const { return bIsServerFilteringBySelection; } bool IsServerFilteringBySelection() const { return bIsServerFilteringBySelection; }
@@ -84,7 +84,11 @@ void FCogEngineWindow_CollisionTester::RenderContent()
} }
ImGui::SetNextItemWidth(-1); ImGui::SetNextItemWidth(-1);
FCogWindowWidgets::MenuActorsCombo("CollisionTesters", *GetWorld(), ACogEngineCollisionTester::StaticClass()); AActor* NewSelection = nullptr;
if (FCogWindowWidgets::MenuActorsCombo("CollisionTesters", NewSelection, *GetWorld(), ACogEngineCollisionTester::StaticClass()))
{
FCogDebug::SetSelection(GetWorld(), NewSelection);
}
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
@@ -2,6 +2,7 @@
#include "CogDebug.h" #include "CogDebug.h"
#include "CogEngineHelper.h" #include "CogEngineHelper.h"
#include "CogEngineReplicator.h"
#include "CogEngineWindow_ImGui.h" #include "CogEngineWindow_ImGui.h"
#include "CogImguiHelper.h" #include "CogImguiHelper.h"
#include "CogImguiInputHelper.h" #include "CogImguiInputHelper.h"
@@ -204,7 +205,14 @@ void FCogEngineWindow_Selection::RenderContent()
if (ImGui::BeginMenu("Options")) if (ImGui::BeginMenu("Options"))
{ {
ImGui::Checkbox("Save selection", &Config->bReapplySelection); ImGui::Checkbox("Save selection", &Config->bReapplySelection);
ImGui::Checkbox("Actor Name Use Label", &FCogDebug::Settings.ActorNameUseLabel); ImGui::SetItemTooltip("Should the last selection be saved and reapplied on startup.");
ImGui::Checkbox("Actor Name Use Label", &FCogDebug::Settings.ActorNameUseLabel);
ImGui::SetItemTooltip("Should actor names be displayed using their label. Labels are more readable.");
ImGui::Checkbox("Replicate Selection", &FCogDebug::Settings.ReplicateSelection);
ImGui::SetItemTooltip("Should the client replicate its actor selection to the server.");
ImGui::EndMenu(); ImGui::EndMenu();
} }
@@ -219,7 +227,14 @@ void FCogEngineWindow_Selection::RenderContent()
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
bool FCogEngineWindow_Selection::DrawSelectionCombo() bool FCogEngineWindow_Selection::DrawSelectionCombo()
{ {
return FCogWindowWidgets::ActorsListWithFilters(*GetWorld(), ActorClasses, Config->SelectedClassIndex, &Filter, GetLocalPlayerPawn()); AActor* NewSelection = nullptr;
const bool result = FCogWindowWidgets::ActorsListWithFilters(NewSelection, *GetWorld(), ActorClasses, Config->SelectedClassIndex, &Filter, GetLocalPlayerPawn());
if (result)
{
SetGlobalSelection(NewSelection);
}
return result;
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
@@ -353,7 +368,8 @@ void FCogEngineWindow_Selection::RenderMainMenuWidget(int32 SubWidgetIndex, floa
else if (SubWidgetIndex == 1) else if (SubWidgetIndex == 1)
{ {
ImGui::SetNextItemWidth(Width); ImGui::SetNextItemWidth(Width);
FCogWindowWidgets::MenuActorsCombo("MenuActorSelection", *GetWorld(), ActorClasses, Config->SelectedClassIndex, &Filter, GetLocalPlayerPawn(), [this](AActor& Actor) { RenderActorContextMenu(Actor); }); AActor* NewSelection = nullptr;
FCogWindowWidgets::MenuActorsCombo("MenuActorSelection", NewSelection, *GetWorld(), ActorClasses, Config->SelectedClassIndex, &Filter, GetLocalPlayerPawn(), [this](AActor& Actor) { RenderActorContextMenu(Actor); });
} }
else if (SubWidgetIndex == 2) else if (SubWidgetIndex == 2)
{ {
@@ -75,7 +75,7 @@ protected:
bool bSelectionModeActive = false; bool bSelectionModeActive = false;
bool bIsInputEnabledBeforeEnteringSelectionMode; bool bIsInputEnabledBeforeEnteringSelectionMode = false;
int32 WaitInputReleased = 0; int32 WaitInputReleased = 0;
@@ -734,7 +734,7 @@ bool FCogWindowWidgets::CollisionProfileChannels(int32& Channels)
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
bool FCogWindowWidgets::ActorsListWithFilters(const UWorld& World, const TArray<TSubclassOf<AActor>>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction) bool FCogWindowWidgets::ActorsListWithFilters(AActor*& NewSelection, const UWorld& World, const TArray<TSubclassOf<AActor>>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction)
{ {
TSubclassOf<AActor> SelectedClass = AActor::StaticClass(); TSubclassOf<AActor> SelectedClass = AActor::StaticClass();
if (ActorClasses.IsValidIndex(SelectedActorClassIndex)) if (ActorClasses.IsValidIndex(SelectedActorClassIndex))
@@ -783,14 +783,14 @@ bool FCogWindowWidgets::ActorsListWithFilters(const UWorld& World, const TArray<
// Actor List // Actor List
//------------------------ //------------------------
ImGui::BeginChild("ActorsList", ImVec2(-1, -1), false); ImGui::BeginChild("ActorsList", ImVec2(-1, -1), false);
const bool SelectionChanged = ActorsList(World, SelectedClass, Filter, LocalPlayerPawn, ContextMenuFunction); const bool SelectionChanged = ActorsList(NewSelection, World, SelectedClass, Filter, LocalPlayerPawn, ContextMenuFunction);
ImGui::EndChild(); ImGui::EndChild();
return SelectionChanged; return SelectionChanged;
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
bool FCogWindowWidgets::ActorsList(const UWorld& World, const TSubclassOf<AActor> ActorClass, const ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction) bool FCogWindowWidgets::ActorsList(AActor*& NewSelection, const UWorld& World, const TSubclassOf<AActor> ActorClass, const ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction)
{ {
TArray<AActor*> Actors; TArray<AActor*> Actors;
for (TActorIterator It(&World, ActorClass); It; ++It) for (TActorIterator It(&World, ActorClass); It; ++It)
@@ -813,8 +813,8 @@ bool FCogWindowWidgets::ActorsList(const UWorld& World, const TSubclassOf<AActor
} }
} }
const AActor* OldSelection = FCogDebug::GetSelection(); AActor* OldSelection = FCogDebug::GetSelection();
const AActor* NewSelection = OldSelection; NewSelection = OldSelection;
ImGuiListClipper Clipper; ImGuiListClipper Clipper;
Clipper.Begin(Actors.Num()); Clipper.Begin(Actors.Num());
@@ -833,7 +833,7 @@ bool FCogWindowWidgets::ActorsList(const UWorld& World, const TSubclassOf<AActor
const bool bIsSelected = Actor == FCogDebug::GetSelection(); const bool bIsSelected = Actor == FCogDebug::GetSelection();
if (ImGui::Selectable(TCHAR_TO_ANSI(*FCogWindowHelper::GetActorName(*Actor)), bIsSelected)) if (ImGui::Selectable(TCHAR_TO_ANSI(*FCogWindowHelper::GetActorName(*Actor)), bIsSelected))
{ {
FCogDebug::SetSelection(&World, Actor); //FCogDebug::SetSelection(&World, Actor);
NewSelection = Actor; NewSelection = Actor;
} }
@@ -862,17 +862,17 @@ bool FCogWindowWidgets::ActorsList(const UWorld& World, const TSubclassOf<AActor
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
bool FCogWindowWidgets::MenuActorsCombo(const char* StrID, const UWorld& World, TSubclassOf<AActor> ActorClass, const FCogWindowActorContextMenuFunction& ContextMenuFunction) bool FCogWindowWidgets::MenuActorsCombo(const char* StrID, AActor*& NewSelection, const UWorld& World, TSubclassOf<AActor> ActorClass, const FCogWindowActorContextMenuFunction& ContextMenuFunction)
{ {
int32 SelectedActorClassIndex = 0; int32 SelectedActorClassIndex = 0;
const TArray ActorClasses = { ActorClass }; const TArray ActorClasses = { ActorClass };
AActor* Actor = nullptr; AActor* Actor = nullptr;
return MenuActorsCombo(StrID, World, ActorClasses, SelectedActorClassIndex, nullptr, nullptr, ContextMenuFunction); return MenuActorsCombo(StrID, NewSelection, World, ActorClasses, SelectedActorClassIndex, nullptr, nullptr, ContextMenuFunction);
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
bool FCogWindowWidgets::MenuActorsCombo(const char* StrID, const UWorld& World, const TArray<TSubclassOf<AActor>>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction) bool FCogWindowWidgets::MenuActorsCombo(const char* StrID, AActor*& NewSelection, const UWorld& World, const TArray<TSubclassOf<AActor>>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction)
{ {
bool Result = false; bool Result = false;
ImGui::PushID(StrID); ImGui::PushID(StrID);
@@ -928,7 +928,7 @@ bool FCogWindowWidgets::MenuActorsCombo(const char* StrID, const UWorld& World,
{ {
ImGui::BeginChild("Child", ImVec2(Pos2.x - Pos1.x, GetFontWidth() * 40), false); ImGui::BeginChild("Child", ImVec2(Pos2.x - Pos1.x, GetFontWidth() * 40), false);
Result = ActorsListWithFilters(World, ActorClasses, SelectedActorClassIndex, Filter, LocalPlayerPawn, ContextMenuFunction); Result = ActorsListWithFilters(NewSelection, World, ActorClasses, SelectedActorClassIndex, Filter, LocalPlayerPawn, ContextMenuFunction);
if (Result) if (Result)
{ {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
@@ -4,6 +4,8 @@
#include "imgui.h" #include "imgui.h"
#include "UObject/ReflectedTypeAccessors.h" #include "UObject/ReflectedTypeAccessors.h"
class AActor;
class APawn;
class FEnumProperty; class FEnumProperty;
class UCollisionProfile; class UCollisionProfile;
class UEnum; class UEnum;
@@ -91,13 +93,13 @@ public:
static bool CollisionProfileChannels(int32& Channels); static bool CollisionProfileChannels(int32& Channels);
static bool MenuActorsCombo(const char* StrID, const UWorld& World, TSubclassOf<AActor> ActorClass, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr); static bool MenuActorsCombo(const char* StrID, AActor*& NewSelection, const UWorld& World, TSubclassOf<AActor> ActorClass, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr);
static bool MenuActorsCombo(const char* StrID, const UWorld& World, const TArray<TSubclassOf<AActor>>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr); static bool MenuActorsCombo(const char* StrID, AActor*& NewSelection, const UWorld& World, const TArray<TSubclassOf<AActor>>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr);
static bool ActorsListWithFilters(const UWorld& World, const TArray<TSubclassOf<AActor>>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr); static bool ActorsListWithFilters(AActor*& NewSelection, const UWorld& World, const TArray<TSubclassOf<AActor>>& ActorClasses, int32& SelectedActorClassIndex, ImGuiTextFilter* Filter, const APawn* LocalPlayerPawn, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr);
static bool ActorsList(const UWorld& World, const TSubclassOf<AActor> ActorClass, const ImGuiTextFilter* Filter = nullptr, const APawn* LocalPlayerPawn = nullptr, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr); static bool ActorsList(AActor*& NewSelection, const UWorld& World, const TSubclassOf<AActor> ActorClass, const ImGuiTextFilter* Filter = nullptr, const APawn* LocalPlayerPawn = nullptr, const FCogWindowActorContextMenuFunction& ContextMenuFunction = nullptr);
static void ActorContextMenu(AActor& Selection, const FCogWindowActorContextMenuFunction& ContextMenuFunction); static void ActorContextMenu(AActor& Selection, const FCogWindowActorContextMenuFunction& ContextMenuFunction);