blaster/Source/Blaster/Components/LagCompensationComponent.cpp

158 lines
4.5 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "LagCompensationComponent.h"
#include "Components/BoxComponent.h"
ULagCompensationComponent::ULagCompensationComponent()
{
PrimaryComponentTick.bCanEverTick = true;
}
void ULagCompensationComponent::BeginPlay()
{
Super::BeginPlay();
}
void ULagCompensationComponent::SaveFramePackage(FFramePackage& Package)
{
Character = Character == nullptr ? Cast<ABlasterCharacter>(GetOwner()) : Character;
if (Character)
{
Package.Time = GetWorld()->GetTimeSeconds();
for (auto& BoxPair : Character->HitCollisionBoxes)
{
FBoxInformation BoxInformation;
BoxInformation.Location = BoxPair.Value->GetComponentLocation();
BoxInformation.Rotation = BoxPair.Value->GetComponentRotation();
BoxInformation.BoxExtend = BoxPair.Value->GetScaledBoxExtent();
Package.HitBoxInfo.Add(BoxPair.Key, BoxInformation);
}
}
}
FFramePackage ULagCompensationComponent::InterpBetweenFrames(const FFramePackage& OlderFrame, const FFramePackage& YoungerFrame, float HitTime)
{
const float Distance = YoungerFrame.Time - OlderFrame.Time;
const float InterpFraction = FMath::Clamp((HitTime - OlderFrame.Time) / Distance, 0.f, 1.f);
FFramePackage InterpFramePackage;
InterpFramePackage.Time = HitTime;
for (auto& YoungerPair : YoungerFrame.HitBoxInfo)
{
const FName& BoxInfoName = YoungerPair.Key;
const FBoxInformation& OlderBox = OlderFrame.HitBoxInfo[BoxInfoName];
const FBoxInformation& YoungerBox = YoungerFrame.HitBoxInfo[BoxInfoName];
FBoxInformation InterpBoxInfo;
InterpBoxInfo.Location = FMath::VInterpTo(OlderBox.Location, YoungerBox.Location, 1.f, InterpFraction);
InterpBoxInfo.Rotation = FMath::RInterpTo(OlderBox.Rotation, YoungerBox.Rotation, 1.f, InterpFraction);
InterpBoxInfo.BoxExtend = OlderBox.BoxExtend;
InterpFramePackage.HitBoxInfo.Add(BoxInfoName, InterpBoxInfo);
}
return InterpFramePackage;
}
void ULagCompensationComponent::ShowFramePackage(const FFramePackage& Package, const FColor Color)
{
for (auto& BoxInfo : Package.HitBoxInfo)
{
DrawDebugBox(
GetWorld(),
BoxInfo.Value.Location,
BoxInfo.Value.BoxExtend,
FQuat(BoxInfo.Value.Rotation),
Color,
false,
4.f
);
}
}
void ULagCompensationComponent::ServerSideRewind(ABlasterCharacter* HitCharacter, const FVector_NetQuantize& TraceStart, const FVector_NetQuantize& HitLocation,
float HitTime)
{
bool bReturn = HitCharacter == nullptr ||
HitCharacter->GetLagCompensation() == nullptr ||
HitCharacter->GetLagCompensation()->FrameHistory.GetHead() == nullptr ||
HitCharacter->GetLagCompensation()->FrameHistory.GetTail() == nullptr;
if (bReturn) return;
// Frame package that we check to verify a hit
FFramePackage FrameToSheck;
bool bShouldInterpolate = true;
const TDoubleLinkedList<FFramePackage>& History = HitCharacter->GetLagCompensation()->FrameHistory;
const float OldestHistoryTime = History.GetTail()->GetValue().Time;
const float NewestHistoryTime = History.GetHead()->GetValue().Time;
if (OldestHistoryTime > HitTime)
{
// Too far back, too laggy to do SSR
return;
}
if (OldestHistoryTime == HitTime)
{
FrameToSheck = History.GetTail()->GetValue();
bShouldInterpolate = false;
}
if (NewestHistoryTime <= HitTime)
{
FrameToSheck = History.GetHead()->GetValue();
bShouldInterpolate = false;
}
auto Younger = History.GetHead();
auto Older = History.GetHead();
while (Older->GetValue().Time > HitTime)
{
if (Older->GetNextNode() == nullptr) break;
Older = Older->GetNextNode();
if (Older->GetValue().Time > HitTime)
{
Younger = Older;
}
}
if (Older->GetValue().Time == HitTime)
{
FrameToSheck = Older->GetValue();
bShouldInterpolate = false;
}
if (bShouldInterpolate) // Why not just check if FrameToCheck == nullptr?
{
// Interpolate between Younger and Older
}
}
void ULagCompensationComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (FrameHistory.Num() <= 1)
{
FFramePackage ThisFrame;
SaveFramePackage(ThisFrame);
FrameHistory.AddHead(ThisFrame);
}
else
{
float HistoryLength = FrameHistory.GetHead()->GetValue().Time - FrameHistory.GetTail()->GetValue().Time;
while (HistoryLength > MaxRecordTime)
{
FrameHistory.RemoveNode(FrameHistory.GetTail());
HistoryLength = FrameHistory.GetHead()->GetValue().Time - FrameHistory.GetTail()->GetValue().Time;
}
FFramePackage ThisFrame;
SaveFramePackage(ThisFrame);
FrameHistory.AddHead(ThisFrame);
ShowFramePackage(ThisFrame, FColor::Red);
}
}