mirror of
https://github.com/Ed94/Cog.git
synced 2026-06-13 08:02:23 -07:00
Cog Sample: Adding more gameplay
Cog Sample: Make Area a component instead of an actor Cog Sample: Add Basic actor for Projectiles, Areas, etc... Cog Sample: Start to add Projectile Cog Sample: Start to add SpawnPrediction
This commit is contained in:
@@ -105,10 +105,17 @@ ManualIPAddress=
|
||||
+Profiles=(Name="Ragdoll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Simulating Skeletal Mesh Component. All other channels will be set to default.")
|
||||
+Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.")
|
||||
+Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility"),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
|
||||
+Profiles=(Name="CogSampleProfile",CollisionEnabled=QueryAndPhysics,bCanModify=True,ObjectTypeName="",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Sample cog profile")
|
||||
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Block,bTraceType=False,bStaticObject=False,Name="CogSampleChannel")
|
||||
+EditProfiles=(Name="Pawn",CustomResponses=((Channel="Camera",Response=ECR_Ignore)))
|
||||
+EditProfiles=(Name="CharacterMesh",CustomResponses=((Channel="Camera",Response=ECR_Ignore)))
|
||||
+Profiles=(Name="ProjectileCollision",CollisionEnabled=QueryOnly,bCanModify=True,ObjectTypeName="Projectile",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Needs description")
|
||||
+Profiles=(Name="ProjectileAssistance",CollisionEnabled=QueryOnly,bCanModify=True,ObjectTypeName="Projectile",CustomResponses=((Channel="WorldStatic",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Needs description")
|
||||
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel2,DefaultResponse=ECR_Ignore,bTraceType=False,bStaticObject=False,Name="Projectile")
|
||||
+EditProfiles=(Name="Pawn",CustomResponses=((Channel="Camera",Response=ECR_Ignore),(Channel="Projectile",Response=ECR_Ignore)))
|
||||
+EditProfiles=(Name="CharacterMesh",CustomResponses=((Channel="Camera",Response=ECR_Ignore),(Channel="Projectile",Response=ECR_Overlap)))
|
||||
+EditProfiles=(Name="BlockAll",CustomResponses=((Channel="Projectile")))
|
||||
+EditProfiles=(Name="OverlapAll",CustomResponses=((Channel="Projectile",Response=ECR_Overlap)))
|
||||
+EditProfiles=(Name="BlockAllDynamic",CustomResponses=((Channel="Projectile")))
|
||||
+EditProfiles=(Name="OverlapAllDynamic",CustomResponses=((Channel="Projectile",Response=ECR_Overlap)))
|
||||
+EditProfiles=(Name="IgnoreOnlyPawn",CustomResponses=((Channel="Projectile")))
|
||||
+EditProfiles=(Name="OverlapOnlyPawn",CustomResponses=((Channel="Projectile")))
|
||||
-ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
|
||||
-ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
|
||||
-ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,7 @@
|
||||
#include "CogEngineWindow_NetEmulation.h"
|
||||
|
||||
#include "CogEngineWindow_Stats.h"
|
||||
#include "CogWindowWidgets.h"
|
||||
#include "Engine/Engine.h"
|
||||
#include "Engine/NetDriver.h"
|
||||
#include "Engine/NetConnection.h"
|
||||
@@ -111,7 +112,7 @@ void UCogEngineWindow_NetEmulation::DrawControls()
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
FCogWindowWidgets::SetNextItemToShortWidth();
|
||||
if (ImGui::DragInt("Lag Min", &Settings.PktLagMin, 1.0f, 0, INT_MAX, "%d ms"))
|
||||
if (ImGui::DragInt("Lag Min", &Settings.PktLagMin, 5.0f, 0, INT_MAX, "%d ms"))
|
||||
{
|
||||
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
|
||||
}
|
||||
@@ -123,7 +124,7 @@ void UCogEngineWindow_NetEmulation::DrawControls()
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
FCogWindowWidgets::SetNextItemToShortWidth();
|
||||
if (ImGui::DragInt("Lag Max", &Settings.PktLagMax, 1.0f, 0, INT_MAX, "%d ms"))
|
||||
if (ImGui::DragInt("Lag Max", &Settings.PktLagMax, 5.0f, 0, INT_MAX, "%d ms"))
|
||||
{
|
||||
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
|
||||
}
|
||||
@@ -184,7 +185,7 @@ void UCogEngineWindow_NetEmulation::DrawControls()
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
FCogWindowWidgets::SetNextItemToShortWidth();
|
||||
if (ImGui::DragInt("Incoming Lag Min", &Settings.PktIncomingLagMin, 1.0f, 0, INT_MAX, "%d ms"))
|
||||
if (ImGui::DragInt("Incoming Lag Min", &Settings.PktIncomingLagMin, 5.0f, 0, INT_MAX, "%d ms"))
|
||||
{
|
||||
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
|
||||
}
|
||||
@@ -196,7 +197,7 @@ void UCogEngineWindow_NetEmulation::DrawControls()
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
FCogWindowWidgets::SetNextItemToShortWidth();
|
||||
if (ImGui::DragInt("Incoming Lag Max", &Settings.PktIncomingLagMax, 1.0f, 0, INT_MAX, "%d ms"))
|
||||
if (ImGui::DragInt("Incoming Lag Max", &Settings.PktIncomingLagMax, 5.0f, 0, INT_MAX, "%d ms"))
|
||||
{
|
||||
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
|
||||
}
|
||||
|
||||
@@ -558,40 +558,32 @@ bool UCogEngineWindow_Selection::ComputeBoundingBoxScreenPosition(const APlayerC
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogEngineWindow_Selection::RenderMainMenuWidget(bool Draw, float& Width)
|
||||
float UCogEngineWindow_Selection::GetMainMenuWidgetWidth(int32 SubWidgetIndex, float MaxWidth)
|
||||
{
|
||||
const float PickButtonWidth = FCogWindowWidgets::GetFontWidth() * 6;
|
||||
const float SelectionButtonWidth = FCogWindowWidgets::GetFontWidth() * 30;
|
||||
const float ResetButtonWidth = FCogWindowWidgets::GetFontWidth() * 3;
|
||||
Width = PickButtonWidth + SelectionButtonWidth + ResetButtonWidth;
|
||||
|
||||
if (Draw == false)
|
||||
switch (SubWidgetIndex)
|
||||
{
|
||||
return;
|
||||
case 0: return FCogWindowWidgets::GetFontWidth() * 6;
|
||||
case 1: return FMath::Min(FMath::Max(MaxWidth, FCogWindowWidgets::GetFontWidth() * 10), FCogWindowWidgets::GetFontWidth() * 30);
|
||||
case 2: return FCogWindowWidgets::GetFontWidth() * 3;
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("SelectionPopup"))
|
||||
{
|
||||
ImGui::BeginChild("Popup", ImVec2(Width, FCogWindowWidgets::GetFontWidth() * 40), false);
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
if (DrawSelectionCombo())
|
||||
{
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogEngineWindow_Selection::RenderMainMenuWidget(int32 SubWidgetIndex, float Width)
|
||||
{
|
||||
//-----------------------------------
|
||||
// Pick Button
|
||||
//-----------------------------------
|
||||
if (SubWidgetIndex == 0)
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
|
||||
|
||||
if (ImGui::Button("Pick", ImVec2(PickButtonWidth, 0)))
|
||||
if (ImGui::Button("Pick", ImVec2(Width, 0)))
|
||||
{
|
||||
ActivateSelectionMode();
|
||||
HackWaitInputRelease();
|
||||
@@ -601,52 +593,67 @@ void UCogEngineWindow_Selection::RenderMainMenuWidget(bool Draw, float& Width)
|
||||
ImGui::PopStyleColor(1);
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
AActor* GlobalSelection = FCogDebugSettings::GetSelection();
|
||||
|
||||
//-----------------------------------
|
||||
// Selection
|
||||
//-----------------------------------
|
||||
else if (SubWidgetIndex == 1)
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
|
||||
ImGui::SameLine();
|
||||
FString CurrentSelectionName = GetActorName(GlobalSelection);
|
||||
if (ImGui::BeginPopup("SelectionPopup"))
|
||||
{
|
||||
ImGui::BeginChild("Popup", ImVec2(Width, FCogWindowWidgets::GetFontWidth() * 40), false);
|
||||
|
||||
if (ImGui::Button(TCHAR_TO_ANSI(*CurrentSelectionName), ImVec2(SelectionButtonWidth, 0)))
|
||||
{
|
||||
ImGui::OpenPopup("SelectionPopup");
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("Current Selection: %s", TCHAR_TO_ANSI(*CurrentSelectionName));
|
||||
if (DrawSelectionCombo())
|
||||
{
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(1);
|
||||
ImGui::PopStyleVar(2);
|
||||
AActor* GlobalSelection = FCogDebugSettings::GetSelection();
|
||||
|
||||
DrawActorContextMenu(GlobalSelection);
|
||||
//-----------------------------------
|
||||
// Selection
|
||||
//-----------------------------------
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
|
||||
FString CurrentSelectionName = GetActorName(GlobalSelection);
|
||||
|
||||
if (ImGui::Button(TCHAR_TO_ANSI(*CurrentSelectionName), ImVec2(Width, 0.0f)))
|
||||
{
|
||||
ImGui::OpenPopup("SelectionPopup");
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("Current Selection: %s", TCHAR_TO_ANSI(*CurrentSelectionName));
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(1);
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
DrawActorContextMenu(GlobalSelection);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
// Reset Button
|
||||
//-----------------------------------
|
||||
else if (SubWidgetIndex == 2)
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("X", ImVec2(ResetButtonWidth, 0)))
|
||||
//-----------------------------------
|
||||
// Reset Button
|
||||
//-----------------------------------
|
||||
{
|
||||
SetGlobalSelection(nullptr);
|
||||
ImGui::CloseCurrentPopup();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
|
||||
if (ImGui::Button("X", ImVec2(Width, 0)))
|
||||
{
|
||||
SetGlobalSelection(nullptr);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("Reset the selection to the controlled actor.");
|
||||
}
|
||||
ImGui::PopStyleColor(1);
|
||||
ImGui::PopStyleVar(1);
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("Reset the selection to the controlled actor.");
|
||||
}
|
||||
ImGui::PopStyleColor(1);
|
||||
ImGui::PopStyleVar(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
#include "CogWindowWidgets.h"
|
||||
#include "Engine/Engine.h"
|
||||
#include "Engine/NetDriver.h"
|
||||
#include "Engine/NetConnection.h"
|
||||
#include "GameFramework/PlayerState.h"
|
||||
#include "Net/NetPing.h"
|
||||
|
||||
ImVec4 StatRedColor(1.0f, 0.4f, 0.3f, 1.0f);
|
||||
ImVec4 StatOrangeColor(1.0f, 0.7f, 0.4f, 1.0f);
|
||||
@@ -53,39 +55,170 @@ void UCogEngineWindow_Stats::RenderContent()
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogEngineWindow_Stats::RenderMainMenuWidget(bool Draw, float& Width)
|
||||
float UCogEngineWindow_Stats::GetMainMenuWidgetWidth(int32 WidgetIndex, float MaxWidth)
|
||||
{
|
||||
Width = FCogWindowWidgets::GetFontWidth() * 25;
|
||||
const APlayerController* PlayerController = GetLocalPlayerController();
|
||||
const UNetConnection* Connection = PlayerController != nullptr ? PlayerController->GetNetConnection() : nullptr;
|
||||
|
||||
if (Draw == false)
|
||||
switch (WidgetIndex)
|
||||
{
|
||||
case 0: return FCogWindowWidgets::GetFontWidth() * 8;
|
||||
case 1: return Connection != nullptr ? FCogWindowWidgets::GetFontWidth() * 7 : 0.0f;
|
||||
case 2: return Connection != nullptr ? FCogWindowWidgets::GetFontWidth() * 7 : 0.0f;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogEngineWindow_Stats::RenderMainMenuWidget(int32 WidgetIndex, float Width)
|
||||
{
|
||||
switch (WidgetIndex)
|
||||
{
|
||||
case 0: RenderMainMenuWidgetFramerate(Width); break;
|
||||
case 1: RenderMainMenuWidgetPing(Width); break;
|
||||
case 2: RenderMainMenuWidgetPacketLoss(Width); break;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogEngineWindow_Stats::RenderMainMenuWidgetFramerate(float Width)
|
||||
{
|
||||
extern ENGINE_API float GAverageFPS;
|
||||
int32 Fps = (int32)GAverageFPS;
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, GetFpsColor(Fps));
|
||||
|
||||
if (ImGui::Button(TCHAR_TO_ANSI(*FString::Printf(TEXT("%3dfps###FramerateButton"), Fps)), ImVec2(Width, 0.0f)))
|
||||
{
|
||||
ImGui::OpenPopup("FrameratePopup");
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
ImGui::SetItemTooltip("Framerate");
|
||||
|
||||
if (ImGui::BeginPopup("FrameratePopup"))
|
||||
{
|
||||
ImGui::Text("Fps");
|
||||
ImGui::SameLine();
|
||||
|
||||
int32 MaxFps = GEngine->GetMaxFPS();
|
||||
TArray<int32> Values{ 0, 10, 20, 30, 60, 120 };
|
||||
if (FCogWindowWidgets::MultiChoiceButtonsInt(Values, MaxFps, ImVec2(3.5f * FCogWindowWidgets::GetFontWidth(), 0)))
|
||||
{
|
||||
GEngine->SetMaxFPS(MaxFps);
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogEngineWindow_Stats::RenderMainMenuWidgetPing(float Width)
|
||||
{
|
||||
const APlayerController* PlayerController = GetLocalPlayerController();
|
||||
const APlayerState* PlayerState = PlayerController != nullptr ? PlayerController->GetPlayerState<APlayerState>() : nullptr;
|
||||
if (PlayerState == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
extern ENGINE_API float GAverageFPS;
|
||||
ImGui::TextColored(GetFpsColor(GAverageFPS), "%3dfps ", (int32)GAverageFPS);
|
||||
ImGui::SetItemTooltip("Frame Per Second");
|
||||
const float Ping = PlayerState->GetPingInMilliseconds();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, GetPingColor(Ping));
|
||||
|
||||
if (const APlayerController* PlayerController = GetLocalPlayerController())
|
||||
if (ImGui::Button(TCHAR_TO_ANSI(*FString::Printf(TEXT("%3dms###PingButton"), (int32)Ping)), ImVec2(Width, 0.0f)))
|
||||
{
|
||||
if (const APlayerState* PlayerState = PlayerController->GetPlayerState<APlayerState>())
|
||||
{
|
||||
const float Ping = PlayerState->GetPingInMilliseconds();
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(GetPingColor(Ping), "%3dms ", (int32)Ping);
|
||||
ImGui::SetItemTooltip("Ping");
|
||||
}
|
||||
|
||||
if (UNetConnection* Connection = PlayerController->GetNetConnection())
|
||||
{
|
||||
const float OutPacketLost = Connection->GetOutLossPercentage().GetAvgLossPercentage() * 100.0f;
|
||||
const float InPacketLost = Connection->GetInLossPercentage().GetAvgLossPercentage() * 100.0f;
|
||||
const float TotalPacketLost = OutPacketLost + InPacketLost;
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(GetPacketLossColor(TotalPacketLost), "%2d%% ", (int32)TotalPacketLost);
|
||||
ImGui::SetItemTooltip("Packet Loss");
|
||||
}
|
||||
ImGui::OpenPopup("PingPopup");
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
ImGui::SetItemTooltip("Ping");
|
||||
|
||||
#if DO_ENABLE_NET_TEST
|
||||
if (ImGui::BeginPopup("PingPopup"))
|
||||
{
|
||||
|
||||
FWorldContext& WorldContext = GEngine->GetWorldContextFromWorldChecked(GetWorld());
|
||||
if (WorldContext.ActiveNetDrivers.Num() > 0)
|
||||
{
|
||||
ImGui::Text("Ping");
|
||||
ImGui::SameLine();
|
||||
|
||||
FNamedNetDriver* SelectedNetDriver = &WorldContext.ActiveNetDrivers[0];
|
||||
FPacketSimulationSettings Settings = SelectedNetDriver->NetDriver->PacketSimulationSettings;
|
||||
TArray<int32> Values{ 0, 50, 100, 200, 500, 1000 };
|
||||
if (FCogWindowWidgets::MultiChoiceButtonsInt(Values, Settings.PktIncomingLagMin, ImVec2(4.5f * FCogWindowWidgets::GetFontWidth(), 0)))
|
||||
{
|
||||
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
|
||||
}
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
#endif //DO_ENABLE_NET_TEST
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogEngineWindow_Stats::RenderMainMenuWidgetPacketLoss(float Width)
|
||||
{
|
||||
const APlayerController* PlayerController = GetLocalPlayerController();
|
||||
UNetConnection* Connection = PlayerController != nullptr ? PlayerController->GetNetConnection() : nullptr;
|
||||
if (Connection == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const float OutPacketLost = Connection->GetOutLossPercentage().GetAvgLossPercentage() * 100.0f;
|
||||
const float InPacketLost = Connection->GetInLossPercentage().GetAvgLossPercentage() * 100.0f;
|
||||
const float TotalPacketLost = (OutPacketLost + InPacketLost) / 2;
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, GetPacketLossColor(TotalPacketLost));
|
||||
|
||||
if (ImGui::Button(TCHAR_TO_ANSI(*FString::Printf(TEXT("%2d%%###PacketLossButton"), (int32)TotalPacketLost)), ImVec2(Width, 0.0f)))
|
||||
{
|
||||
ImGui::OpenPopup("PacketLossPopup");
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
ImGui::SetItemTooltip("Packet Loss");
|
||||
|
||||
#if DO_ENABLE_NET_TEST
|
||||
if (ImGui::BeginPopup("PacketLossPopup"))
|
||||
{
|
||||
|
||||
FWorldContext& WorldContext = GEngine->GetWorldContextFromWorldChecked(GetWorld());
|
||||
if (WorldContext.ActiveNetDrivers.Num() > 0)
|
||||
{
|
||||
ImGui::Text("Packet Loss");
|
||||
ImGui::SameLine();
|
||||
|
||||
FNamedNetDriver* SelectedNetDriver = &WorldContext.ActiveNetDrivers[0];
|
||||
FPacketSimulationSettings Settings = SelectedNetDriver->NetDriver->PacketSimulationSettings;
|
||||
|
||||
TArray<int32> Values{ 0, 5, 10, 20, 30, 40, 50 };
|
||||
if (FCogWindowWidgets::MultiChoiceButtonsInt(Values, Settings.PktIncomingLoss, ImVec2(3.5f * FCogWindowWidgets::GetFontWidth(), 0)))
|
||||
{
|
||||
Settings.PktLoss = Settings.PktIncomingLoss;
|
||||
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
|
||||
}
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
#endif //DO_ENABLE_NET_TEST
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "CogEngineWindow_TimeScale.h"
|
||||
|
||||
#include "CogEngineReplicator.h"
|
||||
#include "CogWindowWidgets.h"
|
||||
#include "Engine/Engine.h"
|
||||
#include "Engine/World.h"
|
||||
|
||||
@@ -43,49 +44,11 @@ void UCogEngineWindow_TimeScale::RenderContent()
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiStyle& Style = ImGui::GetStyle();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(Style.WindowPadding.x * 0.40f, (float)(int)(Style.WindowPadding.y * 0.60f)));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(Style.FramePadding.x * 0.40f, (float)(int)(Style.FramePadding.y * 0.60f)));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(Style.ItemSpacing.x * 0.30f, (float)(int)(Style.ItemSpacing.y * 0.60f)));
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, IM_COL32(255, 255, 255, 180));
|
||||
|
||||
for (float TimeScale : TimingScales)
|
||||
{
|
||||
DrawTimeButton(Replicator, TimeScale);
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(1);
|
||||
ImGui::PopStyleVar(3);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogEngineWindow_TimeScale::DrawTimeButton(ACogEngineReplicator* Replicator, float Value)
|
||||
{
|
||||
const bool IsSelected = FMath::IsNearlyEqual(Replicator->GetTimeDilation(), Value, 0.0001f);
|
||||
if (IsSelected)
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(128, 128, 128, 50));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32(128, 128, 128, 100));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, IM_COL32(128, 128, 128, 150));
|
||||
}
|
||||
|
||||
const char* Text = TCHAR_TO_ANSI(*FString::Printf(TEXT("%g"), Value).Replace(TEXT("0."), TEXT(".")));
|
||||
if (ImGui::Button(Text, ImVec2(3.5f * FCogWindowWidgets::GetFontWidth(), 0)))
|
||||
|
||||
float Value = Replicator->GetTimeDilation();
|
||||
if (FCogWindowWidgets::MultiChoiceButtonsFloat(TimingScales, Value, ImVec2(3.5f * FCogWindowWidgets::GetFontWidth(), 0)))
|
||||
{
|
||||
Replicator->Server_SetTimeDilation(Value);
|
||||
}
|
||||
|
||||
if (IsSelected)
|
||||
{
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PopStyleColor(3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,9 @@ protected:
|
||||
|
||||
virtual void RenderContent() override;
|
||||
|
||||
virtual void RenderMainMenuWidget(bool Draw, float& Width) override;
|
||||
virtual float GetMainMenuWidgetWidth(int32 SubWidgetIndex, float MaxWidth) override;
|
||||
|
||||
virtual void RenderMainMenuWidget(int32 SubWidgetIndex, float Width) override;
|
||||
|
||||
virtual bool DrawSelectionCombo();
|
||||
|
||||
|
||||
@@ -23,5 +23,10 @@ protected:
|
||||
|
||||
virtual void RenderContent() override;
|
||||
|
||||
virtual void RenderMainMenuWidget(bool Draw, float& Width) override;
|
||||
virtual float GetMainMenuWidgetWidth(int32 SubWidgetIndex, float MaxWidth) override;
|
||||
|
||||
virtual void RenderMainMenuWidget(int32 SubWidgetIndex, float Width) override;
|
||||
void RenderMainMenuWidgetPacketLoss(float Width);
|
||||
void RenderMainMenuWidgetPing(float Width);
|
||||
void RenderMainMenuWidgetFramerate(float Width);
|
||||
};
|
||||
|
||||
@@ -21,8 +21,6 @@ protected:
|
||||
|
||||
virtual void RenderContent() override;
|
||||
|
||||
virtual void DrawTimeButton(ACogEngineReplicator* Replicator, float Value);
|
||||
|
||||
TArray<float> TimingScales;
|
||||
|
||||
private:
|
||||
|
||||
@@ -384,21 +384,55 @@ void UCogWindowManager::RenderMainMenu()
|
||||
|
||||
for (UCogWindow* Window : MainMenuWidgets)
|
||||
{
|
||||
float Width = 0.0f;
|
||||
Window->RenderMainMenuWidget(false, Width);
|
||||
TArray<float> SubWidgetsWidths;
|
||||
float SimCursorX = CursorX;
|
||||
for (int32 SubWidgetIndex = 0; ; ++SubWidgetIndex)
|
||||
{
|
||||
const float MaxWidth = SimCursorX - MinCursorX;
|
||||
float SubWidgetWidth = Window->GetMainMenuWidgetWidth(SubWidgetIndex, MaxWidth);
|
||||
if (SubWidgetWidth == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
// Stop drawing if there is not enough room
|
||||
//-------------------------------------------
|
||||
if (CursorX - Width < MinCursorX)
|
||||
SimCursorX -= SubWidgetWidth;
|
||||
SubWidgetsWidths.Add(SubWidgetWidth);
|
||||
}
|
||||
|
||||
bool Stop = false;
|
||||
for (int32 SubWidgetIndex = SubWidgetsWidths.Num() - 1; SubWidgetIndex >= 0; SubWidgetIndex--)
|
||||
{
|
||||
const float SubWidgetWidth = SubWidgetsWidths[SubWidgetIndex];
|
||||
const float MaxWidth = CursorX - MinCursorX;
|
||||
|
||||
//-------------------------------------------
|
||||
// Bypass this subwidget if its width is 0
|
||||
//-------------------------------------------
|
||||
if (SubWidgetWidth == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
// Stop drawing if there is not enough room
|
||||
//-------------------------------------------
|
||||
if (SubWidgetWidth > MaxWidth)
|
||||
{
|
||||
Stop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
CursorX -= SubWidgetWidth;
|
||||
ImGui::SetCursorPosX(CursorX);
|
||||
|
||||
Window->RenderMainMenuWidget(SubWidgetIndex, SubWidgetWidth);
|
||||
}
|
||||
|
||||
if (Stop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
CursorX -= Width;
|
||||
ImGui::SetCursorPosX(CursorX);
|
||||
Window->RenderMainMenuWidget(true, Width);
|
||||
|
||||
CursorX -= ImGui::GetStyle().ItemSpacing.x;
|
||||
}
|
||||
|
||||
|
||||
@@ -474,5 +474,99 @@ bool FCogWindowWidgets::DeleteArrayItemButton()
|
||||
ImGui::SetTooltip("Delete Item");
|
||||
}
|
||||
|
||||
return IsPressed;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool FCogWindowWidgets::MultiChoiceButton(const char* Label, bool IsSelected, const ImVec2& Size)
|
||||
{
|
||||
if (IsSelected)
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(128, 128, 128, 50));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32(128, 128, 128, 100));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, IM_COL32(128, 128, 128, 150));
|
||||
}
|
||||
|
||||
const bool IsPressed = ImGui::Button(Label, Size);
|
||||
|
||||
if (IsSelected)
|
||||
{
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PopStyleColor(3);
|
||||
}
|
||||
|
||||
return IsPressed;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool FCogWindowWidgets::MultiChoiceButtonsInt(TArray<int32>& Values, int32& Value, const ImVec2& Size)
|
||||
{
|
||||
ImGuiStyle& Style = ImGui::GetStyle();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(Style.WindowPadding.x * 0.40f, (float)(int)(Style.WindowPadding.y * 0.60f)));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(Style.FramePadding.x * 0.40f, (float)(int)(Style.FramePadding.y * 0.60f)));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(Style.ItemSpacing.x * 0.30f, (float)(int)(Style.ItemSpacing.y * 0.60f)));
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, IM_COL32(255, 255, 255, 180));
|
||||
|
||||
bool IsPressed = false;
|
||||
for (int32 i = 0; i < Values.Num(); ++i)
|
||||
{
|
||||
int32 ButtonValue = Values[i];
|
||||
|
||||
const char* Text = TCHAR_TO_ANSI(*FString::Printf(TEXT("%d"), ButtonValue));
|
||||
if (MultiChoiceButton(Text, ButtonValue == Value, Size))
|
||||
{
|
||||
IsPressed = true;
|
||||
Value = ButtonValue;
|
||||
}
|
||||
|
||||
if (i < Values.Num() - 1)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(1);
|
||||
ImGui::PopStyleVar(3);
|
||||
|
||||
return IsPressed;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool FCogWindowWidgets::MultiChoiceButtonsFloat(TArray<float>& Values, float& Value, const ImVec2& Size)
|
||||
{
|
||||
ImGuiStyle& Style = ImGui::GetStyle();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(Style.WindowPadding.x * 0.40f, (float)(int)(Style.WindowPadding.y * 0.60f)));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(Style.FramePadding.x * 0.40f, (float)(int)(Style.FramePadding.y * 0.60f)));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(Style.ItemSpacing.x * 0.30f, (float)(int)(Style.ItemSpacing.y * 0.60f)));
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, IM_COL32(255, 255, 255, 180));
|
||||
|
||||
bool IsPressed = false;
|
||||
for (int32 i = 0; i < Values.Num(); ++i)
|
||||
{
|
||||
float ButtonValue = Values[i];
|
||||
|
||||
const char* Text = TCHAR_TO_ANSI(*FString::Printf(TEXT("%g"), ButtonValue).Replace(TEXT("0."), TEXT(".")));
|
||||
if (MultiChoiceButton(Text, ButtonValue == Value, Size))
|
||||
{
|
||||
IsPressed = true;
|
||||
Value = ButtonValue;
|
||||
}
|
||||
|
||||
if (i < Values.Num() - 1)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(1);
|
||||
ImGui::PopStyleVar(3);
|
||||
|
||||
return IsPressed;
|
||||
}
|
||||
@@ -31,7 +31,10 @@ public:
|
||||
virtual void GameTick(float DeltaTime);
|
||||
|
||||
/** */
|
||||
virtual void RenderMainMenuWidget(bool Draw, float& Width) {}
|
||||
virtual float GetMainMenuWidgetWidth(int32 SubWidgetIndex, float MaxWidth) { return -1.0f; }
|
||||
|
||||
/** */
|
||||
virtual void RenderMainMenuWidget(int32 SubWidgetIndex, float Width) {}
|
||||
|
||||
ImGuiID GetID() const { return ID; }
|
||||
|
||||
|
||||
@@ -20,6 +20,12 @@ public:
|
||||
|
||||
static void ToggleButton(bool* Value, const char* TextTrue, const char* TextFalse, const ImVec4& TrueColor, const ImVec4& FalseColor, const ImVec2& Size = ImVec2(0, 0));
|
||||
|
||||
static bool MultiChoiceButton(const char* Label, bool IsSelected, const ImVec2& Size = ImVec2(0, 0));
|
||||
|
||||
static bool MultiChoiceButtonsInt(TArray<int32>& Values, int32& Value, const ImVec2& Size = ImVec2(0, 0));
|
||||
|
||||
static bool MultiChoiceButtonsFloat(TArray<float>& Values, float& Value, const ImVec2& Size = ImVec2(0, 0));
|
||||
|
||||
static void SliderWithReset(const char* Name, float* Value, float Min, float Max, const float& ResetValue, const char* Format);
|
||||
|
||||
static void HelpMarker(const char* Text);
|
||||
|
||||
@@ -48,6 +48,24 @@ void UCogAbilityWindow_Cheats::ResetConfig()
|
||||
void UCogAbilityWindow_Cheats::SetAsset(const UCogAbilityDataAsset* Value)
|
||||
{
|
||||
Asset = Value;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogAbilityWindow_Cheats::GameTick(float DeltaTime)
|
||||
{
|
||||
Super::GameTick(DeltaTime);
|
||||
|
||||
TryReapplyCheats();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogAbilityWindow_Cheats::TryReapplyCheats()
|
||||
{
|
||||
if (bHasReappliedCheats)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (bReapplyCheatsBetweenPlays == false)
|
||||
{
|
||||
@@ -78,7 +96,7 @@ void UCogAbilityWindow_Cheats::SetAsset(const UCogAbilityDataAsset* Value)
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<AActor*> Targets{ LocalPawn };
|
||||
TArray<AActor*> Targets { LocalPawn };
|
||||
|
||||
for (const FString& AppliedCheatName : AppliedCheats)
|
||||
{
|
||||
@@ -88,6 +106,8 @@ void UCogAbilityWindow_Cheats::SetAsset(const UCogAbilityDataAsset* Value)
|
||||
Replicator->ApplyCheat(LocalPawn, Targets, *Cheat);
|
||||
}
|
||||
}
|
||||
|
||||
bHasReappliedCheats = true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -23,17 +23,19 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
virtual void GameTick(float DeltaTime);
|
||||
|
||||
virtual void ResetConfig() override;
|
||||
|
||||
virtual void RenderHelp() override;
|
||||
|
||||
virtual void RenderContent() override;
|
||||
|
||||
private:
|
||||
|
||||
bool AddCheat(AActor* ControlledActor, AActor* TargetActor, const FCogAbilityCheat& CheatEffect, bool IsPersistent);
|
||||
virtual void TryReapplyCheats();
|
||||
|
||||
void RequestCheat(AActor* ControlledActor, AActor* TargetActor, const FCogAbilityCheat& CheatEffect);
|
||||
virtual bool AddCheat(AActor* ControlledActor, AActor* TargetActor, const FCogAbilityCheat& CheatEffect, bool IsPersistent);
|
||||
|
||||
virtual void RequestCheat(AActor* ControlledActor, AActor* TargetActor, const FCogAbilityCheat& CheatEffect);
|
||||
|
||||
UPROPERTY(Config)
|
||||
bool bReapplyCheatsBetweenPlays = true;
|
||||
@@ -46,4 +48,6 @@ private:
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<const UCogAbilityDataAsset> Asset = nullptr;
|
||||
|
||||
bool bHasReappliedCheats = false;
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ public class CogSample : ModuleRules
|
||||
"GameplayTags",
|
||||
"InputCore",
|
||||
"NetCore",
|
||||
"Niagara",
|
||||
});
|
||||
|
||||
if (Target.Configuration != UnrealTargetConfiguration.Shipping && Target.Type != TargetRules.TargetType.Server)
|
||||
|
||||
@@ -29,7 +29,7 @@ void UCogSampleAbilityTask_PlayMontageAndWaitForEvent::OnMontageBlendingOut(UAni
|
||||
// Reset AnimRootMotionTranslationScale
|
||||
ACharacter* Character = Cast<ACharacter>(GetAvatarActor());
|
||||
if (Character && (Character->GetLocalRole() == ROLE_Authority ||
|
||||
(Character->GetLocalRole() == ROLE_AutonomousProxy && Ability->GetNetExecutionPolicy() == EGameplayAbilityNetExecutionPolicy::LocalPredicted)))
|
||||
(Character->GetLocalRole() == ROLE_AutonomousProxy && Ability->GetNetExecutionPolicy() == EGameplayAbilityNetExecutionPolicy::Predicted)))
|
||||
{
|
||||
Character->SetAnimRootMotionTranslationScale(1.f);
|
||||
}
|
||||
@@ -158,7 +158,7 @@ void UCogSampleAbilityTask_PlayMontageAndWaitForEvent::Activate()
|
||||
|
||||
ACharacter* Character = Cast<ACharacter>(GetAvatarActor());
|
||||
if (Character && (Character->GetLocalRole() == ROLE_Authority ||
|
||||
(Character->GetLocalRole() == ROLE_AutonomousProxy && Ability->GetNetExecutionPolicy() == EGameplayAbilityNetExecutionPolicy::LocalPredicted)))
|
||||
(Character->GetLocalRole() == ROLE_AutonomousProxy && Ability->GetNetExecutionPolicy() == EGameplayAbilityNetExecutionPolicy::Predicted)))
|
||||
{
|
||||
Character->SetAnimRootMotionTranslationScale(AnimRootMotionTranslationScale);
|
||||
}
|
||||
|
||||
@@ -1,434 +0,0 @@
|
||||
#include "CogSampleArea.h"
|
||||
|
||||
#include "AbilitySystemComponent.h"
|
||||
#include "AbilitySystemGlobals.h"
|
||||
#include "CogCommon.h"
|
||||
#include "CogSampleDamageableInterface.h"
|
||||
#include "CogSampleFunctionLibrary_Team.h"
|
||||
#include "Engine/World.h"
|
||||
#include "GameFramework/GameStateBase.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
#include "TimerManager.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
ACogSampleArea::ACogSampleArea(const class FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
bReplicates = true;
|
||||
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
SetActorTickEnabled(true);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
DOREPLIFETIME(ACogSampleArea, HalfExtent);
|
||||
DOREPLIFETIME(ACogSampleArea, Level);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::BeginPlay()
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogArea, ELogVerbosity::Verbose, GetInstigator(), TEXT("Area:%s"), *GetName());
|
||||
|
||||
IsAtStart = true;
|
||||
IsAtEnd = false;
|
||||
|
||||
if (HasAuthority())
|
||||
{
|
||||
if (TickRate > 0.0f && IsInstant == false)
|
||||
{
|
||||
GetWorld()->GetTimerManager().SetTimer(TickTimerHandle, this, &ACogSampleArea::OnTickEffect, TickRate, true, InitialTickDelay);
|
||||
}
|
||||
|
||||
RegisterAllEffects();
|
||||
|
||||
OnActorBeginOverlap.AddDynamic(this, &ACogSampleArea::OnActorEntered);
|
||||
OnActorEndOverlap.AddDynamic(this, &ACogSampleArea::OnActorExited);
|
||||
}
|
||||
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogArea, ELogVerbosity::Verbose, GetInstigator(), TEXT("Area:%s"), *GetName());
|
||||
|
||||
IsAtEnd = true;
|
||||
|
||||
if (CanPerformDetection() && IsInstant == false)
|
||||
{
|
||||
int32 EventTypeFilter = (int32)ECogSampleAreaEventType::OnEnd;
|
||||
|
||||
if (ApplyTickEffectOnExit)
|
||||
{
|
||||
EventTypeFilter |= (int32)ECogSampleAreaEventType::OnTick;
|
||||
}
|
||||
|
||||
ApplyEffectsOnActors(InsideActors, EventTypeFilter);
|
||||
|
||||
for (AActor* Actor : InsideActors)
|
||||
{
|
||||
AffectExitingActor(Actor);
|
||||
}
|
||||
}
|
||||
|
||||
InsideActors.Empty();
|
||||
|
||||
Super::EndPlay(EndPlayReason);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::Tick(float DeltaSeconds)
|
||||
{
|
||||
Super::Tick(DeltaSeconds);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// We cannot execute OnStart event inside the OnActorEntered callback because
|
||||
// we need to know all the actors that are inside to execute the OnStart event.
|
||||
// This is because we must iterate over all actors for each effects we need
|
||||
// to apply. See ApplyEffectsOnActors as to why.
|
||||
// So instead we execute it on Tick
|
||||
//------------------------------------------------------------------------------
|
||||
if (IsAtStart)
|
||||
{
|
||||
int32 EventTypeFilter = (int32)ECogSampleAreaEventType::OnStart;
|
||||
|
||||
if (ApplyTickEffectOnEnter)
|
||||
{
|
||||
EventTypeFilter |= (int32)ECogSampleAreaEventType::OnTick;
|
||||
}
|
||||
|
||||
ApplyEffectsOnActors(InsideActors, EventTypeFilter);
|
||||
|
||||
IsAtStart = false;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
AActor* ACogSampleArea::GetInstigatorActor() const
|
||||
{
|
||||
AActor* AreaInstigator = GetInstigator();
|
||||
if (AreaInstigator != nullptr)
|
||||
{
|
||||
return AreaInstigator;
|
||||
}
|
||||
|
||||
if (ParentActor != nullptr)
|
||||
{
|
||||
return ParentActor;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// The game state is the default Instigator
|
||||
//-------------------------------------------------
|
||||
UWorld* World = GetWorld();
|
||||
if (World != nullptr)
|
||||
{
|
||||
return World->GetGameState();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::RegisterAllEffects()
|
||||
{
|
||||
AActor* AreaInstigator = GetInstigatorActor();
|
||||
if (AreaInstigator == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UAbilitySystemComponent* AbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(AreaInstigator);
|
||||
if (AbilitySystem == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FGameplayEffectContextHandle EffectContextHandle = AbilitySystem->MakeEffectContext();
|
||||
|
||||
for (const FCogSampleAreaEffectConfig& EffectConfig : Effects)
|
||||
{
|
||||
for (TSubclassOf<UGameplayEffect> EffectClass : EffectConfig.Effects)
|
||||
{
|
||||
if (EffectsMap.Contains(EffectClass))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FGameplayEffectSpecHandle* BakedEffectSpecHandle = BakedEffects.FindByPredicate([EffectClass](const FGameplayEffectSpecHandle& Handle)
|
||||
{
|
||||
return Handle.Data->Def.GetClass() == EffectClass;
|
||||
});
|
||||
|
||||
if (BakedEffectSpecHandle != nullptr)
|
||||
{
|
||||
EffectsMap.Add(EffectClass, *BakedEffectSpecHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
FGameplayEffectSpecHandle EffectSpecHandle = AbilitySystem->MakeOutgoingSpec(EffectClass, Level, EffectContextHandle);
|
||||
EffectsMap.Add(EffectClass, EffectSpecHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// We iterate over effects and then over actors to make sure effects are applied in order on all actors.
|
||||
// One case where this is useful is an area that applies first a corruption effect and damage effect.
|
||||
// The corruption must be given to everyone in the area before any damage is applied, because the corruption
|
||||
// propagate the damage to other corrupted actors.
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::ApplyEffectsOnActors(const TArray<AActor*>& HitActors, int32 EventTypeFilter)
|
||||
{
|
||||
for (const FCogSampleAreaEffectConfig& EffectConfig : Effects)
|
||||
{
|
||||
if (((int32)EffectConfig.Event & (int32)EventTypeFilter) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (TSubclassOf<UGameplayEffect> EffectClass : EffectConfig.Effects)
|
||||
{
|
||||
FGameplayEffectSpecHandle* Handle = EffectsMap.Find(EffectClass);
|
||||
if (Handle == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FGameplayEffectSpec* Spec = Handle->Data.Get();
|
||||
if (Spec == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (AActor* HitActor : HitActors)
|
||||
{
|
||||
if (UCogSampleFunctionLibrary_Team::MatchAllegianceBetweenTeamAndActor(Team, HitActor, EffectConfig.Allegiance) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsAliveOfAffectDead(HitActor) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UAbilitySystemComponent* TargetAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(HitActor);
|
||||
if (TargetAbilitySystem != nullptr)
|
||||
{
|
||||
TArray<FActiveGameplayEffectHandle>* TargetInsideEffects = nullptr;
|
||||
if ((EventTypeFilter & (int32)ECogSampleAreaEventType::OnInside) != 0)
|
||||
{
|
||||
TargetInsideEffects = &InsideEffects.FindOrAdd(HitActor);
|
||||
}
|
||||
|
||||
const FVector HitNormal = (HitActor->GetActorLocation() - GetActorLocation()) .GetSafeNormal(0.1f, FVector::UpVector);
|
||||
const FHitResult HitResult(HitActor, nullptr, HitActor->GetActorLocation(), HitNormal);
|
||||
Spec->GetContext().AddHitResult(HitResult, true);
|
||||
|
||||
FActiveGameplayEffectHandle ActiveEffectHandle = TargetAbilitySystem->ApplyGameplayEffectSpecToSelf(*Spec);
|
||||
|
||||
if (EffectConfig.Event == ECogSampleAreaEventType::OnInside && TargetInsideEffects != nullptr)
|
||||
{
|
||||
TargetInsideEffects->Add(ActiveEffectHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool ACogSampleArea::MakeAreaOutgoingEffectSpecs(TSubclassOf<UGameplayEffect> EffectClass, FGameplayEffectSpecHandle& EffectSpecHandle) const
|
||||
{
|
||||
AActor* AreaInstigator = GetInstigatorActor();
|
||||
if (AreaInstigator == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
UAbilitySystemComponent* AbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(AreaInstigator);
|
||||
if (AbilitySystem == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
EffectSpecHandle = AbilitySystem->MakeOutgoingSpec(EffectClass, Level, AbilitySystem->MakeEffectContext());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool ACogSampleArea::CanPerformDetection() const
|
||||
{
|
||||
if (OnlyDetectOnAuthority == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (HasAuthority())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::OnTickEffect_Implementation()
|
||||
{
|
||||
ApplyEffectsOnActors(InsideActors, (int32)ECogSampleAreaEventType::OnTick);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::OnActorEntered_Implementation(AActor* OverlappedActor, AActor* EnteringActor)
|
||||
{
|
||||
check(EnteringActor);
|
||||
if (CanBeAffected(EnteringActor) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AffectEnteringActor(EnteringActor);
|
||||
InsideActors.Add(EnteringActor);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::OnActorExited_Implementation(AActor* OverlappedActor, AActor* ExitingActor)
|
||||
{
|
||||
if (IsInstant)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int32 Index = InsideActors.Find(ExitingActor);
|
||||
if (Index == INDEX_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AffectExitingActor(ExitingActor);
|
||||
|
||||
InsideActors.RemoveAt(Index);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool ACogSampleArea::CanBeAffected_Implementation(AActor* OtherActor) const
|
||||
{
|
||||
check(OtherActor);
|
||||
|
||||
if (IsAlreadyAffected(OtherActor))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool ACogSampleArea::IsAliveOfAffectDead(AActor* OtherActor) const
|
||||
{
|
||||
check(OtherActor);
|
||||
|
||||
if (AffectDead)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const ICogSampleDamageableInterface* Damageable = Cast<ICogSampleDamageableInterface>(OtherActor);
|
||||
if (Damageable == nullptr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Damageable->IsDead() == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool ACogSampleArea::IsAlreadyAffected(AActor* OtherActor) const
|
||||
{
|
||||
check(OtherActor);
|
||||
|
||||
if (InsideActors.Contains(OtherActor))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::AffectEnteringActor_Implementation(AActor* EnteringActor)
|
||||
{
|
||||
check(EnteringActor);
|
||||
|
||||
if (IsInstant == false)
|
||||
{
|
||||
TArray<AActor*> Actors;
|
||||
Actors.Add(EnteringActor);
|
||||
ApplyEffectsOnActors(Actors, (int32)ECogSampleAreaEventType::OnEnter | (int32)ECogSampleAreaEventType::OnInside);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::AffectExitingActor_Implementation(AActor* ExitingActor)
|
||||
{
|
||||
if (IsInstant || ExitingActor == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<AActor*> Actors;
|
||||
Actors.Add(ExitingActor);
|
||||
ApplyEffectsOnActors(Actors, (int32)ECogSampleAreaEventType::OnExit);
|
||||
|
||||
RemoveInsideEffects(ExitingActor);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::RemoveInsideEffects_Implementation(AActor* HitActor)
|
||||
{
|
||||
UAbilitySystemComponent* TargetAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(HitActor);
|
||||
if (TargetAbilitySystem == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<FActiveGameplayEffectHandle>* TargetInsideEffects = InsideEffects.Find(HitActor);
|
||||
if (TargetInsideEffects == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (FActiveGameplayEffectHandle Handle : *TargetInsideEffects)
|
||||
{
|
||||
TargetAbilitySystem->RemoveActiveGameplayEffect(Handle, 1);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::ApplyInstantEffects_Implementation(AActor* HitActor)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::ApplyInsideEffects_Implementation(AActor* HitActor)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleArea::ApplyTickEffects_Implementation(AActor* HitActor)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
#include "CogSampleAreaComponent.h"
|
||||
|
||||
#include "AbilitySystemComponent.h"
|
||||
#include "AbilitySystemGlobals.h"
|
||||
#include "CogCommon.h"
|
||||
#include "CogSampleDamageableInterface.h"
|
||||
#include "CogSampleFunctionLibrary_Gameplay.h"
|
||||
#include "CogSampleFunctionLibrary_Team.h"
|
||||
#include "CogSampleLogCategories.h"
|
||||
#include "Components/BoxComponent.h"
|
||||
#include "Components/SphereComponent.h"
|
||||
#include "Engine/World.h"
|
||||
#include "GameFramework/GameStateBase.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
#include "NiagaraComponent.h"
|
||||
#include "TimerManager.h"
|
||||
|
||||
#if ENABLE_COG
|
||||
#include "CogDebugDraw.h"
|
||||
#include "CogDebugLog.h"
|
||||
#endif //ENABLE_COG
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
UCogSampleAreaComponent::UCogSampleAreaComponent(const class FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
SetIsReplicatedByDefault(true);
|
||||
|
||||
PrimaryComponentTick.bCanEverTick = true;
|
||||
PrimaryComponentTick.bStartWithTickEnabled = true;
|
||||
|
||||
bWantsInitializeComponent = true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::InitializeComponent()
|
||||
{
|
||||
Super::InitializeComponent();
|
||||
|
||||
RefreshOtherComponentsValues();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
//void UCogSampleAreaComponent::PreInitializeComponents()
|
||||
//{
|
||||
// Super::PreInitializeComponents();
|
||||
//
|
||||
// RefreshOtherComponentsValues();
|
||||
//}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
FDoRepLifetimeParams Params;
|
||||
Params.bIsPushBased = true;
|
||||
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(UCogSampleAreaComponent, HalfExtent, Params);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::BeginPlay()
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogArea, ELogVerbosity::Verbose, GetOwner()->GetInstigator(), TEXT("Area:%s"), *GetName());
|
||||
|
||||
IsAtStart = true;
|
||||
IsAtEnd = false;
|
||||
|
||||
if (GetOwner()->HasAuthority())
|
||||
{
|
||||
if (TickRate > 0.0f && DurationType != ECogSampleAreaDurationType::Instant)
|
||||
{
|
||||
GetWorld()->GetTimerManager().SetTimer(TickTimerHandle, this, &UCogSampleAreaComponent::OnTickEffect, TickRate, true, InitialTickDelay);
|
||||
}
|
||||
|
||||
if (DurationType == ECogSampleAreaDurationType::HasDuration)
|
||||
{
|
||||
GetWorld()->GetTimerManager().SetTimer(DurationTimerHandle, this, &UCogSampleAreaComponent::OnDurationElapsed, Duration, false);
|
||||
}
|
||||
|
||||
RegisterAllEffects();
|
||||
|
||||
GetOwner()->OnActorBeginOverlap.AddDynamic(this, &UCogSampleAreaComponent::OnActorEntered);
|
||||
GetOwner()->OnActorEndOverlap.AddDynamic(this, &UCogSampleAreaComponent::OnActorExited);
|
||||
|
||||
|
||||
}
|
||||
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogArea, ELogVerbosity::Verbose, GetOwner()->GetInstigator(), TEXT("Area:%s"), *GetName());
|
||||
|
||||
IsAtEnd = true;
|
||||
|
||||
if (CanPerformDetection() && DurationType != ECogSampleAreaDurationType::Instant)
|
||||
{
|
||||
int32 EventTypeFilter = (int32)ECogSampleAreaEventType::OnEnd;
|
||||
|
||||
if (ApplyTickEffectOnExit)
|
||||
{
|
||||
EventTypeFilter |= (int32)ECogSampleAreaEventType::OnTick;
|
||||
}
|
||||
|
||||
ApplyEffectsOnActors(InsideActors, EventTypeFilter);
|
||||
|
||||
for (AActor* Actor : InsideActors)
|
||||
{
|
||||
AffectExitingActor(Actor);
|
||||
}
|
||||
}
|
||||
|
||||
InsideActors.Empty();
|
||||
|
||||
Super::EndPlay(EndPlayReason);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::OnDurationElapsed_Implementation()
|
||||
{
|
||||
GetOwner()->Destroy();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||
{
|
||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// We cannot execute OnStart event inside the OnActorEntered callback because
|
||||
// we need to know all the actors that are inside to execute the OnStart event.
|
||||
// This is because we must iterate over all actors for each effects we need
|
||||
// to apply. See ApplyEffectsOnActors as to why.
|
||||
// So instead we execute it on Tick
|
||||
//------------------------------------------------------------------------------
|
||||
if (IsAtStart)
|
||||
{
|
||||
int32 EventTypeFilter = (int32)ECogSampleAreaEventType::OnStart;
|
||||
|
||||
if (ApplyTickEffectOnEnter)
|
||||
{
|
||||
EventTypeFilter |= (int32)ECogSampleAreaEventType::OnTick;
|
||||
}
|
||||
|
||||
ApplyEffectsOnActors(InsideActors, EventTypeFilter);
|
||||
|
||||
IsAtStart = false;
|
||||
}
|
||||
|
||||
#if ENABLE_COG
|
||||
|
||||
const AActor* AreaInstigator = UCogSampleFunctionLibrary_Gameplay::GetInstigator(GetOwner());
|
||||
if (FCogDebugLog::IsLogCategoryActive(LogCogArea) && FCogDebugSettings::IsDebugActiveForObject(AreaInstigator))
|
||||
{
|
||||
TArray<USceneComponent*, TInlineAllocator<8>> Components;
|
||||
GetOwner()->GetComponents<USceneComponent>(Components);
|
||||
for (USceneComponent* SceneComponent : Components)
|
||||
{
|
||||
if (USphereComponent* SphereComponent = Cast<USphereComponent>(SceneComponent))
|
||||
{
|
||||
FCogDebugDraw::Sphere(LogCogArea, this, SphereComponent->GetComponentLocation(), SphereComponent->GetScaledSphereRadius(), FColor::Yellow, false, 0);
|
||||
}
|
||||
else if (UBoxComponent* BoxComponent = Cast<UBoxComponent>(SceneComponent))
|
||||
{
|
||||
FCogDebugDraw::Box(LogCogArea, this, BoxComponent->GetComponentLocation(), BoxComponent->GetScaledBoxExtent(), BoxComponent->GetComponentQuat(), FColor::Yellow, false, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //ENABLE_COG
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::RegisterAllEffects()
|
||||
{
|
||||
TArray<TSubclassOf<UGameplayEffect>> AllEffects;
|
||||
|
||||
for (const FCogSampleAreaEffectConfig& EffectConfig : Effects)
|
||||
{
|
||||
for (TSubclassOf<UGameplayEffect> EffectClass : EffectConfig.Effects)
|
||||
{
|
||||
AllEffects.Add(EffectClass);
|
||||
}
|
||||
}
|
||||
|
||||
UCogSampleFunctionLibrary_Gameplay::MakeOutgoingSpecs(GetOwner(), AllEffects, BakedEffects, EffectsMap);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// We iterate over effects and then over actors to make sure effects are applied in order on all actors.
|
||||
// One case where this is useful is an area that applies first a corruption effect and damage effect.
|
||||
// The corruption must be given to everyone in the area before any damage is applied, because the corruption
|
||||
// propagate the damage to other corrupted actors.
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::ApplyEffectsOnActors(const TArray<AActor*>& HitActors, int32 EventTypeFilter)
|
||||
{
|
||||
for (const FCogSampleAreaEffectConfig& EffectConfig : Effects)
|
||||
{
|
||||
if (((int32)EffectConfig.Event & (int32)EventTypeFilter) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (TSubclassOf<UGameplayEffect> EffectClass : EffectConfig.Effects)
|
||||
{
|
||||
FGameplayEffectSpecHandle* Handle = EffectsMap.Find(EffectClass);
|
||||
if (Handle == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FGameplayEffectSpec* Spec = Handle->Data.Get();
|
||||
if (Spec == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (AActor* HitActor : HitActors)
|
||||
{
|
||||
if (UCogSampleFunctionLibrary_Team::MatchAllegiance(GetOwner(), HitActor, EffectConfig.Allegiance) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (UCogSampleFunctionLibrary_Gameplay::IsDead(HitActor) && EffectConfig.AffectDead == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UAbilitySystemComponent* TargetAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(HitActor);
|
||||
if (TargetAbilitySystem == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TArray<FActiveGameplayEffectHandle>* TargetInsideEffects = nullptr;
|
||||
if ((EventTypeFilter & (int32)ECogSampleAreaEventType::OnInside) != 0)
|
||||
{
|
||||
TargetInsideEffects = &InsideEffects.FindOrAdd(HitActor);
|
||||
}
|
||||
|
||||
const FVector HitNormal = (HitActor->GetActorLocation() - GetOwner()->GetActorLocation()) .GetSafeNormal(0.1f, FVector::UpVector);
|
||||
const FHitResult HitResult(HitActor, nullptr, HitActor->GetActorLocation(), HitNormal);
|
||||
Spec->GetContext().AddHitResult(HitResult, true);
|
||||
|
||||
FActiveGameplayEffectHandle ActiveEffectHandle = TargetAbilitySystem->ApplyGameplayEffectSpecToSelf(*Spec);
|
||||
|
||||
if (EffectConfig.Event == ECogSampleAreaEventType::OnInside && TargetInsideEffects != nullptr)
|
||||
{
|
||||
TargetInsideEffects->Add(ActiveEffectHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool UCogSampleAreaComponent::MakeAreaOutgoingEffectSpecs(TSubclassOf<UGameplayEffect> EffectClass, FGameplayEffectSpecHandle& EffectSpecHandle) const
|
||||
{
|
||||
AActor* AreaInstigator = UCogSampleFunctionLibrary_Gameplay::GetInstigator(GetOwner());
|
||||
if (AreaInstigator == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
UAbilitySystemComponent* AbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(AreaInstigator);
|
||||
if (AbilitySystem == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const int32 Level = UCogSampleFunctionLibrary_Gameplay::GetProgressionLevel(GetOwner());
|
||||
EffectSpecHandle = AbilitySystem->MakeOutgoingSpec(EffectClass, Level, AbilitySystem->MakeEffectContext());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool UCogSampleAreaComponent::CanPerformDetection() const
|
||||
{
|
||||
if (OnlyDetectOnAuthority == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GetOwner()->HasAuthority())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::OnTickEffect_Implementation()
|
||||
{
|
||||
ApplyEffectsOnActors(InsideActors, (int32)ECogSampleAreaEventType::OnTick);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::OnActorEntered_Implementation(AActor* OverlappedActor, AActor* EnteringActor)
|
||||
{
|
||||
check(EnteringActor);
|
||||
if (CanBeAffected(EnteringActor) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AffectEnteringActor(EnteringActor);
|
||||
InsideActors.Add(EnteringActor);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::OnActorExited_Implementation(AActor* OverlappedActor, AActor* ExitingActor)
|
||||
{
|
||||
if (DurationType == ECogSampleAreaDurationType::Instant)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int32 Index = InsideActors.Find(ExitingActor);
|
||||
if (Index == INDEX_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AffectExitingActor(ExitingActor);
|
||||
|
||||
InsideActors.RemoveAt(Index);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool UCogSampleAreaComponent::CanBeAffected_Implementation(AActor* OtherActor) const
|
||||
{
|
||||
check(OtherActor);
|
||||
|
||||
if (IsAlreadyAffected(OtherActor))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool UCogSampleAreaComponent::IsAlreadyAffected(AActor* OtherActor) const
|
||||
{
|
||||
check(OtherActor);
|
||||
|
||||
if (InsideActors.Contains(OtherActor))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::AffectEnteringActor_Implementation(AActor* EnteringActor)
|
||||
{
|
||||
check(EnteringActor);
|
||||
|
||||
if (DurationType == ECogSampleAreaDurationType::Instant)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<AActor*> Actors;
|
||||
Actors.Add(EnteringActor);
|
||||
ApplyEffectsOnActors(Actors, (int32)ECogSampleAreaEventType::OnEnter | (int32)ECogSampleAreaEventType::OnInside);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::AffectExitingActor_Implementation(AActor* ExitingActor)
|
||||
{
|
||||
if (DurationType == ECogSampleAreaDurationType::Instant || ExitingActor == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<AActor*> Actors;
|
||||
Actors.Add(ExitingActor);
|
||||
ApplyEffectsOnActors(Actors, (int32)ECogSampleAreaEventType::OnExit);
|
||||
|
||||
RemoveInsideEffects(ExitingActor);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::RemoveInsideEffects_Implementation(AActor* HitActor)
|
||||
{
|
||||
UAbilitySystemComponent* TargetAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(HitActor);
|
||||
if (TargetAbilitySystem == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<FActiveGameplayEffectHandle>* TargetInsideEffects = InsideEffects.Find(HitActor);
|
||||
if (TargetInsideEffects == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (FActiveGameplayEffectHandle Handle : *TargetInsideEffects)
|
||||
{
|
||||
TargetAbilitySystem->RemoveActiveGameplayEffect(Handle, 1);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::ApplyInstantEffects_Implementation(AActor* HitActor)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::ApplyInsideEffects_Implementation(AActor* HitActor)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::ApplyTickEffects_Implementation(AActor* HitActor)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::SetHalfExtent(const FVector& Value)
|
||||
{
|
||||
COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(UCogSampleAreaComponent, HalfExtent, Value, this);
|
||||
RefreshOtherComponentsValues();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::OnRep_HalfExtent()
|
||||
{
|
||||
RefreshOtherComponentsValues();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleAreaComponent::RefreshOtherComponentsValues()
|
||||
{
|
||||
TArray<USceneComponent*, TInlineAllocator<8>> Components;
|
||||
GetOwner()->GetComponents<USceneComponent>(Components);
|
||||
|
||||
for (USceneComponent* SceneComponent : Components)
|
||||
{
|
||||
if (USphereComponent* SphereComponent = Cast<USphereComponent>(SceneComponent))
|
||||
{
|
||||
if (SphereComponent->GetUnscaledSphereRadius() != HalfExtent.X)
|
||||
{
|
||||
SphereComponent->SetSphereRadius(HalfExtent.X);
|
||||
}
|
||||
}
|
||||
else if (UBoxComponent* BoxComponent = Cast<UBoxComponent>(SceneComponent))
|
||||
{
|
||||
if (BoxComponent->GetUnscaledBoxExtent() != HalfExtent)
|
||||
{
|
||||
BoxComponent->SetBoxExtent(HalfExtent);
|
||||
}
|
||||
}
|
||||
else if (UNiagaraComponent* NiagaraComponent = Cast<UNiagaraComponent>(SceneComponent))
|
||||
{
|
||||
NiagaraComponent->SetNiagaraVariableVec3("HalfExtent", HalfExtent);
|
||||
NiagaraComponent->SetNiagaraVariableFloat("TickRate", TickRate);
|
||||
NiagaraComponent->SetNiagaraVariableFloat("Duration", Duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "GameplayEffect.h"
|
||||
|
||||
#include "CogSampleArea.generated.h"
|
||||
#include "CogSampleAreaComponent.generated.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// ECogSampleAreaEventType
|
||||
@@ -27,7 +25,7 @@ ENUM_CLASS_FLAGS(ECogSampleAreaEventType);
|
||||
// FCogSampleAreaEffectConfig
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
USTRUCT(BlueprintType)
|
||||
struct COGSAMPLE_API FCogSampleAreaEffectConfig
|
||||
struct FCogSampleAreaEffectConfig
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
@@ -37,72 +35,88 @@ struct COGSAMPLE_API FCogSampleAreaEffectConfig
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (Bitmask, BitmaskEnum = "/Script/CogSample.ECogSampleAllegianceFilter"))
|
||||
int32 Allegiance = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
bool AffectDead = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TArray<TSubclassOf<UGameplayEffect>> Effects;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// ECogSampleAreaDurationType
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
UENUM()
|
||||
enum class ECogSampleAreaDurationType : uint8
|
||||
{
|
||||
Instant,
|
||||
Infinite,
|
||||
HasDuration
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// ACogSampleArea
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
UCLASS()
|
||||
class COGSAMPLE_API ACogSampleArea : public AActor
|
||||
UCLASS(BlueprintType, meta = (BlueprintSpawnableComponent))
|
||||
class UCogSampleAreaComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
|
||||
public:
|
||||
|
||||
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
|
||||
virtual void InitializeComponent() override;
|
||||
|
||||
//virtual void PreInitializeComponents() override;
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area|General", meta = (ExposeOnSpawn = true))
|
||||
TObjectPtr<AActor> ParentActor = nullptr;
|
||||
FVector GetHalfExtent() const { return HalfExtent; }
|
||||
|
||||
UPROPERTY(Replicated, EditAnywhere, BlueprintReadWrite, Category = "Area|General", meta = (ExposeOnSpawn = true))
|
||||
FVector HalfExtent = FVector(100.f, 100.f, 100.f);
|
||||
void SetHalfExtent(const FVector& Value);
|
||||
|
||||
UPROPERTY(Replicated, EditAnywhere, BlueprintReadWrite, Category = "Area|General", meta = (ExposeOnSpawn = true))
|
||||
int32 Level = 0;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area")
|
||||
ECogSampleAreaDurationType DurationType;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area|General", meta = (ExposeOnSpawn = true))
|
||||
int32 Team = 0;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area", meta = (EditConditionHides, EditCondition = "DurationType == ECogSampleAreaDurationType::HasDuration"))
|
||||
float Duration = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area|General", meta = (ExposeOnSpawn = true))
|
||||
bool IsInstant = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area|General", meta = (ExposeOnSpawn = true))
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area", meta = (EditConditionHides, EditCondition = "DurationType != ECogSampleAreaDurationType::Instant"))
|
||||
float TickRate = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area|General", meta = (ExposeOnSpawn = true))
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area", meta = (EditConditionHides, EditCondition = "DurationType != ECogSampleAreaDurationType::Instant"))
|
||||
float InitialTickDelay = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area|General")
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area", meta = (EditConditionHides, EditCondition = "DurationType != ECogSampleAreaDurationType::Instant"))
|
||||
bool ApplyTickEffectOnEnter = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area|General")
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area", meta = (EditConditionHides, EditCondition = "DurationType != ECogSampleAreaDurationType::Instant"))
|
||||
bool ApplyTickEffectOnExit = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area|General")
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area")
|
||||
bool OnlyDetectOnAuthority = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area|General")
|
||||
bool AffectDead = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area|Effects", meta = (ExposeOnSpawn = true))
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Area")
|
||||
TArray<FCogSampleAreaEffectConfig> Effects;
|
||||
|
||||
UPROPERTY(Transient, BlueprintReadWrite, Category = "Internal", meta = (ExposeOnSpawn = true))
|
||||
UPROPERTY(Transient, BlueprintReadWrite, Category = "Internal")
|
||||
TArray<FGameplayEffectSpecHandle> BakedEffects;
|
||||
|
||||
protected:
|
||||
|
||||
UFUNCTION(Category = "Area")
|
||||
void OnRep_HalfExtent();
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Area")
|
||||
void OnTickEffect();
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Area")
|
||||
void OnDurationElapsed();
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Area")
|
||||
void OnActorEntered(AActor* OverlappedActor, AActor* EnteringActor);
|
||||
|
||||
@@ -133,21 +147,20 @@ protected:
|
||||
UFUNCTION(BlueprintPure, Category = "Area")
|
||||
bool CanPerformDetection() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Area")
|
||||
bool IsAliveOfAffectDead(AActor* OtherActor) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Area")
|
||||
bool IsAlreadyAffected(AActor* OtherActor) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Area")
|
||||
AActor* GetInstigatorActor() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure=false, Category = "Area")
|
||||
bool MakeAreaOutgoingEffectSpecs(TSubclassOf<UGameplayEffect> EffectClass, FGameplayEffectSpecHandle& EffectSpecHandle) const;
|
||||
|
||||
void RegisterAllEffects();
|
||||
UPROPERTY(ReplicatedUsing = OnRep_HalfExtent, EditAnywhere, BlueprintReadWrite, Category = "Area")
|
||||
FVector HalfExtent = FVector(100.f, 100.f, 100.f);
|
||||
|
||||
void ApplyEffectsOnActors(const TArray<AActor*>& HitActors, int32 EventTypeFilter);
|
||||
virtual void RegisterAllEffects();
|
||||
|
||||
virtual void ApplyEffectsOnActors(const TArray<AActor*>& HitActors, int32 EventTypeFilter);
|
||||
|
||||
virtual void RefreshOtherComponentsValues();
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Transient)
|
||||
bool IsAtStart = true;
|
||||
@@ -162,4 +175,6 @@ protected:
|
||||
TMap<AActor*, TArray<FActiveGameplayEffectHandle>> InsideEffects;
|
||||
|
||||
FTimerHandle TickTimerHandle;
|
||||
|
||||
FTimerHandle DurationTimerHandle;
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "CogSampleBasicActor.h"
|
||||
|
||||
#include "Net/Core/PushModel/PushModel.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
ACogSampleBasicActor::ACogSampleBasicActor(const FObjectInitializer& ObjectInitializer)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleBasicActor::GetLifetimeReplicatedProps(TArray< FLifetimeProperty >& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
FDoRepLifetimeParams Params;
|
||||
Params.bIsPushBased = true;
|
||||
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleBasicActor, Team, Params);
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleBasicActor, ProgressionLevel, Params);
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleBasicActor, Creator, Params);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleBasicActor::SetTeam(int32 Value)
|
||||
{
|
||||
COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(ACogSampleBasicActor, Team, Value, this);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleBasicActor::SetProgressionLevel(int32 Value)
|
||||
{
|
||||
COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(ACogSampleBasicActor, ProgressionLevel, Value, this);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleBasicActor::SetCreator(AActor* Value)
|
||||
{
|
||||
COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(ACogSampleBasicActor, Creator, Value, this);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CogSampleProgressionLevelInterface.h"
|
||||
#include "CogSampleTeamInterface.h"
|
||||
#include "CogSampleSpawnableInterface.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "CogSampleBasicActor.generated.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
UCLASS(config=Game)
|
||||
class ACogSampleBasicActor : public AActor
|
||||
, public ICogSampleProgressionLevelInterface
|
||||
, public ICogSampleSpawnableInterface
|
||||
, public ICogSampleTeamInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
ACogSampleBasicActor(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
virtual int32 GetTeam() const override { return Team; }
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual void SetTeam(int32 Value) override;
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
virtual int32 GetProgressionLevel() const override { return ProgressionLevel; }
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual void SetProgressionLevel(int32 Value) override;
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
virtual AActor* GetCreator() const override { return Creator.Get(); }
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual void SetCreator(AActor* Value) override;
|
||||
|
||||
protected:
|
||||
|
||||
UPROPERTY(Replicated, EditAnywhere, BlueprintReadOnly, Category = Team, meta = (AllowPrivateAccess, ExposeOnSpawn))
|
||||
int32 Team = 0;
|
||||
|
||||
UPROPERTY(Replicated, EditAnywhere, BlueprintReadOnly, Category = Team, meta = (AllowPrivateAccess, ExposeOnSpawn))
|
||||
int32 ProgressionLevel = 0;
|
||||
|
||||
UPROPERTY(Replicated, EditAnywhere, BlueprintReadOnly, Category = Team, meta = (AllowPrivateAccess, ExposeOnSpawn))
|
||||
TWeakObjectPtr<AActor> Creator = nullptr;
|
||||
};
|
||||
|
||||
@@ -77,13 +77,14 @@ void ACogSampleCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty >
|
||||
|
||||
FDoRepLifetimeParams Params;
|
||||
Params.bIsPushBased = true;
|
||||
Params.Condition = COND_OwnerOnly;
|
||||
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleCharacter, ActiveAbilityHandles, Params);
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleCharacter, Team, Params);
|
||||
|
||||
Params.Condition = COND_None;
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleCharacter, Team, Params);
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleCharacter, ProgressionLevel, Params);
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleCharacter, Scale, Params);
|
||||
|
||||
Params.Condition = COND_OwnerOnly;
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleCharacter, ActiveAbilityHandles, Params);
|
||||
}
|
||||
|
||||
|
||||
@@ -709,10 +710,15 @@ void ACogSampleCharacter::OnRep_Scale()
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleCharacter::SetTeamID(int32 Value)
|
||||
void ACogSampleCharacter::SetTeam(int32 Value)
|
||||
{
|
||||
Team = Value;
|
||||
MARK_PROPERTY_DIRTY_FROM_NAME(ACogSampleCharacter, Team, this);
|
||||
COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(ACogSampleCharacter, Team, Value, this);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void ACogSampleCharacter::SetProgressionLevel(int32 Value)
|
||||
{
|
||||
COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(ACogSampleCharacter, ProgressionLevel, Value, this);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "AbilitySystemInterface.h"
|
||||
#include "ActiveGameplayEffectHandle.h"
|
||||
#include "AttributeSet.h"
|
||||
#include "CogCommonAllegianceActorInterface.h"
|
||||
#include "CogCommonDebugFilteredActorInterface.h"
|
||||
#include "CogSampleDamageEvent.h"
|
||||
#include "CogSampleDefines.h"
|
||||
#include "CogSampleDamageableInterface.h"
|
||||
#include "CogSampleDefines.h"
|
||||
#include "CogSampleProgressionLevelInterface.h"
|
||||
#include "CogSampleTargetableInterface.h"
|
||||
#include "CogSampleTeamInterface.h"
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "GameplayAbilitySpecHandle.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
@@ -82,6 +82,7 @@ class ACogSampleCharacter : public ACharacter
|
||||
, public ICogCommonDebugFilteredActorInterface
|
||||
, public ICogCommonAllegianceActorInterface
|
||||
, public ICogSampleTeamInterface
|
||||
, public ICogSampleProgressionLevelInterface
|
||||
, public ICogSampleTargetableInterface
|
||||
, public ICogSampleDamageableInterface
|
||||
{
|
||||
@@ -151,10 +152,16 @@ public:
|
||||
virtual int32 GetTeam() const override { return Team; }
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SetTeamID(int32 Value);
|
||||
virtual void SetTeam(int32 Value) override;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Team, Replicated, meta = (AllowPrivateAccess = "true"))
|
||||
int32 Team = 0;
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Level
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
virtual int32 GetProgressionLevel() const override { return ProgressionLevel; }
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
virtual void SetProgressionLevel(int32 Value) override;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Camera
|
||||
@@ -163,10 +170,10 @@ public:
|
||||
|
||||
UCameraComponent* GetFollowCamera() const { return FollowCamera; }
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess))
|
||||
USpringArmComponent* CameraBoom;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess))
|
||||
UCameraComponent* FollowCamera;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
@@ -179,26 +186,26 @@ public:
|
||||
FVector GetMoveInputInWorldSpace() const { return MoveInputInWorldSpace; }
|
||||
|
||||
/** MappingContext */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess))
|
||||
UInputMappingContext* DefaultMappingContext;
|
||||
|
||||
/** MappingContext */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess))
|
||||
UInputMappingContext* GhostMappingContext;
|
||||
|
||||
/** Move Input Action */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess))
|
||||
UInputAction* MoveAction;
|
||||
|
||||
/** Move Input Action */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess))
|
||||
UInputAction* MoveZAction;
|
||||
|
||||
/** Look Input Action */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess))
|
||||
UInputAction* LookAction;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess))
|
||||
TArray<UInputAction*> ItemActions;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
@@ -211,7 +218,7 @@ public:
|
||||
|
||||
void OnRevived(AActor* InInstigator, AActor* InCauser, const FGameplayEffectSpec& InEffectSpec, float InMagnitude);
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = Ability, meta = (AllowPrivateAccess = "true"))
|
||||
UPROPERTY(BlueprintReadOnly, Category = Ability, meta = (AllowPrivateAccess))
|
||||
UCogSampleAbilitySystemComponent* AbilitySystem = nullptr;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Ability)
|
||||
@@ -259,11 +266,16 @@ public:
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure=false)
|
||||
bool GetMontage(FName MontageName, UAnimMontage*& Montage, bool bPrintWarning) const;
|
||||
|
||||
private:
|
||||
protected:
|
||||
friend class ACogSamplePlayerController;
|
||||
|
||||
void RefreshServerAnimTickOption();
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = Team, Replicated, meta = (AllowPrivateAccess))
|
||||
int32 Team = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = Level, Replicated, meta = (AllowPrivateAccess))
|
||||
int32 ProgressionLevel = 0;
|
||||
|
||||
UPROPERTY()
|
||||
AController* InitialController = nullptr;
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
};
|
||||
|
||||
UCLASS(meta = (ScriptName = "CogSampleFunctionLibrary_Damage"))
|
||||
class COGSAMPLE_API UCogSampleFunctionLibrary_Damage : public UBlueprintFunctionLibrary
|
||||
class UCogSampleFunctionLibrary_Damage : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
#include "Abilities/GameplayAbility.h"
|
||||
#include "AbilitySystemComponent.h"
|
||||
#include "AbilitySystemGlobals.h"
|
||||
#include "CogSampleDamageableInterface.h"
|
||||
#include "CogSampleGameplayEffectContext.h"
|
||||
#include "CogSampleProgressionLevelInterface.h"
|
||||
#include "CogSampleSpawnableInterface.h"
|
||||
#include "CogSampleTargetableInterface.h"
|
||||
#include "Components/CapsuleComponent.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "GameFramework/GameStateBase.h"
|
||||
#include "GameplayCueNotifyTypes.h"
|
||||
#include "GameplayEffectTypes.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
@@ -317,7 +321,7 @@ bool UCogSampleFunctionLibrary_Gameplay::IsActorMatchingTags(const AActor* Actor
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
AActor* UCogSampleFunctionLibrary_Gameplay::GetActorInstigator(AActor* Actor)
|
||||
AActor* UCogSampleFunctionLibrary_Gameplay::GetInstigator(const AActor* Actor)
|
||||
{
|
||||
if (Actor == nullptr)
|
||||
{
|
||||
@@ -340,4 +344,149 @@ AActor* UCogSampleFunctionLibrary_Gameplay::GetActorInstigator(AActor* Actor)
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
int32 UCogSampleFunctionLibrary_Gameplay::GetProgressionLevel(const AActor* Actor)
|
||||
{
|
||||
if (Actor == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ICogSampleProgressionLevelInterface* LevelActor = Cast<ICogSampleProgressionLevelInterface>(Actor);
|
||||
if (LevelActor == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int32 Value = LevelActor->GetProgressionLevel();
|
||||
return Value;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleFunctionLibrary_Gameplay::SetProgressionLevel(AActor* Actor, int32 Value)
|
||||
{
|
||||
if (Actor == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ICogSampleProgressionLevelInterface* LevelActor = Cast<ICogSampleProgressionLevelInterface>(Actor);
|
||||
if (LevelActor == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LevelActor->SetProgressionLevel(Value);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
AActor* UCogSampleFunctionLibrary_Gameplay::GetCreator(const AActor* Actor)
|
||||
{
|
||||
if (Actor == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const ICogSampleSpawnableInterface* Spawnable = Cast<ICogSampleSpawnableInterface>(Actor);
|
||||
if (Spawnable == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
AActor* Value = Spawnable->GetCreator();
|
||||
return Value;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleFunctionLibrary_Gameplay::SetCreator(AActor* Actor, AActor* Value)
|
||||
{
|
||||
if (Actor == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ICogSampleSpawnableInterface* Spawnable = Cast<ICogSampleSpawnableInterface>(Actor);
|
||||
if (Spawnable == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Spawnable->SetCreator(Value);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool UCogSampleFunctionLibrary_Gameplay::IsAlive(const AActor* Actor)
|
||||
{
|
||||
if (Actor == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const ICogSampleDamageableInterface* Damageable = Cast<ICogSampleDamageableInterface>(Actor);
|
||||
if (Damageable == nullptr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Damageable->IsDead() == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool UCogSampleFunctionLibrary_Gameplay::IsDead(const AActor* Actor)
|
||||
{
|
||||
return IsAlive(Actor) == false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleFunctionLibrary_Gameplay::MakeOutgoingSpecs(
|
||||
const AActor* Actor,
|
||||
const TArray<TSubclassOf<UGameplayEffect>>& Effects,
|
||||
const TArray<FGameplayEffectSpecHandle>& BakedEffects,
|
||||
TMap<TSubclassOf<UGameplayEffect>, FGameplayEffectSpecHandle>& Results)
|
||||
{
|
||||
const AActor* Instigator = UCogSampleFunctionLibrary_Gameplay::GetInstigator(Actor);
|
||||
if (Instigator == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const UAbilitySystemComponent* AbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(Instigator);
|
||||
if (AbilitySystem == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const int32 Level = UCogSampleFunctionLibrary_Gameplay::GetProgressionLevel(Actor);
|
||||
|
||||
FGameplayEffectContextHandle EffectContextHandle = AbilitySystem->MakeEffectContext();
|
||||
|
||||
for (const TSubclassOf<UGameplayEffect>& EffectClass : Effects)
|
||||
{
|
||||
if (Results.Contains(EffectClass))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const FGameplayEffectSpecHandle* BakedEffectSpecHandle = BakedEffects.FindByPredicate([EffectClass](const FGameplayEffectSpecHandle& Handle)
|
||||
{
|
||||
return Handle.Data->Def.GetClass() == EffectClass;
|
||||
});
|
||||
|
||||
if (BakedEffectSpecHandle != nullptr)
|
||||
{
|
||||
Results.Add(EffectClass, *BakedEffectSpecHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
FGameplayEffectSpecHandle EffectSpecHandle = AbilitySystem->MakeOutgoingSpec(EffectClass, Level, EffectContextHandle);
|
||||
Results.Add(EffectClass, EffectSpecHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,18 @@
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CogSampleDefines.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "CogSampleFunctionLibrary_Gameplay.generated.h"
|
||||
|
||||
class UAbilitySystemComponent;
|
||||
class UGameplayAbility;
|
||||
class UGameplayEffect;
|
||||
struct FGameplayAbilitySpecHandle;
|
||||
struct FGameplayAttribute;
|
||||
struct FGameplayAttributeData;
|
||||
struct FGameplayCueNotify_SpawnResult;
|
||||
struct FGameplayCueParameters;
|
||||
struct FGameplayEffectSpecHandle;
|
||||
struct FGameplayTagContainer;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -65,7 +68,25 @@ public:
|
||||
static void FindCapsulePointDistance(const FVector2D& CapsulePoint1, const FVector2D& CapsulePoint2, const float CapsuleRadius, const FVector2D& Point, FVector2D& Projection, float& Time, float& Distance);
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
static AActor* GetActorInstigator(AActor* Actor);
|
||||
static AActor* GetInstigator(const AActor* Actor);
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
static int32 GetProgressionLevel(const AActor* Actor);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
static void SetProgressionLevel(AActor* Actor, int32 Value);
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
static AActor* GetCreator(const AActor* Actor);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
static void SetCreator(AActor* Actor, AActor* Value);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
static bool IsAlive(const AActor* Actor);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
static bool IsDead(const AActor* Actor);
|
||||
|
||||
static void AdjustAttributeForMaxChange(UAbilitySystemComponent* AbilityComponent, FGameplayAttributeData& AffectedAttribute, float OldValue, float NewMaxValue, const FGameplayAttribute& AffectedAttributeProperty);
|
||||
|
||||
@@ -85,5 +106,5 @@ public:
|
||||
|
||||
static bool IsActorMatchingTags(const AActor* Actor, const FGameplayTagContainer& RequiredTags, const FGameplayTagContainer& IgnoredTags);
|
||||
|
||||
static bool MatchCooldownTag(const FGameplayTagContainer& TagContainer);
|
||||
static void MakeOutgoingSpecs(const AActor* Actor, const TArray<TSubclassOf<UGameplayEffect>>& Effects, const TArray<FGameplayEffectSpecHandle>& BakedEffects, TMap<TSubclassOf<UGameplayEffect>, FGameplayEffectSpecHandle>& Result);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "CogSampleTeamInterface.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
int32 UCogSampleFunctionLibrary_Team::GetTeamSafe(const AActor* Actor)
|
||||
int32 UCogSampleFunctionLibrary_Team::GetTeam(const AActor* Actor)
|
||||
{
|
||||
if (Actor == nullptr)
|
||||
{
|
||||
@@ -20,6 +20,24 @@ int32 UCogSampleFunctionLibrary_Team::GetTeamSafe(const AActor* Actor)
|
||||
return Team;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleFunctionLibrary_Team::SetTeam(AActor* Actor, int32 Value)
|
||||
{
|
||||
if (Actor == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ICogSampleTeamInterface* TeamActor = Cast<ICogSampleTeamInterface>(Actor);
|
||||
if (TeamActor == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TeamActor->SetTeam(Value);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
ECogSampleAllegiance UCogSampleFunctionLibrary_Team::GetTeamsAllegiance(int32 Team1, int32 Team2)
|
||||
{
|
||||
@@ -39,8 +57,8 @@ ECogSampleAllegiance UCogSampleFunctionLibrary_Team::GetTeamsAllegiance(int32 Te
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
ECogSampleAllegiance UCogSampleFunctionLibrary_Team::GetActorsAllegiance(const AActor* Actor1, const AActor* Actor2)
|
||||
{
|
||||
const int32 Team1 = GetTeamSafe(Actor1);
|
||||
const int32 Team2 = GetTeamSafe(Actor2);
|
||||
const int32 Team1 = GetTeam(Actor1);
|
||||
const int32 Team2 = GetTeam(Actor2);
|
||||
const ECogSampleAllegiance Allegiance = GetTeamsAllegiance(Team1, Team2);
|
||||
return Allegiance;
|
||||
}
|
||||
@@ -64,7 +82,7 @@ bool UCogSampleFunctionLibrary_Team::MatchAllegianceFromTeams(int32 Team1, int32
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool UCogSampleFunctionLibrary_Team::MatchAllegianceBetweenTeamAndActor(int32 Team, const AActor* Actor, int32 AllegianceFilter)
|
||||
{
|
||||
const int32 ActorTeam = GetTeamSafe(Actor);
|
||||
const int32 ActorTeam = GetTeam(Actor);
|
||||
const ECogSampleAllegiance Allegiance = GetTeamsAllegiance(Team, ActorTeam);
|
||||
const bool Result = MatchAllegianceFilter(Allegiance, AllegianceFilter);
|
||||
return Result;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "CogSampleFunctionLibrary_Team.generated.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -32,7 +33,10 @@ class UCogSampleFunctionLibrary_Team : public UBlueprintFunctionLibrary
|
||||
public:
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
static int32 GetTeamSafe(const AActor* Actor);
|
||||
static int32 GetTeam(const AActor* Actor);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
static void SetTeam(AActor* Actor, int32 Value);
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
static ECogSampleAllegiance GetTeamsAllegiance(int32 Team1, int32 Team2);
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
#include "CogSampleFunctionLibrary_Tag.h"
|
||||
#include "CogSampleGameplayEffectContext.h"
|
||||
#include "CogSampleLogCategories.h"
|
||||
|
||||
|
||||
|
||||
#include "CogSamplePlayerController.h"
|
||||
#include "CogSampleSpawnPredictionComponent.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
UCogSampleGameplayAbility::UCogSampleGameplayAbility()
|
||||
@@ -235,4 +234,49 @@ void UCogSampleGameplayAbility::GetCooldownInfos(float& TimeRemaining, float& Co
|
||||
//-------------------------------------------------------------------------------------
|
||||
FGameplayAbilitySpecHandle Handle;
|
||||
GetCooldownTimeRemainingAndDuration(Handle, CurrentActorInfo, TimeRemaining, CooldownDuration);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleGameplayAbility::SetupSpawnPrediction(AActor* Actor, int32 InstanceIndex)
|
||||
{
|
||||
if (Actor == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UCogSampleSpawnPredictionComponent* SpawnPrediction = Actor->FindComponentByClass<UCogSampleSpawnPredictionComponent>();
|
||||
if (SpawnPrediction == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetupSpawnPredictionComponent(SpawnPrediction, InstanceIndex);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleGameplayAbility::SetupSpawnPredictionComponent(UCogSampleSpawnPredictionComponent* SpawnPrediction, int32 InstanceIndex)
|
||||
{
|
||||
if (SpawnPrediction == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SpawnPrediction->SetCreator(CurrentActorInfo->AvatarActor.Get());
|
||||
|
||||
FCogSampleSpawnPredictionKey PredictedActorKey = FCogSampleSpawnPredictionKey::MakeFromAbility(*this, InstanceIndex);
|
||||
SpawnPrediction->SetSpawnPredictionKey(PredictedActorKey);
|
||||
|
||||
if (GetCurrentActorInfo()->IsNetAuthority())
|
||||
{
|
||||
SpawnPrediction->SetRole(ECogSampleSpawnPredictionRole::Server);
|
||||
}
|
||||
else
|
||||
{
|
||||
SpawnPrediction->SetRole(ECogSampleSpawnPredictionRole::Predicted);
|
||||
|
||||
if (ACogSamplePlayerController* PlayerController = Cast<ACogSamplePlayerController>(GetCurrentActorInfo()->PlayerController))
|
||||
{
|
||||
PlayerController->SpawnPredictions.Add(SpawnPrediction);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "Abilities/GameplayAbility.h"
|
||||
#include "CogSampleGameplayAbility.generated.h"
|
||||
|
||||
class UCogSampleSpawnPredictionComponent;
|
||||
|
||||
UCLASS()
|
||||
class UCogSampleGameplayAbility : public UGameplayAbility
|
||||
{
|
||||
@@ -17,7 +19,9 @@ public:
|
||||
// UGameplayAbility overrides
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
virtual void PreActivate(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, FOnGameplayAbilityEnded::FDelegate* OnGameplayAbilityEndedDelegate, const FGameplayEventData* TriggerEventData) override;
|
||||
|
||||
virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;
|
||||
|
||||
virtual void EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled) override;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
@@ -59,6 +63,16 @@ public:
|
||||
UFUNCTION(BlueprintPure)
|
||||
int32 GetIntValueAtAbilityLevel(const FScalableFloat& ScalableFloat) const;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Predicated Actors
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SetupSpawnPrediction(AActor* PredictedSpawn, int32 InstanceIndex);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SetupSpawnPredictionComponent(UCogSampleSpawnPredictionComponent* SpawnPrediction, int32 InstanceIndex);
|
||||
|
||||
private:
|
||||
|
||||
bool IsCostGameplayEffectIsZero(const UGameplayEffect* GameplayEffect, float Level, const FGameplayEffectContextHandle& EffectContext) const;
|
||||
|
||||
@@ -18,6 +18,8 @@ DEFINE_LOG_CATEGORY(LogCogControlRotation);
|
||||
DEFINE_LOG_CATEGORY(LogCogInput);
|
||||
DEFINE_LOG_CATEGORY(LogCogPosition);
|
||||
DEFINE_LOG_CATEGORY(LogCogPossession);
|
||||
DEFINE_LOG_CATEGORY(LogCogPredictedActor);
|
||||
DEFINE_LOG_CATEGORY(LogCogProjectile);
|
||||
DEFINE_LOG_CATEGORY(LogCogRotation);
|
||||
DEFINE_LOG_CATEGORY(LogCogSkeleton);
|
||||
DEFINE_LOG_CATEGORY(LogCogTargetAcquisition);
|
||||
@@ -39,7 +41,9 @@ namespace CogSampleLog
|
||||
FCogDebugLog::AddLogCategory(LogCogControlRotation, "Control Rotation", "Debug Draw of the Character Control Rotation");
|
||||
FCogDebugLog::AddLogCategory(LogCogInput, "Input", "Log about the input actions");
|
||||
FCogDebugLog::AddLogCategory(LogCogPosition, "Position", "Debug draw of a character position");
|
||||
FCogDebugLog::AddLogCategory(LogCogPossession, "Possession", "Log about the possession of player controller over a Character");
|
||||
FCogDebugLog::AddLogCategory(LogCogPossession, "Possession", "Log about the possession of a PlayerController over a Character");
|
||||
FCogDebugLog::AddLogCategory(LogCogPredictedActor, "Predicted Actor", "Log and debug draw about the prediction of actors.");
|
||||
FCogDebugLog::AddLogCategory(LogCogProjectile, "Projectile", "Log and debug draw about the projectiles.");
|
||||
FCogDebugLog::AddLogCategory(LogCogRotation, "Rotation", "Debug Draw a Character Rotation");
|
||||
FCogDebugLog::AddLogCategory(LogCogSkeleton, "Skeleton", "Debug Draw a Character Skeleton");
|
||||
FCogDebugLog::AddLogCategory(LogCogTargetAcquisition, "Target Acquisition", "Debug Draw the target acquisition debug draw");
|
||||
|
||||
@@ -12,6 +12,8 @@ DECLARE_LOG_CATEGORY_EXTERN(LogCogControlRotation, Warning, All);
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogCogInput, Warning, All);
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogCogPosition, Warning, All);
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogCogPossession, Warning, All);
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogCogPredictedActor, Warning, All);
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogCogProjectile, Warning, All);
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogCogRotation, Warning, All);
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogCogSkeleton, Warning, All);
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogCogTargetAcquisition, Warning, All);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "CogSampleCharacter.h"
|
||||
#include "CogSampleLogCategories.h"
|
||||
#include "CogSampleTargetAcquisition.h"
|
||||
#include "GameFramework/PlayerState.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
|
||||
#if ENABLE_COG
|
||||
@@ -171,7 +172,7 @@ void ACogSamplePlayerController::TickTargeting(float DeltaSeconds)
|
||||
#if ENABLE_COG
|
||||
if (Target != nullptr && PossessedCharacter != nullptr)
|
||||
{
|
||||
FCogDebugDraw::Segment(LogCogTargetAcquisition, PossessedCharacter.Get(), PossessedCharacter->GetActorLocation(), Target->GetActorLocation(), FColor::White, false);
|
||||
FCogDebugDraw::Segment(LogCogTargetAcquisition, this, PossessedCharacter->GetActorLocation(), Target->GetActorLocation(), FColor::White, false);
|
||||
}
|
||||
#endif //ENABLE_COG
|
||||
}
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "CogSamplePlayerController.generated.h"
|
||||
|
||||
class UCogSampleTargetAcquisition;
|
||||
class ACogSampleCharacter;
|
||||
class UCogSampleSpawnPredictionComponent;
|
||||
class UCogSampleTargetAcquisition;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FCogSampleTargetChangedEventDelegate, ACogSamplePlayerController*, Controller, AActor*, NewTarget, AActor*, OldTarget);
|
||||
@@ -53,10 +54,15 @@ public:
|
||||
|
||||
AActor* GetTarget() const { return Target.Get(); }
|
||||
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FCogSampleTargetChangedEventDelegate OnTargetChanged;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Spawn Predictions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
UPROPERTY()
|
||||
TArray<UCogSampleSpawnPredictionComponent*> SpawnPredictions;
|
||||
|
||||
private:
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CogSampleProgressionLevelInterface.generated.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
UINTERFACE(MinimalAPI, Blueprintable)
|
||||
class UCogSampleProgressionLevelInterface : public UInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
class ICogSampleProgressionLevelInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
virtual int32 GetProgressionLevel() const { return 0; }
|
||||
|
||||
virtual void SetProgressionLevel(int32) { }
|
||||
};
|
||||
@@ -0,0 +1,428 @@
|
||||
#include "CogSampleProjectileComponent.h"
|
||||
|
||||
#include "AbilitySystemGlobals.h"
|
||||
#include "AbilitySystemComponent.h"
|
||||
#include "CogCommon.h"
|
||||
#include "CogSampleFunctionLibrary_Gameplay.h"
|
||||
#include "CogSampleFunctionLibrary_Team.h"
|
||||
#include "CogSampleLogCategories.h"
|
||||
|
||||
#if ENABLE_COG
|
||||
#include "CogDebugLog.h"
|
||||
#include "CogDebugDraw.h"
|
||||
#endif //ENABLE_COG
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleProjectileComponent::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
Creator = UCogSampleFunctionLibrary_Gameplay::GetCreator(GetOwner());
|
||||
SpawnPrediction = GetOwner()->FindComponentByClass<UCogSampleSpawnPredictionComponent>();
|
||||
|
||||
if (GetOwner()->HasAuthority())
|
||||
{
|
||||
RegisterAllEffects();
|
||||
}
|
||||
|
||||
Collision = Cast<USphereComponent>(CollisionReference.GetComponent(GetOwner()));
|
||||
if (Collision != nullptr)
|
||||
{
|
||||
Collision->OnComponentBeginOverlap.AddDynamic(this, &UCogSampleProjectileComponent::OnCollisionOverlapBegin);
|
||||
}
|
||||
|
||||
AssistanceOverlap = Cast<USphereComponent>(OverlapReference.GetComponent(GetOwner()));
|
||||
if (AssistanceOverlap != nullptr)
|
||||
{
|
||||
AssistanceOverlap->OnComponentBeginOverlap.AddDynamic(this, &UCogSampleProjectileComponent::OnAssistanceOverlapBegin);
|
||||
}
|
||||
|
||||
#if ENABLE_COG
|
||||
if (FCogDebugLog::IsLogCategoryActive(LogCogProjectile))
|
||||
{
|
||||
LastDebugLocation = GetOwner()->GetActorLocation();
|
||||
}
|
||||
#endif //ENABLE_COG
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleProjectileComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||
{
|
||||
//if (CosmeticComponent != nullptr)
|
||||
//{
|
||||
// CosmeticComponent->AddLocalRotation(CurrentCosmeticAngularVelocity * DeltaTime);
|
||||
// CurrentCosmeticAngularVelocity *= FMath::Clamp(1.0f - CosmeticAngularDrag * DeltaTime, 0.0f, 1.0f);
|
||||
//}
|
||||
|
||||
//PreviousVelocity = Velocity;
|
||||
|
||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||
|
||||
//TravelingTime += DeltaTime;
|
||||
|
||||
#if ENABLE_COG
|
||||
|
||||
if (FCogDebugLog::IsLogCategoryActive(LogCogProjectile))
|
||||
{
|
||||
const float CollisionRadius = Collision != nullptr ? Collision->GetScaledSphereRadius() : 0.0f;
|
||||
const float AssistanceRadius = AssistanceOverlap != nullptr ? AssistanceOverlap->GetScaledSphereRadius() : 0.0f;
|
||||
const float DebugRadius = FMath::Max(CollisionRadius, AssistanceRadius);
|
||||
const FColor Color = SpawnPrediction != nullptr ? SpawnPrediction->GetRoleColor() : FColor(128, 128, 128, 255);
|
||||
const bool Show = SpawnPrediction == nullptr || SpawnPrediction->GetRole() != ECogSampleSpawnPredictionRole::Replicated;
|
||||
|
||||
if (Show && UpdatedComponent != nullptr)
|
||||
{
|
||||
const FVector Location = UpdatedComponent->GetComponentLocation();
|
||||
const FVector Delta = Location - LastDebugLocation;
|
||||
|
||||
if (LogCogProjectile.GetVerbosity() == ELogVerbosity::VeryVerbose)
|
||||
{
|
||||
FCogDebugDraw::Sphere(LogCogProjectile, GetOwner(), Location, DebugRadius, Color, true, 0);
|
||||
FCogDebugDraw::Axis(LogCogProjectile, GetOwner(), Location, UpdatedComponent->GetComponentRotation(), 50.0f, true, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
FCogDebugDraw::Point(LogCogProjectile, GetOwner(), Location, 5.0f, Color, true, 0);
|
||||
}
|
||||
|
||||
if (Delta.IsNearlyZero() == false)
|
||||
{
|
||||
FCogDebugDraw::Segment(LogCogProjectile, GetOwner(), LastDebugLocation, Location, Color, true, 0);
|
||||
}
|
||||
|
||||
LastDebugLocation = Location;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //ENABLE_COG
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
//void UCogSampleProjectileComponent::CatchupReplicatedActor(float CatchupDuration)
|
||||
//{
|
||||
// COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Projectile:%s - Role:%s - CatchupDuration:%0.2f"), *GetName(), *GetRoleName(), CatchupDuration);
|
||||
//
|
||||
// const FVector OldPosition = GetOwner()->GetActorLocation();
|
||||
// const float OldSpeed = Velocity.Length();
|
||||
//
|
||||
// TickComponent(CatchupDuration, LEVELTICK_All, nullptr);
|
||||
//
|
||||
// COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator, TEXT("Distance:%0.2f - OldSpeed:%0.2f - NewSpeed:%0.2f"),
|
||||
// (GetOwner()->GetActorLocation() - OldPosition).Length(),
|
||||
// OldSpeed,
|
||||
// Velocity.Length());
|
||||
//
|
||||
// if (SpawnPrediction != nullptr)
|
||||
// {
|
||||
// if (UCogSampleSpawnPrediction* SpawnPrediction2 = SpawnPrediction->GetSpawnPrediction())
|
||||
// {
|
||||
// SpawnPrediction2->ProjectileMovement->Velocity = ProjectileMovement->Velocity;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleProjectileComponent::RegisterAllEffects()
|
||||
{
|
||||
TArray<TSubclassOf<UGameplayEffect>> AllEffects;
|
||||
|
||||
for (const FCogSampleProjectileEffectConfig& EffectConfig : Effects)
|
||||
{
|
||||
for (TSubclassOf<UGameplayEffect> EffectClass : EffectConfig.Effects)
|
||||
{
|
||||
AllEffects.Add(EffectClass);
|
||||
}
|
||||
}
|
||||
|
||||
UCogSampleFunctionLibrary_Gameplay::MakeOutgoingSpecs(GetOwner(), AllEffects, BakedEffects, EffectsMap);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool UCogSampleProjectileComponent::ShouldProcessOverlap(AActor* OtherActor, UPrimitiveComponent* OtherComp, bool RequireValidActor)
|
||||
{
|
||||
if (RequireValidActor && OtherActor == nullptr)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Skipped:InvalidActor"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetOwner()->GetLocalRole() != ROLE_Authority)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Skipped:NotAuthority"));
|
||||
return false;
|
||||
}
|
||||
|
||||
//if (IsStopped)
|
||||
//{
|
||||
// //----------------------------------------------------------------------------------------
|
||||
// // We can receive overlap events the same frame Stop is called. It shouldn't happen after.
|
||||
// //----------------------------------------------------------------------------------------
|
||||
// COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Skipped:Stopped"));
|
||||
// return false;
|
||||
//}
|
||||
|
||||
if (OtherComp == nullptr)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Warning, Creator.Get(), TEXT("Skipped:InvalidCollider"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (OtherActor == GetOwner())
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Skipped:HittingSelf"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CanHitCreator == false && OtherActor == Creator)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Skipped:HittingCreator"));
|
||||
return false;
|
||||
}
|
||||
|
||||
////-----------------------------------------------------------------------------------------
|
||||
//// Don't overlap if OtherActor is the simulated proxy replicated one time from server to
|
||||
//// client for synch-up
|
||||
////-----------------------------------------------------------------------------------------
|
||||
//if (OtherActor->IsA(AGPCoreProjectile::StaticClass()) && OtherActor->GetLocalRole() == ROLE_SimulatedProxy)
|
||||
//{
|
||||
// COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Skipped:SimulatedProxyProjectile"));
|
||||
// return false;
|
||||
//}
|
||||
|
||||
if (IsAlreadyProcessingAnOverlap)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Skipped:AlreadyProcessingAnOverlap"));
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// Ignore multiple hits on the same actor. This can happen if this the has multiple
|
||||
// collisions, such as the character hit volumes (head, arm, chest, ...)
|
||||
//-----------------------------------------------------------------------------------------
|
||||
if (HitActors.Contains(OtherActor))
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Skipped:AlreadyHit"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleProjectileComponent::OnCollisionOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool IsFromSweep, const FHitResult& SweepHit)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Projectile:%s - Role:%s - Other:%s - Comp:%s"),
|
||||
*GetName(),
|
||||
*GetRoleName(),
|
||||
OtherActor != nullptr ? *OtherActor->GetName() : TEXT("NULL"),
|
||||
OtherComp != nullptr ? *OtherComp->GetName() : TEXT("NULL"));
|
||||
|
||||
if (ShouldProcessOverlap(OtherActor, OtherComp, false) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TGuardValue<bool> OverlapGuard(IsAlreadyProcessingAnOverlap, true);
|
||||
FHitResult PreciseHit;
|
||||
|
||||
if (IsFromSweep)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
// When the projectile moves, it moves with sweep activated.
|
||||
//-----------------------------------------------------------------------------
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Method:IsFromSweep"));
|
||||
PreciseHit = SweepHit;
|
||||
}
|
||||
else if (Collision != nullptr)
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
// Trace to find the accurate collision location. Use the largest collider
|
||||
// which should be the assistance sphere, to make sure we find a result.
|
||||
// If we were using the collision sphere after an assistance sphere overlap,
|
||||
// we could miss the sweep.
|
||||
//-----------------------------------------------------------------------------
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Method:SweepComponent"));
|
||||
|
||||
USphereComponent* TestComp = (AssistanceOverlap != nullptr && AssistanceOverlap->GetUnscaledSphereRadius() > Collision->GetUnscaledSphereRadius()) ? AssistanceOverlap : Collision;
|
||||
OtherComp->SweepComponent(PreciseHit, GetOwner()->GetActorLocation() - Velocity * 10.f, GetOwner()->GetActorLocation() + Velocity, FQuat::Identity, TestComp->GetCollisionShape(), TestComp->bTraceComplexOnMove);
|
||||
|
||||
// SweepComponent specifically does not return us the Physical Material of the hit surface, so we look it up manually
|
||||
if (PreciseHit.GetComponent() != nullptr)
|
||||
{
|
||||
PreciseHit.PhysMaterial = PreciseHit.GetComponent()->GetBodyInstance()->GetSimplePhysicalMaterial();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
// Fallback that uses a raycast if we have no CollisionComp to find a more
|
||||
// accurate collision location. It should never happen.
|
||||
//-----------------------------------------------------------------------------
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Method:LineTrace"));
|
||||
static const FName TraceTag(TEXT("UCogSampleProjectileComponent::OnCollisionOverlapBegin"));
|
||||
FCollisionQueryParams QueryParams(TraceTag, false, GetOwner());
|
||||
QueryParams.bReturnPhysicalMaterial = true;
|
||||
OtherComp->LineTraceComponent(PreciseHit, GetOwner()->GetActorLocation() - Velocity * 10.f, GetOwner()->GetActorLocation() + Velocity, QueryParams);
|
||||
}
|
||||
|
||||
TryHit(PreciseHit);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleProjectileComponent::OnAssistanceOverlapBegin(UPrimitiveComponent* overlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool IsFromSweep, const FHitResult& Hit)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Projectile:%s - Role:%s - Other:%s - Comp:%s"),
|
||||
*GetName(),
|
||||
*GetRoleName(),
|
||||
OtherActor != nullptr ? *OtherActor->GetName() : TEXT("NULL"),
|
||||
OtherComp != nullptr ? *OtherComp->GetName() : TEXT("NULL"));
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Call ShouldProcessOverlap with a requirement of a valid actor because the
|
||||
// assistance overlap is made to overlap only against actors, not static objects which
|
||||
// would be null actor
|
||||
//-------------------------------------------------------------------------------------
|
||||
if (ShouldProcessOverlap(OtherActor, OtherComp, true) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Since PawnOverlapSphere doesn't hit blocking objects, it is possible it is touching
|
||||
// a target through a wall. Make sure that the hit is valid before proceeding.
|
||||
//
|
||||
// TODO: This is an approximation that does not always work if the assistance sphere
|
||||
// is big. The raycast can pass even if there is a collision in the trajectory of the
|
||||
// projectile, because we don't trace along the projectiles trajectory, but against
|
||||
// both actors positions.
|
||||
//
|
||||
// This test is skipped if the projectile collision has been disabled. When the
|
||||
// collision is disabled it means we want the projectile to pass through walls.
|
||||
//-------------------------------------------------------------------------------------
|
||||
bool IsValidOverlap = true;
|
||||
if (Collision->GetCollisionEnabled())
|
||||
{
|
||||
static const FName TraceTag(TEXT("UCogSampleProjectileComponent::OnAssistanceOverlapBegin"));
|
||||
FCollisionQueryParams QueryParams(TraceTag, true, GetOwner());
|
||||
QueryParams.AddIgnoredActor(OtherActor);
|
||||
const FVector OtherLocation = IsFromSweep ? (FVector)Hit.Location : OtherActor->GetActorLocation();
|
||||
if (GetWorld()->LineTraceTestByProfile(OtherLocation, GetOwner()->GetActorLocation(), Collision->GetCollisionProfileName(), QueryParams) == false)
|
||||
{
|
||||
IsValidOverlap = true;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Call OnCollisionOverlapBegin since its doing the sweep test.
|
||||
//-------------------------------------------------------------------------------------
|
||||
if (IsValidOverlap)
|
||||
{
|
||||
OnCollisionOverlapBegin(Collision, OtherActor, OtherComp, OtherBodyIndex, IsFromSweep, Hit);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleProjectileComponent::TryHit(const FHitResult& HitResult)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Projectile:%s - Role:%s - Other:%s - Comp:%s - Bone:%s"),
|
||||
*GetName(),
|
||||
*GetRoleName(),
|
||||
HitResult.GetActor() != nullptr ? *HitResult.GetActor()->GetName() : TEXT("NULL"),
|
||||
HitResult.GetComponent() != nullptr ? *HitResult.GetComponent()->GetName() : TEXT("NULL"),
|
||||
*HitResult.BoneName.ToString());
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// User defined callback for gameplay logic
|
||||
//-----------------------------------------------------------------------------------------
|
||||
if (ShouldHit(HitResult) == false)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Skipped by ShouldHit callback"));
|
||||
return;
|
||||
}
|
||||
|
||||
HitActors.Add(HitResult.GetActor());
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// User defined callback to decide what should happen to projectile (Stop, Attach, ...)
|
||||
//-----------------------------------------------------------------------------------------
|
||||
FCogSampleHitConsequence HitConsequence;
|
||||
Hit(HitResult, HitConsequence);
|
||||
|
||||
if (HitConsequence.Stop)
|
||||
{
|
||||
//InternalStop(HitResult, HitConsequence);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleProjectileComponent::ClearHitActors()
|
||||
{
|
||||
HitActors.Empty();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool UCogSampleProjectileComponent::ShouldHit_Implementation(const FHitResult& Hit)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleProjectileComponent::Hit_Implementation(const FHitResult& HitResult, FCogSampleHitConsequence& hitConsequence)
|
||||
{
|
||||
AActor* HitActor = HitResult.GetActor();
|
||||
|
||||
#if ENABLE_COG
|
||||
FCogDebugDraw::Arrow(LogCogProjectile, GetOwner(), HitResult.Location, HitResult.Location + HitResult.Normal * 50.0f, FColor::Red, true, 0);
|
||||
FCogDebugDraw::Box(LogCogProjectile, GetOwner(), HitResult.Location, FVector(0.0f, 5.0f, 5.0f), FRotationMatrix::MakeFromX(HitResult.Normal).ToQuat(), FColor::Red, true, 0);
|
||||
#endif //ENABLE_COG
|
||||
|
||||
for (const FCogSampleProjectileEffectConfig& EffectConfig : Effects)
|
||||
{
|
||||
for (TSubclassOf<UGameplayEffect> EffectClass : EffectConfig.Effects)
|
||||
{
|
||||
if (UCogSampleFunctionLibrary_Team::MatchAllegiance(GetOwner(), HitActor, EffectConfig.Allegiance) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FGameplayEffectSpecHandle* Handle = EffectsMap.Find(EffectClass);
|
||||
if (Handle == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FGameplayEffectSpec* Spec = Handle->Data.Get();
|
||||
if (Spec == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (UCogSampleFunctionLibrary_Gameplay::IsDead(HitActor) && EffectConfig.AffectDead == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UAbilitySystemComponent* TargetAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(HitActor);
|
||||
if (TargetAbilitySystem == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Spec->GetContext().AddHitResult(HitResult, true);
|
||||
TargetAbilitySystem->ApplyGameplayEffectSpecToSelf(*Spec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
FString UCogSampleProjectileComponent::GetRoleName() const
|
||||
{
|
||||
if (SpawnPrediction == nullptr)
|
||||
{
|
||||
return TEXT("No Prediction");
|
||||
}
|
||||
|
||||
return SpawnPrediction->GetRoleName();
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/SphereComponent.h"
|
||||
#include "GameFramework/ProjectileMovementComponent.h"
|
||||
#include "CogSampleSpawnPredictionComponent.h"
|
||||
#include "GameplayEffect.h"
|
||||
#include "CogSampleProjectileComponent.generated.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// FCogSampleProjectileEffectConfig
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
USTRUCT(BlueprintType)
|
||||
struct FCogSampleProjectileEffectConfig
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (Bitmask, BitmaskEnum = "/Script/CogSample.ECogSampleAllegianceFilter"))
|
||||
int32 Allegiance = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
bool AffectDead = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TArray<TSubclassOf<UGameplayEffect>> Effects;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// FCogSampleHitConsequence
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
USTRUCT(BlueprintType)
|
||||
struct FCogSampleHitConsequence
|
||||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
bool Stop = false;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
bool AttachToComponent = false;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
bool HideOnStop = false;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// UCogSampleProjectileComponent
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
UCLASS(BlueprintType, meta = (BlueprintSpawnableComponent))
|
||||
class UCogSampleProjectileComponent : public UProjectileMovementComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void ClearHitActors();
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Projectile")
|
||||
TArray<FCogSampleProjectileEffectConfig> Effects;
|
||||
|
||||
UPROPERTY(Transient, BlueprintReadWrite, Category = "Internal")
|
||||
TArray<FGameplayEffectSpecHandle> BakedEffects;
|
||||
|
||||
protected:
|
||||
|
||||
virtual FString GetRoleName() const;
|
||||
|
||||
//virtual void CatchupReplicatedActor(float CatchupDuration);
|
||||
|
||||
virtual bool ShouldProcessOverlap(AActor* OtherActor, UPrimitiveComponent* OtherComp, bool RequireValidActor);
|
||||
|
||||
virtual void TryHit(const FHitResult& Hit);
|
||||
|
||||
UFUNCTION()
|
||||
virtual void OnCollisionOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool IsFromSweep, const FHitResult& SweepHit);
|
||||
|
||||
UFUNCTION()
|
||||
virtual void OnAssistanceOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool IsFromSweep, const FHitResult& SweepHit);
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
|
||||
bool ShouldHit(const FHitResult& hit);
|
||||
|
||||
/** Blueprint hook called when projectile hits something */
|
||||
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
|
||||
void Hit(const FHitResult& Hit, FCogSampleHitConsequence& HitConsequence);
|
||||
|
||||
void RegisterAllEffects();
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
FComponentReference CollisionReference;
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
FComponentReference OverlapReference;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Projectile")
|
||||
bool CanHitCreator = false;
|
||||
|
||||
/** Sphere collision component */
|
||||
UPROPERTY()
|
||||
TObjectPtr<USphereComponent> Collision = nullptr;
|
||||
|
||||
/** Overlap collision component */
|
||||
UPROPERTY()
|
||||
TObjectPtr<USphereComponent> AssistanceOverlap = nullptr;
|
||||
|
||||
UPROPERTY()
|
||||
TWeakObjectPtr<AActor> Creator = nullptr;
|
||||
|
||||
UPROPERTY()
|
||||
TWeakObjectPtr<UCogSampleSpawnPredictionComponent> SpawnPrediction = nullptr;
|
||||
|
||||
/** Re-entrancy guard */
|
||||
bool IsAlreadyProcessingAnOverlap = false;
|
||||
|
||||
/** The actors that were hit with this projectile. Used to prevent touching the same actor multiple times */
|
||||
TSet<AActor*> HitActors;
|
||||
|
||||
TMap<TSubclassOf<UGameplayEffect>, FGameplayEffectSpecHandle> EffectsMap;
|
||||
|
||||
#if ENABLE_COG
|
||||
FVector LastDebugLocation = FVector::ZeroVector;
|
||||
#endif //ENABLE_COG
|
||||
};
|
||||
@@ -0,0 +1,334 @@
|
||||
#include "CogSampleSpawnPredictionComponent.h"
|
||||
|
||||
#include "Abilities/GameplayAbility.h"
|
||||
#include "Abilities/GameplayAbilityTypes.h"
|
||||
#include "CogSampleLogCategories.h"
|
||||
#include "CogSampleFunctionLibrary_Gameplay.h"
|
||||
#include "CogSamplePlayerController.h"
|
||||
#include "Engine/World.h"
|
||||
#include "GameFramework/Pawn.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
|
||||
#if ENABLE_COG
|
||||
#include "CogDebugDraw.h"
|
||||
#include "CogDebugLog.h"
|
||||
#endif //ENABLE_COG
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// FCogSampleSpawnPredictionKey
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
FString FCogSampleSpawnPredictionKey::ToString() const
|
||||
{
|
||||
return FString::Printf(TEXT("[Creator=%s Ability=%s PredictionKey=%s Index=%d]"), *Creator.ToString(), *Ability.ToString(), *PredictionKey.ToString(), InstanceIndex);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool FCogSampleSpawnPredictionKey::operator==(const FCogSampleSpawnPredictionKey& other) const
|
||||
{
|
||||
return Creator == other.Creator
|
||||
&& Ability == other.Ability
|
||||
&& PredictionKey == other.PredictionKey
|
||||
&& InstanceIndex == other.InstanceIndex;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool FCogSampleSpawnPredictionKey::operator!=(const FCogSampleSpawnPredictionKey& other) const
|
||||
{
|
||||
return ((*this == other) == false);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
FCogSampleSpawnPredictionKey FCogSampleSpawnPredictionKey::MakeFromAbility(const UGameplayAbility& InAbility, int32 InInstanceIndex)
|
||||
{
|
||||
FGameplayAbilitySpec* Spec = InAbility.GetCurrentAbilitySpec();
|
||||
check(Spec);
|
||||
|
||||
FCogSampleSpawnPredictionKey Key;
|
||||
Key.Creator = InAbility.GetAvatarActorFromActorInfo() != nullptr ? InAbility.GetAvatarActorFromActorInfo()->GetFName() : FName();
|
||||
Key.Ability = InAbility.GetFName();
|
||||
Key.PredictionKey = Spec->ActivationInfo.GetActivationPredictionKey();
|
||||
Key.InstanceIndex = InInstanceIndex;
|
||||
Key.GameTime = InAbility.GetWorld()->GetTimeSeconds();
|
||||
return Key;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// UCogSampleSpawnPredictionComponent
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
UCogSampleSpawnPredictionComponent::UCogSampleSpawnPredictionComponent(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
SetIsReplicatedByDefault(true);
|
||||
|
||||
PredictedSpawn = nullptr;
|
||||
ReplicatedActor = nullptr;
|
||||
|
||||
#if ENABLE_COG
|
||||
PrimaryComponentTick.bCanEverTick = true;
|
||||
PrimaryComponentTick.bStartWithTickEnabled = true;
|
||||
#endif //ENABLE_COG
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleSpawnPredictionComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// TODO: Push Model
|
||||
//-------------------------------------------------------------------------
|
||||
DOREPLIFETIME_CONDITION(UCogSampleSpawnPredictionComponent, PredictedActorKey, COND_OwnerOnly);
|
||||
DOREPLIFETIME(UCogSampleSpawnPredictionComponent, Creator);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleSpawnPredictionComponent::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
APawn* PawnCreator = Cast<APawn>(Creator);
|
||||
PlayerController = PawnCreator ? Cast<ACogSamplePlayerController>(PawnCreator->Controller) : nullptr;
|
||||
//IsReplicatedActor = GetOwner()->HasAuthority() == false && PlayerController != nullptr;
|
||||
|
||||
if (PlayerController != nullptr)
|
||||
{
|
||||
if (GetOwner()->HasAuthority() == false)
|
||||
{
|
||||
Role = ECogSampleSpawnPredictionRole::Replicated;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Role = ECogSampleSpawnPredictionRole::Remote;
|
||||
}
|
||||
|
||||
if (PlayerController != nullptr)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogPredictedActor, ELogVerbosity::Verbose, UCogSampleFunctionLibrary_Gameplay::GetInstigator(GetOwner()), TEXT("Actor:%s - Role:%s"), *GetName(), *GetRoleName());
|
||||
ReconcileReplicatedWithPredicted();
|
||||
}
|
||||
|
||||
#if ENABLE_COG
|
||||
if (FCogDebugLog::IsLogCategoryActive(LogCogPredictedActor))
|
||||
{
|
||||
LastDebugLocation = GetOwner()->GetActorLocation();
|
||||
}
|
||||
#endif //ENABLE_COG
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleSpawnPredictionComponent::ReconcileReplicatedWithPredicted()
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
// If we are a replicated actor on a local client, find the corresponding
|
||||
// predicted actor and sync them together.
|
||||
//-------------------------------------------------------------------------
|
||||
if (Role != ECogSampleSpawnPredictionRole::Replicated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CleanInvalidPredictedActors();
|
||||
|
||||
int32 PredictedActorIndex = FindSpawnPredictionIndex();
|
||||
if (PredictedActorIndex == INDEX_NONE)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogPredictedActor, ELogVerbosity::Warning, Creator.Get(), TEXT("Failed to find predicted actor. Key:%s"), *PredictedActorKey.ToString());
|
||||
|
||||
#if ENABLE_COG
|
||||
for (const UCogSampleSpawnPredictionComponent* Candidate : PlayerController->SpawnPredictions)
|
||||
{
|
||||
if (Candidate != nullptr)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogPredictedActor, ELogVerbosity::Warning, Creator.Get(), TEXT(" Candidate:%s"), *Candidate->PredictedActorKey.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogPredictedActor, ELogVerbosity::Warning, Creator.Get(), TEXT(" Candidate:NULL"));
|
||||
}
|
||||
}
|
||||
#endif //ENABLE_COG
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
UCogSampleSpawnPredictionComponent* SpawnPrediction = PlayerController->SpawnPredictions[PredictedActorIndex];
|
||||
PlayerController->SpawnPredictions.RemoveAt(PredictedActorIndex, 1);
|
||||
SyncReplicatedWithPredicted(SpawnPrediction);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleSpawnPredictionComponent::OnRep_PredictedActorKey()
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogPredictedActor, ELogVerbosity::Verbose, Creator.Get(), TEXT("Actor:%s - Role:%s - PredictedActorKey:%s"), *GetName(), *GetRoleName(), *PredictedActorKey.ToString());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleSpawnPredictionComponent::CleanInvalidPredictedActors()
|
||||
{
|
||||
if (PlayerController == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<UCogSampleSpawnPredictionComponent*>& SpawnPredictions = PlayerController->SpawnPredictions;
|
||||
for (int32 i = 0; i < SpawnPredictions.Num(); )
|
||||
{
|
||||
UCogSampleSpawnPredictionComponent* Candidate = SpawnPredictions[i];
|
||||
if (Candidate == nullptr || Candidate->GetOwner()->IsPendingKillPending())
|
||||
{
|
||||
SpawnPredictions.RemoveAt(i, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
int32 UCogSampleSpawnPredictionComponent::FindSpawnPredictionIndex()
|
||||
{
|
||||
if (PlayerController == nullptr)
|
||||
{
|
||||
return INDEX_NONE;
|
||||
}
|
||||
|
||||
int32 Index = PlayerController->SpawnPredictions.IndexOfByPredicate([this](const UCogSampleSpawnPredictionComponent* Candidate)
|
||||
{
|
||||
if (Candidate == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Candidate->GetClass() != GetClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Candidate->PredictedActorKey != PredictedActorKey)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return Index;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleSpawnPredictionComponent::SyncReplicatedWithPredicted(UCogSampleSpawnPredictionComponent* InPredictedActor)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogPredictedActor, ELogVerbosity::Verbose, Creator.Get(), TEXT("Actor:%s - Role:%s - PredictedActor:%s"), *GetName(), *GetRoleName(), InPredictedActor != nullptr ? *InPredictedActor->GetName() : TEXT("NULL"));
|
||||
|
||||
PredictedSpawn = InPredictedActor;
|
||||
|
||||
if (PredictedSpawn != nullptr)
|
||||
{
|
||||
PredictedSpawn->ReplicatedActor = this;
|
||||
|
||||
const float PredictedLifeSpawn = PredictedSpawn->GetOwner()->GetLifeSpan();
|
||||
GetOwner()->SetLifeSpan(PredictedLifeSpawn);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Destroying the replicated actor doesn't currently work because the server will keep it alive on all clients
|
||||
// no matter what. We should investigate a way to make it work, but currently we hide it.
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
if (DestroyReplicatedActor)
|
||||
{
|
||||
SetVisibility(false);
|
||||
GetOwner()->Destroy();
|
||||
}
|
||||
else if (HideReplicatedActor)
|
||||
{
|
||||
SetVisibility(false);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleSpawnPredictionComponent::SetVisibility(bool Value)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogPredictedActor, ELogVerbosity::Verbose, Creator.Get(), TEXT("Actor:%s - Role:%s - Visibility:%d"), *GetName(), *GetRoleName(), Value);
|
||||
|
||||
GetOwner()->SetActorHiddenInGame(!Value);
|
||||
|
||||
TArray<USceneComponent*> OtherComponents;
|
||||
GetOwner()->GetComponents<USceneComponent>(OtherComponents);
|
||||
|
||||
for (int32 i = 0; i < OtherComponents.Num(); i++)
|
||||
{
|
||||
OtherComponents[i]->SetVisibility(Value);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
void UCogSampleSpawnPredictionComponent::OnComponentDestroyed(bool bDestroyingHierarchy)
|
||||
{
|
||||
COG_LOG_OBJECT(LogCogPredictedActor, ELogVerbosity::Verbose, Creator.Get(), TEXT("Actor:%s - Role:%s"), *GetName(), *GetRoleName());
|
||||
|
||||
if (ReplicatedActor != nullptr)
|
||||
{
|
||||
ReplicatedActor->GetOwner()->Destroy();
|
||||
}
|
||||
|
||||
Super::OnComponentDestroyed(bDestroyingHierarchy);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
FString UCogSampleSpawnPredictionComponent::GetRoleName() const
|
||||
{
|
||||
switch (Role)
|
||||
{
|
||||
case ECogSampleSpawnPredictionRole::Server: return "Server";
|
||||
case ECogSampleSpawnPredictionRole::Predicted: return "Predicted";
|
||||
case ECogSampleSpawnPredictionRole::Replicated: return "Replicated";
|
||||
case ECogSampleSpawnPredictionRole::Remote: return "Remote";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
FColor UCogSampleSpawnPredictionComponent::GetRoleColor() const
|
||||
{
|
||||
switch (Role)
|
||||
{
|
||||
case ECogSampleSpawnPredictionRole::Server: return FColor::FColor(255, 0, 0, 255);
|
||||
case ECogSampleSpawnPredictionRole::Predicted: return FColor::FColor(255, 255, 0, 255);
|
||||
case ECogSampleSpawnPredictionRole::Replicated: return FColor::FColor(128, 128, 0, 255);
|
||||
case ECogSampleSpawnPredictionRole::Remote: return FColor::FColor(255, 0, 255, 255);
|
||||
}
|
||||
|
||||
return FColor(128, 128, 128, 255);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
#if ENABLE_COG
|
||||
|
||||
void UCogSampleSpawnPredictionComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||
{
|
||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||
|
||||
const FVector Location = GetOwner()->GetActorLocation();
|
||||
|
||||
if (FCogDebugLog::IsLogCategoryActive(LogCogPredictedActor))
|
||||
{
|
||||
const FColor Color = GetRoleColor();
|
||||
const FVector Delta = Location - LastDebugLocation;
|
||||
|
||||
FCogDebugDraw::Axis(LogCogPredictedActor, this, Location, GetOwner()->GetActorRotation(), 50.0f, true, 0);
|
||||
FCogDebugDraw::Point(LogCogPredictedActor, this, Location, 8.0f, Color, true, 0);
|
||||
|
||||
if (Delta.IsNearlyZero() == false)
|
||||
{
|
||||
FCogDebugDraw::Segment(LogCogPredictedActor, this, LastDebugLocation, Location, Color, true, 0);
|
||||
}
|
||||
}
|
||||
|
||||
LastDebugLocation = Location;
|
||||
}
|
||||
|
||||
#endif //ENABLE_COG
|
||||
@@ -0,0 +1,146 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CogCommon.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "GameplayPrediction.h"
|
||||
#include "CogSampleSpawnPredictionComponent.generated.h"
|
||||
|
||||
class UGameplayAbility;
|
||||
class ACogSamplePlayerController;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// FCogSamplePredictedActorKey
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
USTRUCT()
|
||||
struct FCogSampleSpawnPredictionKey
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY()
|
||||
FName Creator;
|
||||
|
||||
UPROPERTY()
|
||||
FName Ability;
|
||||
|
||||
UPROPERTY()
|
||||
FPredictionKey PredictionKey;
|
||||
|
||||
UPROPERTY()
|
||||
int32 InstanceIndex = 0;
|
||||
|
||||
UPROPERTY()
|
||||
float GameTime = 0;
|
||||
|
||||
FString ToString() const;
|
||||
|
||||
bool operator==(const FCogSampleSpawnPredictionKey& other) const;
|
||||
|
||||
bool operator!=(const FCogSampleSpawnPredictionKey& other) const;
|
||||
|
||||
static FCogSampleSpawnPredictionKey MakeFromAbility(const UGameplayAbility& InAbility, int32 InInstanceIndex);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
UENUM()
|
||||
enum class ECogSampleSpawnPredictionRole : uint8
|
||||
{
|
||||
Server,
|
||||
Predicted,
|
||||
Replicated,
|
||||
Remote,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// UCogSamplePredictedActorComponent
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
UCLASS(BlueprintType, meta = (BlueprintSpawnableComponent))
|
||||
class UCogSampleSpawnPredictionComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UCogSampleSpawnPredictionComponent(const class FObjectInitializer& ObjectInitializer);
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
|
||||
virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override;
|
||||
|
||||
#if ENABLE_COG
|
||||
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
#endif //ENABLE_COG
|
||||
|
||||
virtual TWeakObjectPtr<AActor> GetCreator() const { return Creator; }
|
||||
|
||||
virtual void SetCreator(TWeakObjectPtr<AActor> Value) { Creator = Value; }
|
||||
|
||||
virtual const FCogSampleSpawnPredictionKey& GetSpawnPredictionKey() const { return PredictedActorKey; }
|
||||
|
||||
virtual void SetSpawnPredictionKey(const FCogSampleSpawnPredictionKey& Value) { PredictedActorKey = Value; }
|
||||
|
||||
virtual void SetSpawnTransform(FTransform Transform) { SpawnTransform = Transform; }
|
||||
|
||||
virtual FTransform GetSpawnTransform() { return SpawnTransform; }
|
||||
|
||||
virtual ECogSampleSpawnPredictionRole GetRole() const { return Role; }
|
||||
|
||||
virtual void SetRole(ECogSampleSpawnPredictionRole Value) { Role = Value; }
|
||||
|
||||
UCogSampleSpawnPredictionComponent* GetPredicted() const { return PredictedSpawn; }
|
||||
|
||||
UCogSampleSpawnPredictionComponent* GetReplicated() const { return ReplicatedActor; }
|
||||
|
||||
virtual void ReconcileReplicatedWithPredicted();
|
||||
|
||||
FString GetRoleName() const;
|
||||
|
||||
FColor GetRoleColor() const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual int32 FindSpawnPredictionIndex();
|
||||
|
||||
virtual void SyncReplicatedWithPredicted(UCogSampleSpawnPredictionComponent* PredictedSpawn);
|
||||
|
||||
void CleanInvalidPredictedActors();
|
||||
|
||||
void SetVisibility(bool Value);
|
||||
|
||||
UFUNCTION()
|
||||
void OnRep_PredictedActorKey();
|
||||
|
||||
UPROPERTY(Replicated)
|
||||
TWeakObjectPtr<AActor> Creator = nullptr;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadonly)
|
||||
bool DestroyReplicatedActor = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadonly)
|
||||
bool HideReplicatedActor = true;
|
||||
|
||||
UPROPERTY(BlueprintReadonly)
|
||||
UCogSampleSpawnPredictionComponent* PredictedSpawn = nullptr;
|
||||
|
||||
UPROPERTY(BlueprintReadonly)
|
||||
UCogSampleSpawnPredictionComponent* ReplicatedActor = nullptr;
|
||||
|
||||
UPROPERTY(BlueprintReadonly)
|
||||
ECogSampleSpawnPredictionRole Role = ECogSampleSpawnPredictionRole::Replicated;
|
||||
|
||||
UPROPERTY(BlueprintReadonly)
|
||||
TWeakObjectPtr<ACogSamplePlayerController> PlayerController = nullptr;
|
||||
|
||||
UPROPERTY(ReplicatedUsing = OnRep_PredictedActorKey)
|
||||
FCogSampleSpawnPredictionKey PredictedActorKey;
|
||||
|
||||
FTransform SpawnTransform;
|
||||
|
||||
#if ENABLE_COG
|
||||
FVector LastDebugLocation = FVector::ZeroVector;
|
||||
#endif //ENABLE_COG
|
||||
};
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CogSampleSpawnableInterface.generated.h"
|
||||
|
||||
UINTERFACE(MinimalAPI, Blueprintable)
|
||||
class UCogSampleSpawnableInterface : public UInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
class ICogSampleSpawnableInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
virtual AActor* GetCreator() const { return nullptr; }
|
||||
|
||||
virtual void SetCreator(AActor* Value) { }
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "CoreMinimal.h"
|
||||
#include "CogSampleTeamInterface.generated.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
UINTERFACE(MinimalAPI, Blueprintable)
|
||||
class UCogSampleTeamInterface : public UInterface
|
||||
{
|
||||
@@ -17,4 +16,7 @@ class ICogSampleTeamInterface
|
||||
public:
|
||||
|
||||
virtual int32 GetTeam() const { return 0; }
|
||||
|
||||
virtual void SetTeam(int32) { }
|
||||
};
|
||||
|
||||
|
||||
@@ -6,9 +6,17 @@
|
||||
|
||||
- CogEngine: More stats in the stats window
|
||||
- CogEngine: Overlay mode of stats.
|
||||
- CogEngine: Stat main menu widget could have a tooltip on each stat with a control to change set the emulation (FPS, Ping, Packetloss)
|
||||
- CogEngine: Add more info in stats tooltip (details, curves, ...)
|
||||
- CogEngine: Add screen settings (fullscreen, borderless, window and resolution)
|
||||
- CogEngine: make a better widget for CheckBoxState for input shortcuts
|
||||
|
||||
- CogSample: Add a custom window in sample (changing the character faction)
|
||||
- CogSample: Create more abilities
|
||||
- CogSample: Push Model
|
||||
- CogSample: Add timescale game tweak
|
||||
- CogSample: Add cooldown reduction
|
||||
- CogSample: Add more debug for area (change color on tick, duration ...)
|
||||
|
||||
- CogDebug: Check KismetExecutionMessage for warnings. As an exemple it is used by GEngine::GetWorldFromContextObject.
|
||||
|
||||
- CogInput: Add gamepad stick drag to set their values
|
||||
Reference in New Issue
Block a user