188 - Confirming the Hit
This commit is contained in:
parent
650b206797
commit
c455d1655d
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue