diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index 7f9d732..b6b8052 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -96,7 +96,7 @@ ManualIPAddress= +Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ") +Profiles=(Name="Pawn",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object. Can be used for capsule of any playerable character or AI. ") +Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldStatic"),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.") -+Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.") ++Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="CharacterMesh",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.") +Profiles=(Name="PhysicsActor",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=,HelpMessage="Simulating actors") +Profiles=(Name="Destructible",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Destructible",CustomResponses=,HelpMessage="Destructible actors") +Profiles=(Name="InvisibleWall",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldStatic object that is invisible.") @@ -105,8 +105,9 @@ 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="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") ++Profiles=(Name="ProjectileCollision",CollisionEnabled=QueryOnly,bCanModify=True,ObjectTypeName="Projectile",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(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),(Channel="CharacterMesh",Response=ECR_Overlap)),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_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),(Channel="CharacterMesh",Response=ECR_Overlap)),HelpMessage="Needs description") ++DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=False,bStaticObject=False,Name="CharacterMesh") +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))) diff --git a/Content/Characters/_Shared_/BP_Character.uasset b/Content/Characters/_Shared_/BP_Character.uasset index c856025..349e65d 100644 Binary files a/Content/Characters/_Shared_/BP_Character.uasset and b/Content/Characters/_Shared_/BP_Character.uasset differ diff --git a/Content/Core/Actors/BP_Base_Projectile.uasset b/Content/Core/Actors/BP_Base_Projectile.uasset index 6523c0d..f3a533f 100644 Binary files a/Content/Core/Actors/BP_Base_Projectile.uasset and b/Content/Core/Actors/BP_Base_Projectile.uasset differ diff --git a/Content/Core/Actors/BP_Base_ProjectileLauncher.uasset b/Content/Core/Actors/BP_Base_ProjectileLauncher.uasset index 8d4f1de..e5da814 100644 Binary files a/Content/Core/Actors/BP_Base_ProjectileLauncher.uasset and b/Content/Core/Actors/BP_Base_ProjectileLauncher.uasset differ diff --git a/Content/Core/Debug/DA_Debug_Engine.uasset b/Content/Core/Debug/DA_Debug_Engine.uasset index 4b7b5a4..84dc0e1 100644 Binary files a/Content/Core/Debug/DA_Debug_Engine.uasset and b/Content/Core/Debug/DA_Debug_Engine.uasset differ diff --git a/Content/Core/GameplayCues/Damage/VFX_Damage.uasset b/Content/Core/GameplayCues/Damage/VFX_Damage.uasset index 87f1192..1f4aaf6 100644 Binary files a/Content/Core/GameplayCues/Damage/VFX_Damage.uasset and b/Content/Core/GameplayCues/Damage/VFX_Damage.uasset differ diff --git a/Content/Ingredients/DamageArea/BP_DamageArea.uasset b/Content/Ingredients/DamageArea/BP_DamageArea.uasset deleted file mode 100644 index 14daf0a..0000000 Binary files a/Content/Ingredients/DamageArea/BP_DamageArea.uasset and /dev/null differ diff --git a/Content/Ingredients/DamageArea/GE_DamageArea.uasset b/Content/Ingredients/DamageArea/GE_DamageArea.uasset deleted file mode 100644 index 12c5db2..0000000 Binary files a/Content/Ingredients/DamageArea/GE_DamageArea.uasset and /dev/null differ diff --git a/Content/Ingredients/DamageProjectile/BP_DamageProjectileLauncher.uasset b/Content/Ingredients/DamageProjectile/BP_DamageProjectileLauncher.uasset deleted file mode 100644 index 4461a06..0000000 Binary files a/Content/Ingredients/DamageProjectile/BP_DamageProjectileLauncher.uasset and /dev/null differ diff --git a/Content/Ingredients/DamageProjectile/BP_Trap_Dart_Projectile.uasset b/Content/Ingredients/DamageProjectile/BP_Trap_Dart_Projectile.uasset deleted file mode 100644 index 626f27b..0000000 Binary files a/Content/Ingredients/DamageProjectile/BP_Trap_Dart_Projectile.uasset and /dev/null differ diff --git a/Content/Ingredients/DamageProjectile/BP_Trap_Dart.uasset b/Content/Mechanisms/Cannon/BP_Mechanism_Cannon.uasset similarity index 51% rename from Content/Ingredients/DamageProjectile/BP_Trap_Dart.uasset rename to Content/Mechanisms/Cannon/BP_Mechanism_Cannon.uasset index f31d2f0..b0f4846 100644 Binary files a/Content/Ingredients/DamageProjectile/BP_Trap_Dart.uasset and b/Content/Mechanisms/Cannon/BP_Mechanism_Cannon.uasset differ diff --git a/Content/Mechanisms/Cannon/BP_Mechanism_Cannon_Projectile.uasset b/Content/Mechanisms/Cannon/BP_Mechanism_Cannon_Projectile.uasset new file mode 100644 index 0000000..36b6395 Binary files /dev/null and b/Content/Mechanisms/Cannon/BP_Mechanism_Cannon_Projectile.uasset differ diff --git a/Content/Mechanisms/Cannon/BP_Trap_Cannon.uasset b/Content/Mechanisms/Cannon/BP_Trap_Cannon.uasset new file mode 100644 index 0000000..5e0b2de Binary files /dev/null and b/Content/Mechanisms/Cannon/BP_Trap_Cannon.uasset differ diff --git a/Content/Ingredients/DamageProjectile/GE_Trap_Dart_Damage.uasset b/Content/Mechanisms/Cannon/GE_Mechanism_Cannon_Damage.uasset similarity index 56% rename from Content/Ingredients/DamageProjectile/GE_Trap_Dart_Damage.uasset rename to Content/Mechanisms/Cannon/GE_Mechanism_Cannon_Damage.uasset index 79af13f..974bd8d 100644 Binary files a/Content/Ingredients/DamageProjectile/GE_Trap_Dart_Damage.uasset and b/Content/Mechanisms/Cannon/GE_Mechanism_Cannon_Damage.uasset differ diff --git a/Content/Mechanisms/DamageArea/BP_DamageArea.uasset b/Content/Mechanisms/DamageArea/BP_DamageArea.uasset new file mode 100644 index 0000000..6b9a038 Binary files /dev/null and b/Content/Mechanisms/DamageArea/BP_DamageArea.uasset differ diff --git a/Content/Mechanisms/DamageArea/GE_DamageArea.uasset b/Content/Mechanisms/DamageArea/GE_DamageArea.uasset new file mode 100644 index 0000000..b2120c1 Binary files /dev/null and b/Content/Mechanisms/DamageArea/GE_DamageArea.uasset differ diff --git a/Content/Ingredients/DamageArea/VFX_DamageArea.uasset b/Content/Mechanisms/DamageArea/VFX_DamageArea.uasset similarity index 94% rename from Content/Ingredients/DamageArea/VFX_DamageArea.uasset rename to Content/Mechanisms/DamageArea/VFX_DamageArea.uasset index 89c1854..5eaf6ed 100644 Binary files a/Content/Ingredients/DamageArea/VFX_DamageArea.uasset and b/Content/Mechanisms/DamageArea/VFX_DamageArea.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Default/2/ZP/ZFTVD1X629VL0RB90NJ1OK.uasset b/Content/__ExternalActors__/Maps/L_Default/2/ZP/ZFTVD1X629VL0RB90NJ1OK.uasset index 13667d2..6359990 100644 Binary files a/Content/__ExternalActors__/Maps/L_Default/2/ZP/ZFTVD1X629VL0RB90NJ1OK.uasset and b/Content/__ExternalActors__/Maps/L_Default/2/ZP/ZFTVD1X629VL0RB90NJ1OK.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Default/4/98/HCM4KXTG2Y2G1I0BTX2UNY.uasset b/Content/__ExternalActors__/Maps/L_Default/4/98/HCM4KXTG2Y2G1I0BTX2UNY.uasset new file mode 100644 index 0000000..4052957 Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Default/4/98/HCM4KXTG2Y2G1I0BTX2UNY.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Default/5/88/NDHUEK1ROBM2RCW7ZU51MM.uasset b/Content/__ExternalActors__/Maps/L_Default/5/88/NDHUEK1ROBM2RCW7ZU51MM.uasset index fd119e6..a777a24 100644 Binary files a/Content/__ExternalActors__/Maps/L_Default/5/88/NDHUEK1ROBM2RCW7ZU51MM.uasset and b/Content/__ExternalActors__/Maps/L_Default/5/88/NDHUEK1ROBM2RCW7ZU51MM.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Default/7/Z0/GPP630NNTJ7N1E8B7TBGS5.uasset b/Content/__ExternalActors__/Maps/L_Default/7/Z0/GPP630NNTJ7N1E8B7TBGS5.uasset deleted file mode 100644 index 9c40f1b..0000000 Binary files a/Content/__ExternalActors__/Maps/L_Default/7/Z0/GPP630NNTJ7N1E8B7TBGS5.uasset and /dev/null differ diff --git a/Content/__ExternalActors__/Maps/L_Default/8/EO/J2O30Y8BP1IJGKNHYD8SUY.uasset b/Content/__ExternalActors__/Maps/L_Default/8/EO/J2O30Y8BP1IJGKNHYD8SUY.uasset index f84502e..a7c2a29 100644 Binary files a/Content/__ExternalActors__/Maps/L_Default/8/EO/J2O30Y8BP1IJGKNHYD8SUY.uasset and b/Content/__ExternalActors__/Maps/L_Default/8/EO/J2O30Y8BP1IJGKNHYD8SUY.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Default/E/HA/CXMK7W9FIGA0C2MR0GYXOO.uasset b/Content/__ExternalActors__/Maps/L_Default/E/HA/CXMK7W9FIGA0C2MR0GYXOO.uasset new file mode 100644 index 0000000..63f308a Binary files /dev/null and b/Content/__ExternalActors__/Maps/L_Default/E/HA/CXMK7W9FIGA0C2MR0GYXOO.uasset differ diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Plots.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Plots.cpp index 5030fb5..7f61af6 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Plots.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Plots.cpp @@ -383,7 +383,7 @@ void FCogEngineWindow_Plots::RenderContent() if (Entry.FindValue(ImPlot::GetPlotMousePos().x, Value)) { ImGui::BeginTooltip(); - ImGui::Text("%s: %0.1f", Label.Get(), Value); + ImGui::Text("%s: %0.2f", Label.Get(), Value); ImGui::EndTooltip(); } } diff --git a/Source/CogSample/CogSampleCharacter.cpp b/Source/CogSample/CogSampleCharacter.cpp index eef9ec9..1ea0ecf 100644 --- a/Source/CogSample/CogSampleCharacter.cpp +++ b/Source/CogSample/CogSampleCharacter.cpp @@ -87,7 +87,6 @@ void ACogSampleCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleCharacter, ActiveAbilityHandles, Params); } - //-------------------------------------------------------------------------------------------------------------------------- void ACogSampleCharacter::PostInitializeComponents() { diff --git a/Source/CogSample/CogSampleFunctionLibrary_Gameplay.h b/Source/CogSample/CogSampleFunctionLibrary_Gameplay.h index 096f539..22d633d 100644 --- a/Source/CogSample/CogSampleFunctionLibrary_Gameplay.h +++ b/Source/CogSample/CogSampleFunctionLibrary_Gameplay.h @@ -107,4 +107,7 @@ public: static bool IsActorMatchingTags(const AActor* Actor, const FGameplayTagContainer& RequiredTags, const FGameplayTagContainer& IgnoredTags); static void MakeOutgoingSpecs(const AActor* Actor, const TArray>& Effects, const TArray& BakedEffects, TMap, FGameplayEffectSpecHandle>& Result); + + static APlayerController* GetFirstLocalPlayerController(UObject* WorldContextObject); + }; diff --git a/Source/CogSample/CogSampleGameState.cpp b/Source/CogSample/CogSampleGameState.cpp index 5d3b1c6..c24bb30 100644 --- a/Source/CogSample/CogSampleGameState.cpp +++ b/Source/CogSample/CogSampleGameState.cpp @@ -102,6 +102,11 @@ void ACogSampleGameState::Tick(float DeltaSeconds) FCogDebugPlot::PlotValue(this, "Frame Rate", GAverageFPS); FCogDebugPlot::PlotValue(this, "Frame Time", GAverageMS); + //const float LocalWorldTime = GetWorld()->GetTimeSeconds(); + //const float ServerWorldTime = GetServerWorldTimeSeconds(); + //const float ServerWorldTimeDelta = LocalWorldTime - ServerWorldTime; + //FCogDebugPlot::PlotValue(this, "Server World Time Delta", ServerWorldTimeDelta); + CogWindowManager->Tick(DeltaSeconds); #endif //ENABLE_COG diff --git a/Source/CogSample/CogSamplePlayerController.cpp b/Source/CogSample/CogSamplePlayerController.cpp index 5a4abc8..ab9c779 100644 --- a/Source/CogSample/CogSamplePlayerController.cpp +++ b/Source/CogSample/CogSamplePlayerController.cpp @@ -11,6 +11,7 @@ #if ENABLE_COG #include "CogAbilityReplicator.h" #include "CogDebugDraw.h" +#include "CogDebugPlot.h" #include "CogDebugReplicator.h" #include "CogEngineReplicator.h" #endif //ENABLE_COG @@ -202,3 +203,29 @@ void ACogSamplePlayerController::Server_SetTarget_Implementation(AActor* Value) { Target = Value; } + +//-------------------------------------------------------------------------------------------------------------------------- +const ACogSamplePlayerController* ACogSamplePlayerController::GetFirstLocalPlayerController(UObject* WorldContextObject) +{ + UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); + if (World == nullptr) + { + return nullptr; + } + + UGameInstance* const GameInstance = World->GetGameInstance(); + if (GameInstance == nullptr) + { + return nullptr; + } + + ACogSamplePlayerController* PlayerController = Cast(GameInstance->GetFirstLocalPlayerController(World)); + return PlayerController; +} + +//-------------------------------------------------------------------------------------------------------------------------- +float ACogSamplePlayerController::GetClientLag() const +{ + return (PlayerState != nullptr && GetNetMode() != NM_Standalone) ? (0.0001f * 0.5f * PlayerState->ExactPing) : 0.f; +} + diff --git a/Source/CogSample/CogSamplePlayerController.h b/Source/CogSample/CogSamplePlayerController.h index c8e2fb4..a4be124 100644 --- a/Source/CogSample/CogSamplePlayerController.h +++ b/Source/CogSample/CogSamplePlayerController.h @@ -25,12 +25,16 @@ class ACogSamplePlayerController public: + static const ACogSamplePlayerController* GetFirstLocalPlayerController(UObject* WorldContextObject); + ACogSamplePlayerController(); virtual void BeginPlay() override; virtual void Tick(float DeltaSeconds) override; + float GetClientLag() const; + //---------------------------------------------------------------------------------------------------------------------- // Possession //---------------------------------------------------------------------------------------------------------------------- diff --git a/Source/CogSample/CogSampleProjectileComponent.cpp b/Source/CogSample/CogSampleProjectileComponent.cpp index 58223ba..dcea728 100644 --- a/Source/CogSample/CogSampleProjectileComponent.cpp +++ b/Source/CogSample/CogSampleProjectileComponent.cpp @@ -6,12 +6,74 @@ #include "CogSampleFunctionLibrary_Gameplay.h" #include "CogSampleFunctionLibrary_Team.h" #include "CogSampleLogCategories.h" +#include "CogSamplePlayerController.h" +#include "GameFramework/Character.h" +#include "Net/Core/PushModel/PushModel.h" +#include "Net/UnrealNetwork.h" #if ENABLE_COG #include "CogDebugLog.h" #include "CogDebugDraw.h" #endif //ENABLE_COG +//-------------------------------------------------------------------------------------------------------------------------- +// Postulates: +//-------------------------------------------------------------------------------------------------------------------------- +// +// Projectiles can be launched by a Player or a NPC. +// Projectiles can hit the world, or another player, or a NPC. +// When hitting characters, projectiles do not hit the characters' capsules, but their animated hit boxes. +// The server do not update animations and therefore do not update animated hit boxes(like Fortnite) +// The server applies the gameplay effects related to projectile hit. +// +//-------------------------------------------------------------------------------------------------------------------------- +// Questions/Answers: +//-------------------------------------------------------------------------------------------------------------------------- +// +// Where should projectile collision happen ? On the server, or on the client ? +// +// On the clients.If projectiles should hit animated hit boxes, and if hit boxes are not updated on the server, +// then we need to rely on the clients to perform the collision detection.Clients should send the hit result to the +// server, the server should verify if the result is valid(anti cheat), and then apply gameplay effects. +// +// If the projectile is launched by a NPC and hit a player, which client should send the hit result to the server ? +// The client that got hit, or another client that also detected the hit ? +// +// +// +// If the projectile is launched by a player and hit another player, which client should detect and send the hit result +// to the server ? The player that launched the projectile or/ and the player that got hit ? +// +// If the server only receives the hit from the client that got hit, then that client can prevent this message +// from being sent, or he can alter the message to gain advantages. The server needs another information. +// This information can come from the launcher of the projectile. +// +// If the projectile is launched by a NPC and hit another NPC, which client should send the hit result to the server ? +// +// One client could be made responsible to detect hits received by a specific NPC. +// +//-------------------------------------------------------------------------------------------------------------------------- +UCogSampleProjectileComponent::UCogSampleProjectileComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SetIsReplicatedByDefault(true); + bAutoActivate = false; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSampleProjectileComponent::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + FDoRepLifetimeParams Params; + Params.bIsPushBased = true; + + Params.Condition = COND_None; + DOREPLIFETIME_WITH_PARAMS_FAST(UCogSampleProjectileComponent, ServerSpawnLocation, Params); + DOREPLIFETIME_WITH_PARAMS_FAST(UCogSampleProjectileComponent, ServerSpawnRotation, Params); + DOREPLIFETIME_WITH_PARAMS_FAST(UCogSampleProjectileComponent, ServerSpawnVelocity, Params); +} + //-------------------------------------------------------------------------------------------------------------------------- void UCogSampleProjectileComponent::BeginPlay() { @@ -20,10 +82,7 @@ void UCogSampleProjectileComponent::BeginPlay() Creator = UCogSampleFunctionLibrary_Gameplay::GetCreator(GetOwner()); SpawnPrediction = GetOwner()->FindComponentByClass(); - if (GetOwner()->HasAuthority()) - { - RegisterAllEffects(); - } + RegisterAllEffects(); Collision = Cast(CollisionReference.GetComponent(GetOwner())); if (Collision != nullptr) @@ -37,14 +96,59 @@ void UCogSampleProjectileComponent::BeginPlay() AssistanceOverlap->OnComponentBeginOverlap.AddDynamic(this, &UCogSampleProjectileComponent::OnAssistanceOverlapBegin); } + if (GetOwner()->GetLocalRole() != ROLE_Authority) + { + Activate(false); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSampleProjectileComponent::Activate(bool bReset) +{ + + //------------------------------------------------------------------------------------------------ + // Save the spawn location and rotation and get them replicated because, we want remote clients + // to tick projectiles on their own, and be synced with the server. To do so they need to + // recompute (to catchup) the projectile movement from its initial location, rotation and velocity. + // If we don't reposition the remote client projectile at its initial values, we get some offset + // because the server doesn't necessarly replicates the location and rotation of the projectile + // at its spawn frame. + //------------------------------------------------------------------------------------------------ + if (GetOwner()->GetLocalRole() == ROLE_Authority) + { + COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(UCogSampleProjectileComponent, ServerSpawnLocation, GetOwner()->GetActorLocation(), this); + COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(UCogSampleProjectileComponent, ServerSpawnRotation, GetOwner()->GetActorRotation(), this); + COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(UCogSampleProjectileComponent, ServerSpawnVelocity, Velocity, this); + } + else + { + GetOwner()->SetActorLocationAndRotation(ServerSpawnLocation, ServerSpawnRotation); + Velocity = ServerSpawnVelocity; + } + + Super::Activate(bReset); + #if ENABLE_COG + DrawDebugCurrentState(FColor::Green); if (FCogDebugLog::IsLogCategoryActive(LogCogProjectile)) { LastDebugLocation = GetOwner()->GetActorLocation(); } #endif //ENABLE_COG -} + //-------------------------------------------------------------------------- + // Catchup after settings LastDebugLocation because Tick will be triggered + // by Catchup and LastDebugLocation is used in Tick debug draw. + //-------------------------------------------------------------------------- + if (GetOwner()->GetLocalRole() != ROLE_Authority) + { + if (const ACogSamplePlayerController* Controller = ACogSamplePlayerController::GetFirstLocalPlayerController(this)) + { + Catchup(Controller->GetClientLag()); + } + } + +} //-------------------------------------------------------------------------------------------------------------------------- void UCogSampleProjectileComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) @@ -68,8 +172,8 @@ void UCogSampleProjectileComponent::TickComponent(float DeltaTime, enum ELevelTi 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; + const FColor Color = (SpawnPrediction != nullptr ? SpawnPrediction->GetRoleColor() : FColor(128, 128, 128, 255)).WithAlpha(IsCatchingUp ? 100 : 255); if (Show && UpdatedComponent != nullptr) { @@ -99,28 +203,39 @@ void UCogSampleProjectileComponent::TickComponent(float DeltaTime, enum ELevelTi #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::Catchup(float CatchupDuration) +{ + COG_LOG_OBJECT(LogCogProjectile, ELogVerbosity::Verbose, Creator.Get(), TEXT("Projectile:%s - Role:%s - CatchupDuration:%0.2f"), *GetName(), *GetRoleName(), CatchupDuration); + + IsCatchingUp = true; + TickComponent(CatchupDuration, LEVELTICK_All, nullptr); + IsCatchingUp = false; + +#if ENABLE_COG + DrawDebugCurrentState(FColor::Red); +#endif //ENABLE_COG +} + + +//-------------------------------------------------------------------------------------------------------------------------- +#if ENABLE_COG + +void UCogSampleProjectileComponent::DrawDebugCurrentState(const FColor& Color, bool DrawVelocity) +{ + if (FCogDebugLog::IsLogCategoryActive(LogCogProjectile)) + { + float CollisionRadius = Collision != nullptr ? Collision->GetScaledSphereRadius() : 0.0f; + float AssistanceRadius = AssistanceOverlap != nullptr ? AssistanceOverlap->GetScaledSphereRadius() : 0.0f; + float DebugRadius = FMath::Max(CollisionRadius, AssistanceRadius); + FCogDebugDraw::Sphere(LogCogProjectile, GetOwner(), GetOwner()->GetActorLocation(), DebugRadius, Color, true, 0); + + if (DrawVelocity) + { + FCogDebugDraw::Arrow(LogCogProjectile, GetOwner(), GetOwner()->GetActorLocation(), GetOwner()->GetActorLocation() + Velocity * 0.1f, Color, true, 0); + } + } +} +#endif //ENABLE_COG //-------------------------------------------------------------------------------------------------------------------------- void UCogSampleProjectileComponent::RegisterAllEffects() @@ -181,16 +296,6 @@ bool UCogSampleProjectileComponent::ShouldProcessOverlap(AActor* OtherActor, UPr 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")); @@ -369,15 +474,24 @@ bool UCogSampleProjectileComponent::ShouldHit_Implementation(const FHitResult& H } //-------------------------------------------------------------------------------------------------------------------------- -void UCogSampleProjectileComponent::Hit_Implementation(const FHitResult& HitResult, FCogSampleHitConsequence& hitConsequence) +void UCogSampleProjectileComponent::Hit_Implementation(const FHitResult& HitResult, FCogSampleHitConsequence& HitConsequence) { AActor* HitActor = HitResult.GetActor(); #if ENABLE_COG + DrawDebugCurrentState(FColor::White, false); 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); + FCogDebugDraw::Arrow(LogCogProjectile, GetOwner(), HitResult.ImpactPoint, HitResult.ImpactPoint + HitResult.ImpactNormal * 50.0f, FColor::Yellow, true, 0); + FCogDebugDraw::Box(LogCogProjectile, GetOwner(), HitResult.ImpactPoint, FVector(0.0f, 5.0f, 5.0f), FRotationMatrix::MakeFromX(HitResult.ImpactNormal).ToQuat(), FColor::Yellow, true, 0); #endif //ENABLE_COG + UAbilitySystemComponent* TargetAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(HitActor); + if (TargetAbilitySystem == nullptr) + { + return; + } + for (const FCogSampleProjectileEffectConfig& EffectConfig : Effects) { for (TSubclassOf EffectClass : EffectConfig.Effects) @@ -404,12 +518,6 @@ void UCogSampleProjectileComponent::Hit_Implementation(const FHitResult& HitResu continue; } - UAbilitySystemComponent* TargetAbilitySystem = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(HitActor); - if (TargetAbilitySystem == nullptr) - { - continue; - } - Spec->GetContext().AddHitResult(HitResult, true); TargetAbilitySystem->ApplyGameplayEffectSpecToSelf(*Spec); } diff --git a/Source/CogSample/CogSampleProjectileComponent.h b/Source/CogSample/CogSampleProjectileComponent.h index 3a7f25a..c4d5448 100644 --- a/Source/CogSample/CogSampleProjectileComponent.h +++ b/Source/CogSample/CogSampleProjectileComponent.h @@ -7,8 +7,6 @@ #include "GameplayEffect.h" #include "CogSampleProjectileComponent.generated.h" -//-------------------------------------------------------------------------------------------------------------------------- -// FCogSampleProjectileEffectConfig //-------------------------------------------------------------------------------------------------------------------------- USTRUCT(BlueprintType) struct FCogSampleProjectileEffectConfig @@ -25,8 +23,6 @@ struct FCogSampleProjectileEffectConfig TArray> Effects; }; -//-------------------------------------------------------------------------------------------------------------------------- -// FCogSampleHitConsequence //-------------------------------------------------------------------------------------------------------------------------- USTRUCT(BlueprintType) struct FCogSampleHitConsequence @@ -43,8 +39,6 @@ struct FCogSampleHitConsequence bool HideOnStop = false; }; -//-------------------------------------------------------------------------------------------------------------------------- -// UCogSampleProjectileComponent //-------------------------------------------------------------------------------------------------------------------------- UCLASS(BlueprintType, meta = (BlueprintSpawnableComponent)) class UCogSampleProjectileComponent : public UProjectileMovementComponent @@ -53,10 +47,16 @@ class UCogSampleProjectileComponent : public UProjectileMovementComponent public: + UCogSampleProjectileComponent(const FObjectInitializer& ObjectInitializer); + + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + virtual void BeginPlay() override; virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction); + virtual void Activate(bool bReset) override; + UFUNCTION(BlueprintCallable) void ClearHitActors(); @@ -70,7 +70,7 @@ protected: virtual FString GetRoleName() const; - //virtual void CatchupReplicatedActor(float CatchupDuration); + virtual void Catchup(float CatchupDuration); virtual bool ShouldProcessOverlap(AActor* OtherActor, UPrimitiveComponent* OtherComp, bool RequireValidActor); @@ -91,11 +91,11 @@ protected: void RegisterAllEffects(); - UPROPERTY(EditAnywhere) + UPROPERTY(EditAnywhere, Category = "Projectile") FComponentReference CollisionReference; - UPROPERTY(EditAnywhere) - FComponentReference OverlapReference; + UPROPERTY(EditAnywhere, Category = "Projectile") + FComponentReference OverlapReference; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Projectile") bool CanHitCreator = false; @@ -114,6 +114,15 @@ protected: UPROPERTY() TWeakObjectPtr SpawnPrediction = nullptr; + UPROPERTY(Replicated) + FVector ServerSpawnLocation = FVector::ZeroVector; + + UPROPERTY(Replicated) + FRotator ServerSpawnRotation = FRotator::ZeroRotator; + + UPROPERTY(Replicated) + FVector ServerSpawnVelocity = FVector::ZeroVector; + /** Re-entrancy guard */ bool IsAlreadyProcessingAnOverlap = false; @@ -122,7 +131,13 @@ protected: TMap, FGameplayEffectSpecHandle> EffectsMap; + float SpawnTime = 0.0f; + + bool IsCatchingUp = false; + #if ENABLE_COG + void DrawDebugCurrentState(const FColor& Color, bool DrawVelocity = true); + FVector LastDebugLocation = FVector::ZeroVector; #endif //ENABLE_COG }; \ No newline at end of file diff --git a/TODO.txt b/TODO.txt index a5057fe..727bf48 100644 --- a/TODO.txt +++ b/TODO.txt @@ -10,6 +10,7 @@ - CogEngine: Add screen settings (fullscreen, borderless, window and resolution) - CogEngine: make a better widget for CheckBoxState for input shortcuts - CogEngine: save active log categories +- CogEngine: add menu on the PlotWindow wih the controls - CogSample: Add a custom window in sample (changing the character faction) - CogSample: Create more abilities @@ -19,5 +20,6 @@ - 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. +- CogDebug: Rework Tickness and Duration params. - CogInput: Add gamepad stick drag to set their values \ No newline at end of file