diff --git a/Content/Core/Debug/Cheats/GE_Cheat_MoveSpeed.uasset b/Content/Core/Debug/Cheats/GE_Cheat_MoveSpeed.uasset new file mode 100644 index 0000000..511705b Binary files /dev/null and b/Content/Core/Debug/Cheats/GE_Cheat_MoveSpeed.uasset differ diff --git a/Content/Core/Debug/Cheats/GE_Cheat_Speed.uasset b/Content/Core/Debug/Cheats/GE_Cheat_Speed.uasset deleted file mode 100644 index a7f6476..0000000 Binary files a/Content/Core/Debug/Cheats/GE_Cheat_Speed.uasset and /dev/null differ diff --git a/Content/Core/Debug/DA_Debug_Ability.uasset b/Content/Core/Debug/DA_Debug_Ability.uasset index 4f0a77d..36ddae4 100644 Binary files a/Content/Core/Debug/DA_Debug_Ability.uasset and b/Content/Core/Debug/DA_Debug_Ability.uasset differ diff --git a/Content/Core/Debug/DA_Debug_Engine.uasset b/Content/Core/Debug/DA_Debug_Engine.uasset index a627828..cc7952c 100644 Binary files a/Content/Core/Debug/DA_Debug_Engine.uasset and b/Content/Core/Debug/DA_Debug_Engine.uasset differ diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineDataAsset.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineDataAsset.cpp new file mode 100644 index 0000000..d5e3ecf --- /dev/null +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineDataAsset.cpp @@ -0,0 +1,18 @@ +#include "CogEngineDataAsset.h" + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogEngineCheat_Execution::Execute_Implementation(const AActor* Instigator, const TArray& Targets) const +{ +} + +//-------------------------------------------------------------------------------------------------------------------------- +ECogEngineCheat_ActiveState UCogEngineCheat_Execution::IsActiveOnTargets_Implementation(const TArray& Targets) const +{ + return ECogEngineCheat_ActiveState::Inactive; +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool UCogEngineCheat_Execution::GetColor(const FCogWindow& InCallingWindow, FLinearColor& OutColor) const +{ + return false; +} diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineReplicator.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineReplicator.cpp index ef20cb5..404ff8f 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineReplicator.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineReplicator.cpp @@ -220,3 +220,26 @@ void ACogEngineReplicator::Server_DeleteActor_Implementation(AActor* Actor) #endif // !UE_BUILD_SHIPPING } + + +//-------------------------------------------------------------------------------------------------------------------------- +void ACogEngineReplicator::Server_ApplyCheat_Implementation(const AActor* CheatInstigator, const TArray& Targets, const FCogEngineCheat& Cheat) const +{ + if (Cheat.Execution == nullptr) + { + return; + } + + Cheat.Execution->Execute(CheatInstigator, Targets); +} + +//-------------------------------------------------------------------------------------------------------------------------- +ECogEngineCheat_ActiveState ACogEngineReplicator::IsCheatActiveOnTargets(const TArray& Targets, const FCogEngineCheat& Cheat) +{ + if (Cheat.Execution == nullptr) + { + return ECogEngineCheat_ActiveState::Inactive; + } + + return Cheat.Execution->IsActiveOnTargets(Targets); +} diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Cheats.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Cheats.cpp new file mode 100644 index 0000000..0e7cc21 --- /dev/null +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Cheats.cpp @@ -0,0 +1,485 @@ +#include "CogEngineWindow_Cheats.h" + +#include "CogEngineDataAsset.h" +#include "CogEngineReplicator.h" +#include "CogCommonAllegianceActorInterface.h" +#include "CogImguiHelper.h" +#include "CogWindowConsoleCommandManager.h" +#include "CogWindowWidgets.h" +#include "EngineUtils.h" +#include "GameFramework/Character.h" +#include "imgui.h" +#include "imgui_internal.h" + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::RenderHelp() +{ + ImGui::Text( + "This window can be used to apply cheats to the selected actor (by default). " + "The cheats can be configured in the '%s' data asset. " + "When clicking a cheat button, press:\n" + " [CTRL] to apply the cheat to controlled actor\n" + " [ALT] to apply the cheat to the allies of the selected actor\n" + " [SHIFT] to apply the cheat to the enemies of the selected actor\n" + , TCHAR_TO_ANSI(*GetNameSafe(Asset.Get())) + ); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::Initialize() +{ + Super::Initialize(); + + bHasMenu = true; + + Asset = GetAsset(); + Config = GetConfig(); + + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + TEXT("Cog.Cheat"), + TEXT("Apply a cheat to the selection. Cog.Cheat -Allies -Enemies -Controlled"), + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + if (InArgs.Num() > 0) + { + if (const FCogEngineCheat* cheat = FindCheatByName(InArgs[0], false)) + { + const bool ApplyToEnemies = InArgs.Contains("-Enemies"); + const bool ApplyToAllies = InArgs.Contains("-Allies"); + const bool ApplyToControlled = InArgs.Contains("-Controlled"); + + RequestCheat(GetLocalPlayerPawn(), GetSelection(), *cheat, ApplyToEnemies, ApplyToAllies, ApplyToControlled); + } + else + { + UE_LOG(LogCogImGui, Warning, TEXT("Cog.Cheat %s | Cheat not found"), *InArgs[0]); + } + } + })); + + + for (const FCogEngineCheatCategory& CheatCategory : Asset->CheatCategories) + { + for (const FCogEngineCheat& Cheat : CheatCategory.PersistentEffects) + { + UpdateCheatColor(Cheat); + } + + for (const FCogEngineCheat& Cheat : CheatCategory.InstantEffects) + { + UpdateCheatColor(Cheat); + } + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::UpdateCheatColor(const FCogEngineCheat& Cheat) const +{ + FLinearColor CustomColor; + if (Cheat.Execution != nullptr && Cheat.Execution->GetColor(*this, CustomColor)) + { + Cheat.CustomColor = CustomColor; + } + else + { + Cheat.CustomColor = Cheat.Color; + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::ResetConfig() +{ + Super::ResetConfig(); + + Config->Reset(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::GameTick(float DeltaTime) +{ + Super::GameTick(DeltaTime); + + TryReapplyCheats(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::TryReapplyCheats() +{ + if (Config == nullptr) + { return; } + + if (bHasReappliedCheats) + { return; } + + if (Config->bReapplyCheatsBetweenPlays == false) + { return; } + + static int32 IsFirstLaunch = true; + if (IsFirstLaunch && Config->bReapplyCheatsBetweenLaunches == false) + { return; } + IsFirstLaunch = false; + + if (Asset == nullptr) + { return; } + + APawn* ControlledActor = GetLocalPlayerPawn(); + if (ControlledActor == nullptr) + { return; } + + const ACogEngineReplicator* Replicator = ACogEngineReplicator::GetLocalReplicator(*GetWorld()); + if (Replicator == nullptr) + { return; } + + TArray Targets { ControlledActor }; + + for (int32 i = Config->AppliedCheats.Num() - 1; i >= 0; i--) + { + if (const FCogEngineCheat* Cheat = FindCheatByName(Config->AppliedCheats[i], true)) + { + Replicator->Server_ApplyCheat(ControlledActor, Targets, *Cheat); + } + else + { + //----------------------------------------------------- + // This cheat doesn't exist anymore. We can remove it. + //----------------------------------------------------- + Config->AppliedCheats.RemoveAt(i); + } + } + + bHasReappliedCheats = true; +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogEngineWindow_Cheats::DrawTable() +{ + const bool Open = ImGui::BeginTable("Cheats", 2, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_NoBordersInBodyUntilResize); + ImGui::TableSetupColumn("Toggle", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("Instant", ImGuiTableColumnFlags_WidthStretch); + return Open; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::RenderContent() +{ + Super::RenderContent(); + + if (Config == nullptr) + { + ImGui::TextDisabled("Invalid Config"); + return; + } + + AActor* SelectedActor = GetSelection(); + if (SelectedActor == nullptr) + { + ImGui::TextDisabled("Invalid Selection"); + return; + } + + if (Asset == nullptr) + { + ImGui::TextDisabled("Invalid Asset"); + return; + } + + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Options")) + { + ImGui::Checkbox("Group By Category", &Config->bGroupByCategories); + + ImGui::Checkbox("Use Two Columns", &Config->bUseTwoColumns); + + ImGui::Separator(); + + ImGui::Checkbox("Reapply Cheats Between Plays", &Config->bReapplyCheatsBetweenPlays); + if (Config->bReapplyCheatsBetweenPlays == false) + { + ImGui::BeginDisabled(); + } + + ImGui::Checkbox("Reapply Cheats Between Launches", &Config->bReapplyCheatsBetweenLaunches); + if (Config->bReapplyCheatsBetweenPlays == false) + { + ImGui::EndDisabled(); + } + + ImGui::Separator(); + if (ImGui::MenuItem("Reset Settings")) + { + ResetConfig(); + } + + ImGui::EndMenu(); + } + + ImGui::SameLine(); + + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 7); + + FString CategoryPreview; + if (Config->SelectedCategories.Num() == 0) + { + CategoryPreview = "None"; + } + else if (Config->SelectedCategories.Num() == 1) + { + CategoryPreview = *Config->SelectedCategories.CreateIterator(); + } + else + { + CategoryPreview = "Multiple"; + } + + const auto CategoryPreviewStr = StringCast(*CategoryPreview); + if (ImGui::BeginCombo("##Categories", CategoryPreviewStr.Get())) + { + for (const FCogEngineCheatCategory& CheatCategory : Asset->CheatCategories) + { + const auto CategoryStr = StringCast(*CheatCategory.Name); + bool IsSelected = Config->SelectedCategories.Contains(CheatCategory.Name); + if (ImGui::Checkbox(CategoryStr.Get(), &IsSelected)) + { + if (IsSelected) + { + Config->SelectedCategories.Add(CheatCategory.Name); + } + else + { + Config->SelectedCategories.Remove(CheatCategory.Name); + } + } + } + ImGui::EndCombo(); + } + + FCogWindowWidgets::SearchBar(Filter); + + ImGui::EndMenuBar(); + } + + APawn* ControlledActor = GetLocalPlayerPawn(); + + bool OpenTable = false; + if (Config->bGroupByCategories == false && Config->bUseTwoColumns) + { + OpenTable = DrawTable(); + } + + for (const FCogEngineCheatCategory& CheatCategory : Asset->CheatCategories) + { + const auto CategoryStr = StringCast(*CheatCategory.Name); + + if (Config->SelectedCategories.Num() != 0 && Config->SelectedCategories.Contains(CheatCategory.Name) == false) + { continue; } + + bool Open = true; + if (Config->bGroupByCategories) + { + ImGui::PushStyleColor(ImGuiCol_Header, IM_COL32(66, 66, 66, 79)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, IM_COL32(62, 62, 62, 204)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, IM_COL32(86, 86, 86, 255)); + + Open = ImGui::CollapsingHeader(CategoryStr.Get(), ImGuiTreeNodeFlags_DefaultOpen); + + ImGui::PopStyleColor(3); + + if (Open && Config->bUseTwoColumns) + { + DrawTable(); + } + } + + + if (Open) + { + if (Config->bUseTwoColumns) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + } + + int Index = 0; + for (const FCogEngineCheat& Cheat : CheatCategory.PersistentEffects) + { + AddCheat(Index, ControlledActor, SelectedActor, Cheat, true); + Index++; + } + + //---------------------------------------------------------------------------- + // Update the config of applied cheat to reapply them on the next launch. + // We do not update them only when the user input is pressed because + // the state of the cheat is lagging when connected to a server. + // So we check if the array should be updated all the time. + //---------------------------------------------------------------------------- + if (SelectedActor == ControlledActor) + { + for (const FCogEngineCheat& Cheat : CheatCategory.PersistentEffects) + { + TArray Targets = { SelectedActor }; + if (ACogEngineReplicator::IsCheatActiveOnTargets(Targets, Cheat) == ECogEngineCheat_ActiveState::Active) + { + Config->AppliedCheats.AddUnique(Cheat.Name); + } + else + { + Config->AppliedCheats.Remove(Cheat.Name); + } + } + } + + ImGui::TableNextColumn(); + + Index = 0; + for (const FCogEngineCheat& Cheat : CheatCategory.InstantEffects) + { + AddCheat(Index, ControlledActor, SelectedActor, Cheat, false); + Index++; + } + + if (Config->bGroupByCategories && Config->bUseTwoColumns) + { + ImGui::EndTable(); + } + } + } + + if (OpenTable) + { + ImGui::EndTable(); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogEngineWindow_Cheats::AddCheat(const int32 Index, AActor* ControlledActor, AActor* SelectedActor, const FCogEngineCheat& Cheat, bool IsPersistent) +{ + const auto CheatName = StringCast(*Cheat.Name); + + if (Filter.PassFilter(CheatName.Get()) == false) + { return false; } + + ImGui::PushID(Index); + + FCogWindowWidgets::PushBackColor(FCogImguiHelper::ToImVec4(Cheat.CustomColor)); + + const bool IsShiftDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Shift) != 0; + const bool IsAltDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Alt) != 0; + const bool IsControlDown = (ImGui::GetCurrentContext()->IO.KeyMods & ImGuiMod_Ctrl) != 0; + + bool bIsPressed = false; + if (IsPersistent) + { + TArray Targets = { SelectedActor }; + bool isEnabled = ACogEngineReplicator::IsCheatActiveOnTargets(Targets, Cheat) == ECogEngineCheat_ActiveState::Active; + if (ImGui::Checkbox(CheatName.Get(), &isEnabled)) + { + RequestCheat(ControlledActor, SelectedActor, Cheat, IsShiftDown, IsAltDown, IsControlDown); + bIsPressed = true; + } + } + else + { + if (ImGui::Button(CheatName.Get(), ImVec2(-1, 0))) + { + RequestCheat(ControlledActor, SelectedActor, Cheat, IsShiftDown, IsAltDown, IsControlDown); + bIsPressed = true; + } + } + + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsShiftDown || IsAltDown || IsControlDown ? 0.5f : 1.0f), "On Selection"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsShiftDown ? 1.0f : 0.5f), "On Enemies [SHIFT]"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsAltDown ? 1.0f : 0.5f), "On Allies [ALT]"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsControlDown ? 1.0f : 0.5f), "On Controlled [CTRL]"); + ImGui::EndTooltip(); + } + + FCogWindowWidgets::PopBackColor(); + + ImGui::PopID(); + + return bIsPressed; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_Cheats::RequestCheat(AActor* ControlledActor, AActor* SelectedActor, const FCogEngineCheat& Cheat, bool ApplyToEnemies, bool ApplyToAllies, bool ApplyToControlled) +{ + TArray Actors; + + if (ApplyToControlled) + { + Actors.Add(ControlledActor); + } + + if (ApplyToEnemies || ApplyToAllies) + { + for (TActorIterator It(GetWorld(), ACharacter::StaticClass()); It; ++It) + { + if (AActor* OtherActor = *It) + { + ECogCommonAllegiance Allegiance = ECogCommonAllegiance::Enemy; + + if (ICogCommonAllegianceActorInterface* AllegianceInterface = Cast(OtherActor)) + { + Allegiance = AllegianceInterface->GetAllegianceWithOtherActor(ControlledActor); + } + + if ((ApplyToEnemies && (Allegiance == ECogCommonAllegiance::Enemy)) + || (ApplyToAllies && (Allegiance == ECogCommonAllegiance::Friendly))) + { + Actors.Add(OtherActor); + } + } + } + } + + if ((ApplyToControlled || ApplyToEnemies || ApplyToAllies) == false) + { + Actors.Add(SelectedActor); + } + + if (ACogEngineReplicator* Replicator = ACogEngineReplicator::GetLocalReplicator(*GetWorld())) + { + Replicator->Server_ApplyCheat(ControlledActor, Actors, Cheat); + } + else + { + UE_LOG(LogCogImGui, Warning, TEXT("FCogAbilityWindow_Cheats::RequestCheat | Replicator not found")); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +const FCogEngineCheat* FCogEngineWindow_Cheats::FindCheatByName(const FString& CheatName, const bool OnlyPersistentCheats) +{ + for (const FCogEngineCheatCategory& CheatCategory : Asset->CheatCategories) + { + for (const FCogEngineCheat& Cheat : CheatCategory.PersistentEffects) + { + if (Cheat.Name == CheatName) + { + return &Cheat; + } + } + + if (OnlyPersistentCheats) + { + continue; + } + + for (const FCogEngineCheat& Cheat : CheatCategory.InstantEffects) + { + if (Cheat.Name == CheatName) + { + return &Cheat; + } + } + + + } + + return nullptr; +} diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineDataAsset.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineDataAsset.h index 8462ebd..c395a0a 100644 --- a/Plugins/Cog/Source/CogEngine/Public/CogEngineDataAsset.h +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineDataAsset.h @@ -5,6 +5,68 @@ #include "Engine/EngineTypes.h" #include "CogEngineDataAsset.generated.h" +class FCogWindow; +//-------------------------------------------------------------------------------------------------------------------------- +UENUM(BlueprintType) +enum class ECogEngineCheat_ActiveState : uint8 +{ + Inactive, + Partial, + Active, +}; + +//-------------------------------------------------------------------------------------------------------------------------- +UCLASS(BlueprintType, Abstract, Const, DefaultToInstanced, EditInlineNew, CollapseCategories) +class COGENGINE_API UCogEngineCheat_Execution + : public UObject +{ + GENERATED_BODY() + +public: + + UFUNCTION(BlueprintNativeEvent) + void Execute(const AActor* Instigator, const TArray& Targets) const; + + UFUNCTION(BlueprintNativeEvent) + ECogEngineCheat_ActiveState IsActiveOnTargets(const TArray& Targets) const; + + virtual bool GetColor(const FCogWindow& InCallingWindow, FLinearColor& OutColor) const; +}; + +//-------------------------------------------------------------------------------------------------------------------------- +USTRUCT() +struct COGENGINE_API FCogEngineCheat +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere) + FString Name; + + UPROPERTY(EditAnywhere, Instanced) + TObjectPtr Execution; + + UPROPERTY(EditAnywhere) + FLinearColor Color = FLinearColor::White; + + mutable FLinearColor CustomColor = FLinearColor::White; +}; + +//-------------------------------------------------------------------------------------------------------------------------- +USTRUCT() +struct COGENGINE_API FCogEngineCheatCategory +{ + GENERATED_BODY() + + UPROPERTY(Category = "Cheats", EditAnywhere) + FString Name; + + UPROPERTY(Category = "Cheats", EditAnywhere, meta = (TitleProperty = "Name")) + TArray PersistentEffects; + + UPROPERTY(Category = "Cheats", EditAnywhere, meta = (TitleProperty = "Name")) + TArray InstantEffects; +}; + //-------------------------------------------------------------------------------------------------------------------------- USTRUCT() struct COGENGINE_API FCogEngineSpawnEntry @@ -44,6 +106,9 @@ public: UCogEngineDataAsset() {} + UPROPERTY(Category = "Cheats", EditAnywhere, meta = (TitleProperty = "Name")) + TArray CheatCategories; + UPROPERTY(Category = "Spawns", EditAnywhere, meta = (TitleProperty = "Name")) TArray SpawnGroups; }; diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineReplicator.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineReplicator.h index 953712a..be13be5 100644 --- a/Plugins/Cog/Source/CogEngine/Public/CogEngineReplicator.h +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineReplicator.h @@ -1,6 +1,7 @@ #pragma once #include "CoreMinimal.h" +#include "CogEngineDataAsset.h" #include "GameFramework/Actor.h" #include "UObject/Class.h" #include "UObject/ObjectMacros.h" @@ -50,6 +51,11 @@ public: UFUNCTION(Server, Reliable) void Server_DeleteActor(AActor* Actor); + UFUNCTION(Reliable, Server) + void Server_ApplyCheat(const AActor* CheatInstigator, const TArray& TargetActors, const FCogEngineCheat& Cheat) const; + + static ECogEngineCheat_ActiveState IsCheatActiveOnTargets(const TArray& Targets, const FCogEngineCheat& Cheat); + protected: UFUNCTION(Server, Reliable) diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Cheats.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Cheats.h new file mode 100644 index 0000000..712c04d --- /dev/null +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Cheats.h @@ -0,0 +1,90 @@ +#pragma once + +#include "CoreMinimal.h" +#include "CogCommonConfig.h" +#include "CogWindow.h" +#include "CogEngineWindow_Cheats.generated.h" + +class AActor; +class UCogEngineConfig_Cheats; +class UCogEngineDataAsset; +struct FCogEngineCheat; + +//-------------------------------------------------------------------------------------------------------------------------- +class COGENGINE_API FCogEngineWindow_Cheats : public FCogWindow +{ + typedef FCogWindow Super; + +public: + + virtual void Initialize() override; + +protected: + + virtual void GameTick(float DeltaTime) override; + + virtual void ResetConfig() override; + + virtual void RenderHelp() override; + + virtual void RenderContent() override; + + virtual void TryReapplyCheats(); + + virtual bool AddCheat(const int32 Index, AActor* ControlledActor, AActor* TargetActor, const FCogEngineCheat& CheatEffect, bool IsPersistent); + + virtual void RequestCheat(AActor* ControlledActor, AActor* SelectedActor, const FCogEngineCheat& Cheat, bool ApplyToEnemies, bool ApplyToAllies, bool ApplyToControlled); + + virtual const FCogEngineCheat* FindCheatByName(const FString& CheatName, const bool OnlyPersistentCheats); + + static bool DrawTable(); + + void UpdateCheatColor(const FCogEngineCheat& Cheat) const; + + TObjectPtr Asset = nullptr; + + TObjectPtr Config = nullptr; + + bool bHasReappliedCheats = false; + + ImGuiTextFilter Filter; + + TArray AllCheats; +}; + +//-------------------------------------------------------------------------------------------------------------------------- +UCLASS(Config = Cog) +class UCogEngineConfig_Cheats : public UCogCommonConfig +{ + GENERATED_BODY() + +public: + + UPROPERTY(Config) + bool bGroupByCategories = true; + + UPROPERTY(Config) + bool bReapplyCheatsBetweenPlays = true; + + UPROPERTY(Config) + bool bReapplyCheatsBetweenLaunches = true; + + UPROPERTY(Config) + bool bUseTwoColumns = true; + + UPROPERTY(Config) + TArray AppliedCheats; + + UPROPERTY(Config) + TSet SelectedCategories; + + virtual void Reset() override + { + Super::Reset(); + + bReapplyCheatsBetweenPlays = true; + bReapplyCheatsBetweenLaunches = true; + AppliedCheats.Empty(); + SelectedCategories.Empty(); + } +}; diff --git a/Plugins/CogAbility/Source/CogAbility/CogAbility.Build.cs b/Plugins/CogAbility/Source/CogAbility/CogAbility.Build.cs index 16e7478..b81d069 100644 --- a/Plugins/CogAbility/Source/CogAbility/CogAbility.Build.cs +++ b/Plugins/CogAbility/Source/CogAbility/CogAbility.Build.cs @@ -1,5 +1,4 @@ using UnrealBuildTool; -using UnrealBuildTool.Rules; public class CogAbility : ModuleRules { @@ -26,10 +25,11 @@ public class CogAbility : ModuleRules "CogImgui", "CogCommon", "CogDebug", + "CogEngine", "CogWindow", "GameplayAbilities", "GameplayTags", - "NetCore", + "NetCore", } ); diff --git a/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityCheat_Execution_ApplyEffect.cpp b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityCheat_Execution_ApplyEffect.cpp new file mode 100644 index 0000000..1636fee --- /dev/null +++ b/Plugins/CogAbility/Source/CogAbility/Private/CogAbilityCheat_Execution_ApplyEffect.cpp @@ -0,0 +1,111 @@ +#include "CogAbilityCheat_Execution_ApplyEffect.h" + +#include "CogAbilityDataAsset.h" + +#include "AbilitySystemComponent.h" +#include "AbilitySystemGlobals.h" +#include "CogAbilityConfig_Alignment.h" +#include "CogImguiHelper.h" +#include "CogWindow.h" + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogAbilityCheat_Execution_ApplyEffect::Execute_Implementation(const AActor* Instigator, const TArray& Targets) const +{ + UAbilitySystemComponent* DefaultInstigatorAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(Instigator, true); + + for (AActor* Target : Targets) + { + UAbilitySystemComponent* TargetAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(Target, true); + if (TargetAbilitySystem == nullptr) + { + UE_LOG(LogCogImGui, Warning, TEXT("ACogAbilityReplicator::Server_ApplyCheat_Implementation | Target:%s | Invalid Target AbilitySystem"), *GetNameSafe(Target)); + continue; + } + + if (TargetAbilitySystem->GetGameplayEffectCount(Effect, nullptr) > 0) + { + TargetAbilitySystem->RemoveActiveGameplayEffectBySourceEffect(Effect, nullptr); + } + else + { + //----------------------------------------------------------------------------------- + // When executing a cheat directly on the game server, there is not an obvious + // local player to use as the instigator. Instead, we use the target ability system. + //----------------------------------------------------------------------------------- + UAbilitySystemComponent* InstigatorAbilitySystem = (DefaultInstigatorAbilitySystem != nullptr) ? DefaultInstigatorAbilitySystem : TargetAbilitySystem; + + FGameplayEffectContextHandle ContextHandle = InstigatorAbilitySystem->MakeEffectContext(); + ContextHandle.AddSourceObject(InstigatorAbilitySystem); + FGameplayEffectSpecHandle SpecHandle = InstigatorAbilitySystem->MakeOutgoingSpec(Effect, 1, ContextHandle); + + if (const FGameplayEffectSpec* EffectSpec = SpecHandle.Data.Get()) + { + FHitResult HitResult; + HitResult.HitObjectHandle = FActorInstanceHandle(Target); + HitResult.Normal = FVector::ForwardVector; + HitResult.ImpactNormal = FVector::ForwardVector; + HitResult.Location = Target->GetActorLocation(); + HitResult.ImpactPoint = Target->GetActorLocation(); + HitResult.PhysMaterial = nullptr; + ContextHandle.AddHitResult(HitResult, true); + + InstigatorAbilitySystem->ApplyGameplayEffectSpecToTarget(*EffectSpec, TargetAbilitySystem); + } + } + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +ECogEngineCheat_ActiveState UCogAbilityCheat_Execution_ApplyEffect::IsActiveOnTargets_Implementation(const TArray& Targets) const +{ + if (Effect == nullptr) + { + return ECogEngineCheat_ActiveState::Inactive; + } + + int32 NumWithEffect = 0; + for (const AActor* Target : Targets) + { + const UAbilitySystemComponent* AbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(Target, true); + if (AbilitySystem == nullptr) + { + continue; + } + + const int32 Count = AbilitySystem->GetGameplayEffectCount(Effect, nullptr); + if (Count > 0) + { + NumWithEffect++; + } + } + + if (NumWithEffect == 0) + { + return ECogEngineCheat_ActiveState::Inactive; + } + + if (NumWithEffect == Targets.Num()) + { + return ECogEngineCheat_ActiveState::Active; + } + + return ECogEngineCheat_ActiveState::Partial; +} + + +//-------------------------------------------------------------------------------------------------------------------------- +bool UCogAbilityCheat_Execution_ApplyEffect::GetColor(const FCogWindow& InCallingWindow, FLinearColor& OutColor) const +{ + if (Effect == nullptr) + { return false; } + + const UGameplayEffect* GameplayEffect = Effect->GetDefaultObject(); + if (GameplayEffect == nullptr) + { return false; } + + const UCogAbilityConfig_Alignment* Config = InCallingWindow.GetConfig(); + const UCogAbilityDataAsset* Asset = InCallingWindow.GetAsset(); + + OutColor = Config->GetEffectColor(Asset, *GameplayEffect); + return true; +} diff --git a/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityCheat_Execution_ApplyEffect.h b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityCheat_Execution_ApplyEffect.h new file mode 100644 index 0000000..fd388e9 --- /dev/null +++ b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilityCheat_Execution_ApplyEffect.h @@ -0,0 +1,24 @@ +#pragma once + +#include "CoreMinimal.h" +#include "CogEngineDataAsset.h" +#include "GameplayEffect.h" +#include "CogAbilityCheat_Execution_ApplyEffect.generated.h" + +//-------------------------------------------------------------------------------------------------------------------------- +UCLASS(DisplayName = "Apply Effect") +class COGABILITY_API UCogAbilityCheat_Execution_ApplyEffect + : public UCogEngineCheat_Execution +{ + GENERATED_BODY() + +public: + void Execute_Implementation(const AActor* Instigator, const TArray& Targets) const override; + + ECogEngineCheat_ActiveState IsActiveOnTargets_Implementation(const TArray& Targets) const override; + + virtual bool GetColor(const FCogWindow& InCallingWindow, FLinearColor& OutColor) const override; + + UPROPERTY(EditAnywhere) + TSubclassOf Effect; +}; diff --git a/Plugins/CogAll/Source/CogAll/Private/CogAll.cpp b/Plugins/CogAll/Source/CogAll/Private/CogAll.cpp index 6425a08..ad4b176 100644 --- a/Plugins/CogAll/Source/CogAll/Private/CogAll.cpp +++ b/Plugins/CogAll/Source/CogAll/Private/CogAll.cpp @@ -2,7 +2,6 @@ #include "CogAbilityWindow_Abilities.h" #include "CogAbilityWindow_Attributes.h" -#include "CogAbilityWindow_Cheats.h" #include "CogAbilityWindow_Effects.h" #include "CogAbilityWindow_Pools.h" #include "CogAbilityWindow_Tags.h" @@ -10,6 +9,7 @@ #include "CogAbilityWindow_Tweaks.h" #include "CogAIWindow_BehaviorTree.h" #include "CogAIWindow_Blackboard.h" +#include "CogEngineWindow_Cheats.h" #include "CogEngineWindow_CollisionTester.h" #include "CogEngineWindow_CollisionViewer.h" #include "CogEngineWindow_CommandBindings.h" @@ -103,7 +103,9 @@ void Cog::AddAllWindows(UCogWindowManager& CogWindowManager) CogWindowManager.AddWindow("Gameplay.Blocking Tags"); - CogWindowManager.AddWindow("Gameplay.Cheats"); + //CogWindowManager.AddWindow("Gameplay.Cheats"); + + CogWindowManager.AddWindow("Gameplay.Cheats"); CogWindowManager.AddWindow("Gameplay.Effects");