#pragma once
#include "CoreMinimal.h"
#include "../fastnet.h"
UENUM(BlueprintType)
enum class EFastNetEventType : uint8
{
None = 0 UMETA(DisplayName = "None"),
Connected = 1 UMETA(DisplayName = "Connected"),
Data = 2 UMETA(DisplayName = "Data"),
Disconnected = 3 UMETA(DisplayName = "Disconnected"),
Error = 4 UMETA(DisplayName = "Error")
};
USTRUCT(BlueprintType)
struct FFastNetEvent
{
GENERATED_BODY()
UPROPERTY(BlueprintReadOnly)
EFastNetEventType Type = EFastNetEventType::None;
UPROPERTY(BlueprintReadOnly)
int32 PeerId = 0;
UPROPERTY(BlueprintReadOnly)
uint8 Channel = 0;
UPROPERTY(BlueprintReadOnly)
TArray<uint8> Data;
UPROPERTY(BlueprintReadOnly)
int32 ErrorCode = 0;
};
class YOURGAME_API FFastNetClient
{
public:
FFastNetClient() : Handle(nullptr) {}
~FFastNetClient()
{
Disconnect();
}
FFastNetClient(const FFastNetClient&) = delete;
FFastNetClient& operator=(const FFastNetClient&) = delete;
FFastNetClient(FFastNetClient&& Other) noexcept : Handle(Other.Handle)
{
Other.Handle = nullptr;
}
FFastNetClient& operator=(FFastNetClient&& Other) noexcept
{
if (this != &Other)
{
Disconnect();
Handle = Other.Handle;
Other.Handle = nullptr;
}
return *this;
}
bool Connect(const FString& Host, uint16 Port)
{
Disconnect();
Handle = fastnet_client_connect(TCHAR_TO_UTF8(*Host), Port);
return Handle != nullptr;
}
void Disconnect()
{
if (Handle)
{
fastnet_client_disconnect(Handle);
Handle = nullptr;
}
}
bool IsConnected() const
{
return Handle != nullptr;
}
bool Send(uint8 Channel, const TArray<uint8>& Data)
{
if (!Handle || Data.Num() == 0) return false;
return fastnet_client_send(Handle, Channel, Data.GetData(), Data.Num()) == 0;
}
bool SendRaw(uint8 Channel, const uint8* Data, uint32 Len)
{
if (!Handle || !Data || Len == 0) return false;
return fastnet_client_send(Handle, Channel, Data, Len) == 0;
}
bool Poll(FFastNetEvent& OutEvent)
{
if (!Handle) return false;
FastNetEvent CEvent;
if (!fastnet_client_poll(Handle, &CEvent)) return false;
OutEvent.Type = static_cast<EFastNetEventType>(CEvent.type);
OutEvent.PeerId = CEvent.peer_id;
OutEvent.Channel = CEvent.channel;
OutEvent.ErrorCode = CEvent.error_code;
if (CEvent.data && CEvent.data_len > 0)
{
OutEvent.Data.SetNumUninitialized(CEvent.data_len);
FMemory::Memcpy(OutEvent.Data.GetData(), CEvent.data, CEvent.data_len);
}
else
{
OutEvent.Data.Empty();
}
return true;
}
uint64 GetRTT() const
{
return Handle ? fastnet_client_rtt_us(Handle) : 0;
}
float GetRTTMs() const
{
return GetRTT() / 1000.0f;
}
private:
FastNetClient Handle;
};
class YOURGAME_API FFastNetServer
{
public:
FFastNetServer() : Handle(nullptr) {}
~FFastNetServer()
{
Destroy();
}
FFastNetServer(const FFastNetServer&) = delete;
FFastNetServer& operator=(const FFastNetServer&) = delete;
bool Create(uint16 UdpPort, uint16 TcpPort, const FString& CertPath, const FString& KeyPath)
{
Destroy();
Handle = fastnet_server_create(
UdpPort,
TcpPort,
TCHAR_TO_UTF8(*CertPath),
TCHAR_TO_UTF8(*KeyPath)
);
return Handle != nullptr;
}
void Destroy()
{
if (Handle)
{
fastnet_server_destroy(Handle);
Handle = nullptr;
}
}
bool IsRunning() const
{
return Handle != nullptr;
}
bool Send(uint16 PeerId, uint8 Channel, const TArray<uint8>& Data)
{
if (!Handle || Data.Num() == 0) return false;
return fastnet_server_send(Handle, PeerId, Channel, Data.GetData(), Data.Num()) == 0;
}
void Broadcast(uint8 Channel, const TArray<uint8>& Data)
{
}
bool Poll(FFastNetEvent& OutEvent)
{
if (!Handle) return false;
FastNetEvent CEvent;
if (!fastnet_server_poll(Handle, &CEvent)) return false;
OutEvent.Type = static_cast<EFastNetEventType>(CEvent.type);
OutEvent.PeerId = CEvent.peer_id;
OutEvent.Channel = CEvent.channel;
OutEvent.ErrorCode = CEvent.error_code;
if (CEvent.data && CEvent.data_len > 0)
{
OutEvent.Data.SetNumUninitialized(CEvent.data_len);
FMemory::Memcpy(OutEvent.Data.GetData(), CEvent.data, CEvent.data_len);
}
else
{
OutEvent.Data.Empty();
}
return true;
}
uint32 GetPeerCount() const
{
return Handle ? fastnet_server_peer_count(Handle) : 0;
}
private:
FastNetServer Handle;
};