Files
UnrealEngine/Engine/Source/Runtime/PacketHandlers/ReliabilityHandlerComponent/Private/ReliabilityHandlerComponent.cpp
2025-05-18 13:04:45 +08:00

180 lines
4.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ReliabilityHandlerComponent.h"
#include "Modules/ModuleManager.h"
#include "Net/Core/Misc/PacketAudit.h"
#include "HAL/PlatformTime.h"
IMPLEMENT_MODULE(FReliabilityHandlerComponentModuleInterface, ReliabilityHandlerComponent);
// RELIABILITY
ReliabilityHandlerComponent::ReliabilityHandlerComponent()
: HandlerComponent(FName(TEXT("ReliabilityHandlerComponent")))
, LocalPacketID(1)
, LocalPacketIDACKED(0)
, RemotePacketID(0)
, RemotePacketIDACKED(0)
, ResendResolutionTime(0.1)
, LastResendTime(0.0)
{
}
void ReliabilityHandlerComponent::CountBytes(FArchive& Ar) const
{
HandlerComponent::CountBytes(Ar);
const SIZE_T SizeOfThis = sizeof(*this) - sizeof(HandlerComponent);
Ar.CountBytes(SizeOfThis, SizeOfThis);
BufferedPackets.CountBytes(Ar);
for (BufferedPacket const * const LocalPacket : BufferedPackets)
{
if (LocalPacket)
{
LocalPacket->CountBytes(Ar);
}
}
}
void ReliabilityHandlerComponent::Initialize()
{
SetActive(true);
Initialized();
State = UE::Handler::Component::State::Initialized;
}
bool ReliabilityHandlerComponent::IsValid() const
{
return true;
}
void ReliabilityHandlerComponent::Outgoing(FBitWriter& Packet, FOutPacketTraits& Traits)
{
switch (State)
{
case UE::Handler::Component::State::Initialized:
{
check(IsActive() && IsValid());
FBitWriter Local;
Local.AllowAppend(true);
Local.SetAllowResize(true);
check(Packet.GetNumBytes() > 0);
Local.SerializeIntPacked(RemotePacketID);
Local.SerializeIntPacked(LocalPacketID);
Local.SerializeBits(Packet.GetData(), Packet.GetNumBits());
Packet = Local;
FPacketAudit::AddStage(TEXT("PostReliability"), Packet);
break;
}
default:
{
break;
}
}
}
void ReliabilityHandlerComponent::Incoming(FBitReader& Packet)
{
switch (State)
{
case UE::Handler::Component::State::Initialized:
{
if (IsActive() && IsValid())
{
FPacketAudit::CheckStage(TEXT("PostReliability"), Packet);
// Read ACK
uint32 IncomingLocalPacketIDACK;
Packet.SerializeIntPacked(IncomingLocalPacketIDACK);
// Read Remote ID
uint32 IncomingRemotePacketID;
Packet.SerializeIntPacked(IncomingRemotePacketID);
// Out of sequence or duplicate packet, ignore
if (RemotePacketID + 1 != IncomingRemotePacketID)
{
Packet.SetData(nullptr, 0);
return;
}
// Set latest ID
RemotePacketID = IncomingRemotePacketID;
check(IncomingLocalPacketIDACK >= LocalPacketIDACKED);
// We don't record the latest ACK unless this packet is in-order, since we can't trust the ACK without further modifications
LocalPacketIDACKED = IncomingLocalPacketIDACK;
// Do not realign the remaining packet here, let the PacketHandler do that.
// Previous code from here, had a bug that added an extra byte in some circumstances.
}
break;
}
default:
{
break;
}
}
}
void ReliabilityHandlerComponent::Tick(float DeltaTime)
{
const double CurrentTime = FPlatformTime::Seconds();
if (CurrentTime - LastResendTime < ResendResolutionTime)
{
return;
}
LastResendTime = CurrentTime;
// Resend UNACKED packets
// We resend all packets just to make sure
// This is very inefficient and wastes bandwidth, we will want to implement NAK version at some point
for (int i = 0; i < BufferedPackets.Num(); i++)
{
BufferedPacket* Packet = BufferedPackets[i];
check(Packet->Id >= 1);
if (LocalPacketIDACKED < Packet->Id)
{
// Send this as a raw packet, since it's already been processed
Handler->QueuePacketForRawSending(Packet);
}
else
{
// This packet was ACK'd, we can remove
check(i == 0);
BufferedPackets.RemoveAt(i);
i--;
delete Packet;
}
}
}
void ReliabilityHandlerComponent::QueuePacketForResending(uint8* Packet, int32 CountBits, FOutPacketTraits& Traits)
{
BufferedPackets.Add(new BufferedPacket(Packet, CountBits, Traits, FPlatformTime::Seconds() + ResendResolutionTime, LocalPacketID++));
}
int32 ReliabilityHandlerComponent::GetReservedPacketBits() const
{
return 64;
}
// MODULE INTERFACE
TSharedPtr<HandlerComponent> FReliabilityHandlerComponentModuleInterface::CreateComponentInstance(FString& Options)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
return MakeShareable(new ReliabilityHandlerComponent);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}