188 - Confirming the Hit

This commit is contained in:
Kingsmedia 2022-05-27 17:42:34 +02:00
parent 650b206797
commit c455d1655d
2 changed files with 149 additions and 9 deletions

View File

@ -59,6 +59,119 @@ FFramePackage ULagCompensationComponent::InterpBetweenFrames(const FFramePackage
return InterpFramePackage; return InterpFramePackage;
} }
FServerSideRewindResult ULagCompensationComponent::ConfirmHit(const FFramePackage& Package, ABlasterCharacter* HitCharacter,
const FVector_NetQuantize& TraceStart, const FVector_NetQuantize HitLocation)
{
if (HitCharacter == nullptr) return FServerSideRewindResult();
FFramePackage CurrentFrame;
CacheBoxPositions(HitCharacter, CurrentFrame);
MoveBoxes(HitCharacter, Package);
EnableCharacterMeshCollision(HitCharacter, ECollisionEnabled::NoCollision);
// Enable collision for the head first
UBoxComponent* HeadBox = HitCharacter->HitCollisionBoxes[FName("head")];
HeadBox->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
HeadBox->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
FHitResult ConfirmHitResult;
const FVector TraceEnd = TraceStart + (HitLocation - TraceStart) * 1.25f;
UWorld* World = GetWorld();
if (World)
{
World->LineTraceSingleByChannel(
ConfirmHitResult,
TraceStart,
TraceEnd,
ECC_Visibility
);
if (ConfirmHitResult.bBlockingHit) // we hit the head, return early
{
ResetHitBoxes(HitCharacter, CurrentFrame);
EnableCharacterMeshCollision(HitCharacter, ECollisionEnabled::QueryAndPhysics);
return FServerSideRewindResult{ true, true };
}
// Didn't hit the head, check the rest of the boxes
for (auto& HitBoxPair : HitCharacter->HitCollisionBoxes)
{
if (HitBoxPair.Value != nullptr)
{
HitBoxPair.Value->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
HitBoxPair.Value->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
}
}
World->LineTraceSingleByChannel(
ConfirmHitResult,
TraceStart,
TraceEnd,
ECC_Visibility
);
if (ConfirmHitResult.bBlockingHit)
{
ResetHitBoxes(HitCharacter, CurrentFrame);
EnableCharacterMeshCollision(HitCharacter, ECollisionEnabled::QueryAndPhysics);
return FServerSideRewindResult{ true, false };
}
ResetHitBoxes(HitCharacter, CurrentFrame);
EnableCharacterMeshCollision(HitCharacter, ECollisionEnabled::QueryAndPhysics);
return FServerSideRewindResult{ false, false };
}
}
void ULagCompensationComponent::CacheBoxPositions(ABlasterCharacter* HitCharacter, FFramePackage& OutFramePackage)
{
if (HitCharacter == nullptr) return;
for (auto& HitBoxPair : HitCharacter->HitCollisionBoxes)
{
if (HitBoxPair.Value != nullptr)
{
FBoxInformation BoxInfo;
BoxInfo.Location = HitBoxPair.Value->GetComponentLocation();
BoxInfo.Rotation = HitBoxPair.Value->GetComponentRotation();
BoxInfo.BoxExtend = HitBoxPair.Value->GetScaledBoxExtent();
OutFramePackage.HitBoxInfo.Add(HitBoxPair.Key, BoxInfo);
}
}
}
void ULagCompensationComponent::MoveBoxes(ABlasterCharacter* HitCharacter, const FFramePackage& Package)
{
if (HitCharacter == nullptr) return;
for (auto& HitBoxPair : HitCharacter->HitCollisionBoxes)
{
if (HitBoxPair.Value != nullptr)
{
HitBoxPair.Value->SetWorldLocation(Package.HitBoxInfo[HitBoxPair.Key].Location);
HitBoxPair.Value->SetWorldRotation(Package.HitBoxInfo[HitBoxPair.Key].Rotation);
HitBoxPair.Value->SetBoxExtent(Package.HitBoxInfo[HitBoxPair.Key].BoxExtend);
}
}
}
void ULagCompensationComponent::ResetHitBoxes(ABlasterCharacter* HitCharacter, const FFramePackage& Package)
{
if (HitCharacter == nullptr) return;
for (auto& HitBoxPair : HitCharacter->HitCollisionBoxes)
{
if (HitBoxPair.Value != nullptr)
{
HitBoxPair.Value->SetWorldLocation(Package.HitBoxInfo[HitBoxPair.Key].Location);
HitBoxPair.Value->SetWorldRotation(Package.HitBoxInfo[HitBoxPair.Key].Rotation);
HitBoxPair.Value->SetBoxExtent(Package.HitBoxInfo[HitBoxPair.Key].BoxExtend);
HitBoxPair.Value->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
}
}
void ULagCompensationComponent::ShowFramePackage(const FFramePackage& Package, const FColor Color) void ULagCompensationComponent::ShowFramePackage(const FFramePackage& Package, const FColor Color)
{ {
for (auto& BoxInfo : Package.HitBoxInfo) for (auto& BoxInfo : Package.HitBoxInfo)
@ -75,7 +188,7 @@ void ULagCompensationComponent::ShowFramePackage(const FFramePackage& Package, c
} }
} }
void ULagCompensationComponent::ServerSideRewind(ABlasterCharacter* HitCharacter, const FVector_NetQuantize& TraceStart, const FVector_NetQuantize& HitLocation, FServerSideRewindResult ULagCompensationComponent::ServerSideRewind(ABlasterCharacter* HitCharacter, const FVector_NetQuantize& TraceStart, const FVector_NetQuantize& HitLocation,
float HitTime) float HitTime)
{ {
bool bReturn = HitCharacter == nullptr || bool bReturn = HitCharacter == nullptr ||
@ -83,10 +196,10 @@ void ULagCompensationComponent::ServerSideRewind(ABlasterCharacter* HitCharacter
HitCharacter->GetLagCompensation()->FrameHistory.GetHead() == nullptr || HitCharacter->GetLagCompensation()->FrameHistory.GetHead() == nullptr ||
HitCharacter->GetLagCompensation()->FrameHistory.GetTail() == nullptr; HitCharacter->GetLagCompensation()->FrameHistory.GetTail() == nullptr;
if (bReturn) return; if (bReturn) FServerSideRewindResult();
// Frame package that we check to verify a hit // Frame package that we check to verify a hit
FFramePackage FrameToSheck; FFramePackage FrameToCheck;
bool bShouldInterpolate = true; bool bShouldInterpolate = true;
const TDoubleLinkedList<FFramePackage>& History = HitCharacter->GetLagCompensation()->FrameHistory; const TDoubleLinkedList<FFramePackage>& History = HitCharacter->GetLagCompensation()->FrameHistory;
@ -95,16 +208,16 @@ void ULagCompensationComponent::ServerSideRewind(ABlasterCharacter* HitCharacter
if (OldestHistoryTime > HitTime) if (OldestHistoryTime > HitTime)
{ {
// Too far back, too laggy to do SSR // Too far back, too laggy to do SSR
return; FServerSideRewindResult();
} }
if (OldestHistoryTime == HitTime) if (OldestHistoryTime == HitTime)
{ {
FrameToSheck = History.GetTail()->GetValue(); FrameToCheck = History.GetTail()->GetValue();
bShouldInterpolate = false; bShouldInterpolate = false;
} }
if (NewestHistoryTime <= HitTime) if (NewestHistoryTime <= HitTime)
{ {
FrameToSheck = History.GetHead()->GetValue(); FrameToCheck = History.GetHead()->GetValue();
bShouldInterpolate = false; bShouldInterpolate = false;
} }
auto Younger = History.GetHead(); auto Younger = History.GetHead();
@ -120,13 +233,24 @@ void ULagCompensationComponent::ServerSideRewind(ABlasterCharacter* HitCharacter
} }
if (Older->GetValue().Time == HitTime) if (Older->GetValue().Time == HitTime)
{ {
FrameToSheck = Older->GetValue(); FrameToCheck = Older->GetValue();
bShouldInterpolate = false; bShouldInterpolate = false;
} }
if (bShouldInterpolate) // Why not just check if FrameToCheck == nullptr? if (bShouldInterpolate) // Why not just check if FrameToCheck == nullptr?
{ {
// Interpolate between Younger and Older // Interpolate between Younger and Older
FrameToCheck = InterpBetweenFrames(Older->GetValue(), Younger->GetValue(), HitTime);
}
return ConfirmHit(FrameToCheck, HitCharacter, TraceStart, HitLocation);
}
void ULagCompensationComponent::EnableCharacterMeshCollision(ABlasterCharacter* HitCharacter, ECollisionEnabled::Type CollisionEnabled)
{
if (HitCharacter && HitCharacter->GetMesh())
{
HitCharacter->GetMesh()->SetCollisionEnabled(CollisionEnabled);
} }
} }

View File

@ -33,6 +33,18 @@ struct FFramePackage
TMap<FName, FBoxInformation> HitBoxInfo; TMap<FName, FBoxInformation> HitBoxInfo;
}; };
USTRUCT(BlueprintType)
struct FServerSideRewindResult
{
GENERATED_BODY()
UPROPERTY()
bool bHitConfirmed;
UPROPERTY()
bool bHeadShot;
};
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class BLASTER_API ULagCompensationComponent : public UActorComponent class BLASTER_API ULagCompensationComponent : public UActorComponent
{ {
@ -43,13 +55,17 @@ public:
friend ABlasterCharacter; friend ABlasterCharacter;
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
void ShowFramePackage(const FFramePackage& Package, const FColor Color); void ShowFramePackage(const FFramePackage& Package, const FColor Color);
void ServerSideRewind(class ABlasterCharacter* HitCharacter, const FVector_NetQuantize& TraceStart, const FVector_NetQuantize& HitLocation, float HitTime); FServerSideRewindResult ServerSideRewind(class ABlasterCharacter* HitCharacter, const FVector_NetQuantize& TraceStart, const FVector_NetQuantize& HitLocation, float HitTime);
protected: protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
void SaveFramePackage(FFramePackage& Package); void SaveFramePackage(FFramePackage& Package);
FFramePackage InterpBetweenFrames(const FFramePackage& OlderFrame, const FFramePackage& YoungerFrame, float HitTime); FFramePackage InterpBetweenFrames(const FFramePackage& OlderFrame, const FFramePackage& YoungerFrame, float HitTime);
FServerSideRewindResult ConfirmHit(const FFramePackage& Package, ABlasterCharacter* HitCharacter, const FVector_NetQuantize& TraceStart, const FVector_NetQuantize HitLocation);
void CacheBoxPositions(ABlasterCharacter* HitCharacter, FFramePackage& OutFramePackage);
void MoveBoxes(ABlasterCharacter* HitCharacter, const FFramePackage& Package);
void ResetHitBoxes(ABlasterCharacter* HitCharacter, const FFramePackage& Package);
void EnableCharacterMeshCollision(ABlasterCharacter* HitCharacter, ECollisionEnabled::Type CollisionEnabled);
private: private:
UPROPERTY() UPROPERTY()