优化代码 修复发送空消息阻塞
This commit is contained in:
parent
859db61f9c
commit
2cd3447821
@ -5,85 +5,54 @@
|
|||||||
#include "Sockets.h"
|
#include "Sockets.h"
|
||||||
#include "IPAddress.h"
|
#include "IPAddress.h"
|
||||||
#include "SocketSubsystem.h"
|
#include "SocketSubsystem.h"
|
||||||
|
#include "..\Public\RedNetworkClient.h"
|
||||||
|
|
||||||
bool URedNetworkClient::Send(const TArray<uint8>& Data)
|
bool URedNetworkClient::Send(const TArray<uint8>& Data)
|
||||||
{
|
{
|
||||||
if (!IsActive() || !(ClientPass.ID | ClientPass.Key)) return false;
|
if (!IsActive() || !IsLogged()) return false;
|
||||||
|
|
||||||
return KCPUnit->Send(Data.GetData(), Data.Num());
|
return KCPUnit->Send(Data.GetData(), Data.Num()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 URedNetworkClient::UDPSend(const uint8 * Data, int32 Count)
|
void URedNetworkClient::UDPSend(const uint8 * Data, int32 Count)
|
||||||
{
|
|
||||||
if (!IsActive() || !(ClientPass.ID | ClientPass.Key)) return false;
|
|
||||||
|
|
||||||
SendBuffer.SetNumUninitialized(8, false);
|
|
||||||
|
|
||||||
SendBuffer[0] = ClientPass.ID >> 0;
|
|
||||||
SendBuffer[1] = ClientPass.ID >> 8;
|
|
||||||
SendBuffer[2] = ClientPass.ID >> 16;
|
|
||||||
SendBuffer[3] = ClientPass.ID >> 24;
|
|
||||||
|
|
||||||
SendBuffer[4] = ClientPass.Key >> 0;
|
|
||||||
SendBuffer[5] = ClientPass.Key >> 8;
|
|
||||||
SendBuffer[6] = ClientPass.Key >> 16;
|
|
||||||
SendBuffer[7] = ClientPass.Key >> 24;
|
|
||||||
|
|
||||||
SendBuffer.Append(Data, Count);
|
|
||||||
|
|
||||||
int32 BytesSend;
|
|
||||||
SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *ServerAddrPtr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void URedNetworkClient::Tick(float DeltaTime)
|
|
||||||
{
|
{
|
||||||
if (!IsActive()) return;
|
if (!IsActive()) return;
|
||||||
|
|
||||||
ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get();
|
SendBuffer.SetNumUninitialized(8, false);
|
||||||
check(SocketSubsystem);
|
|
||||||
|
|
||||||
const FDateTime NowTime = FDateTime::Now();
|
ClientPass.ToBytes(SendBuffer.GetData());
|
||||||
|
|
||||||
|
if (Count != 0) SendBuffer.Append(Data, Count);
|
||||||
|
|
||||||
|
int32 BytesSend;
|
||||||
|
SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *ServerAddrPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void URedNetworkClient::UpdateKCP()
|
||||||
|
{
|
||||||
|
if (!KCPUnit) return;
|
||||||
|
|
||||||
// update kcp
|
|
||||||
if (KCPUnit)
|
|
||||||
{
|
|
||||||
int32 Current = FPlatformTime::Cycles64() / 1000;
|
int32 Current = FPlatformTime::Cycles64() / 1000;
|
||||||
|
|
||||||
KCPUnit->Update(Current);
|
KCPUnit->Update(Current);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send heartbeat
|
void URedNetworkClient::SendHeartbeat()
|
||||||
{
|
{
|
||||||
if (NowTime - LastHeartbeat > Heartbeat)
|
UDPSend(nullptr, 0);
|
||||||
{
|
}
|
||||||
SendBuffer.SetNumUninitialized(8, false);
|
|
||||||
|
|
||||||
SendBuffer[0] = ClientPass.ID >> 0;
|
void URedNetworkClient::HandleSocketRecv()
|
||||||
SendBuffer[1] = ClientPass.ID >> 8;
|
{
|
||||||
SendBuffer[2] = ClientPass.ID >> 16;
|
ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get();
|
||||||
SendBuffer[3] = ClientPass.ID >> 24;
|
check(SocketSubsystem);
|
||||||
|
check(SocketPtr);
|
||||||
SendBuffer[4] = ClientPass.Key >> 0;
|
|
||||||
SendBuffer[5] = ClientPass.Key >> 8;
|
|
||||||
SendBuffer[6] = ClientPass.Key >> 16;
|
|
||||||
SendBuffer[7] = ClientPass.Key >> 24;
|
|
||||||
|
|
||||||
int32 BytesSend;
|
|
||||||
if (SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *ServerAddrPtr) && BytesSend == SendBuffer.Num())
|
|
||||||
{
|
|
||||||
LastHeartbeat = NowTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle socket recv
|
|
||||||
{
|
|
||||||
int32 BytesRead;
|
int32 BytesRead;
|
||||||
TSharedRef<FInternetAddr> SourceAddr = SocketSubsystem->CreateInternetAddr();
|
|
||||||
|
|
||||||
while (SocketPtr) {
|
while (SocketPtr) {
|
||||||
|
|
||||||
|
TSharedRef<FInternetAddr> SourceAddr = SocketSubsystem->CreateInternetAddr();
|
||||||
|
|
||||||
RecvBuffer.SetNumUninitialized(65535, false);
|
RecvBuffer.SetNumUninitialized(65535, false);
|
||||||
|
|
||||||
if (!SocketPtr->RecvFrom(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead, *SourceAddr)) break;
|
if (!SocketPtr->RecvFrom(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead, *SourceAddr)) break;
|
||||||
@ -91,23 +60,30 @@ void URedNetworkClient::Tick(float DeltaTime)
|
|||||||
if (BytesRead < 8) continue;
|
if (BytesRead < 8) continue;
|
||||||
RecvBuffer.SetNumUninitialized(BytesRead, false);
|
RecvBuffer.SetNumUninitialized(BytesRead, false);
|
||||||
|
|
||||||
FRedNetworkPass SourcePass;
|
FRedNetworkPass SourcePass(RecvBuffer.GetData());
|
||||||
SourcePass.ID = 0;
|
|
||||||
SourcePass.Key = 0;
|
|
||||||
|
|
||||||
SourcePass.ID |= (int32)RecvBuffer[0] << 0;
|
HandleLoginRecv(SourcePass);
|
||||||
SourcePass.ID |= (int32)RecvBuffer[1] << 8;
|
|
||||||
SourcePass.ID |= (int32)RecvBuffer[2] << 16;
|
|
||||||
SourcePass.ID |= (int32)RecvBuffer[3] << 24;
|
|
||||||
|
|
||||||
SourcePass.Key |= (int32)RecvBuffer[4] << 0;
|
if (!IsLogged()) continue;
|
||||||
SourcePass.Key |= (int32)RecvBuffer[5] << 8;
|
|
||||||
SourcePass.Key |= (int32)RecvBuffer[6] << 16;
|
|
||||||
SourcePass.Key |= (int32)RecvBuffer[7] << 24;
|
|
||||||
|
|
||||||
// is registration request
|
if (SourcePass.ID == ClientPass.ID && SourcePass.Key == ClientPass.Key)
|
||||||
if (!IsLogged())
|
|
||||||
{
|
{
|
||||||
|
LastRecvTime = NowTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RecvBuffer.Num() == 8) continue;
|
||||||
|
|
||||||
|
if (SourcePass.ID == ClientPass.ID && SourcePass.Key == ClientPass.Key)
|
||||||
|
{
|
||||||
|
KCPUnit->Input(RecvBuffer.GetData() + 8, RecvBuffer.Num() - 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void URedNetworkClient::HandleLoginRecv(const FRedNetworkPass & SourcePass)
|
||||||
|
{
|
||||||
|
if (IsLogged()) return;
|
||||||
|
|
||||||
ClientPass = SourcePass;
|
ClientPass = SourcePass;
|
||||||
|
|
||||||
KCPUnit = MakeShared<FKCPWrap>(ClientPass.ID, FString::Printf(TEXT("Client-%i"), ClientPass.ID));
|
KCPUnit = MakeShared<FKCPWrap>(ClientPass.ID, FString::Printf(TEXT("Client-%i"), ClientPass.ID));
|
||||||
@ -116,54 +92,38 @@ void URedNetworkClient::Tick(float DeltaTime)
|
|||||||
|
|
||||||
KCPUnit->OutputFunc = [this](const uint8* Data, int32 Count)->int32
|
KCPUnit->OutputFunc = [this](const uint8* Data, int32 Count)->int32
|
||||||
{
|
{
|
||||||
return UDPSend(Data, Count);
|
UDPSend(Data, Count);
|
||||||
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
OnLogin.Broadcast();
|
OnLogin.Broadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SourcePass.ID == ClientPass.ID && SourcePass.Key == ClientPass.Key)
|
void URedNetworkClient::HandleKCPRecv()
|
||||||
{
|
{
|
||||||
LastRecvTime = NowTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
// is heartbeat request
|
|
||||||
if ((SourcePass.ID | SourcePass.Key) && RecvBuffer.Num() == 8) continue;
|
|
||||||
|
|
||||||
// is server request
|
|
||||||
if (SourcePass.ID == ClientPass.ID && SourcePass.Key == ClientPass.Key)
|
|
||||||
{
|
|
||||||
KCPUnit->Input(RecvBuffer.GetData() + 8, RecvBuffer.Num() - 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle kcp recv
|
|
||||||
{
|
|
||||||
while (KCPUnit)
|
while (KCPUnit)
|
||||||
{
|
{
|
||||||
int32 Size = KCPUnit->PeekSize();
|
int32 Size = KCPUnit->PeekSize();
|
||||||
|
|
||||||
if (Size <= 0) break;
|
if (Size < 0) break;
|
||||||
|
|
||||||
RecvBuffer.SetNumUninitialized(Size, false);
|
RecvBuffer.SetNumUninitialized(Size, false);
|
||||||
|
|
||||||
Size = KCPUnit->Recv(RecvBuffer.GetData(), RecvBuffer.Num());
|
Size = KCPUnit->Recv(RecvBuffer.GetData(), RecvBuffer.Num());
|
||||||
|
|
||||||
if (Size <= 0) break;
|
if (Size < 0) break;
|
||||||
|
|
||||||
RecvBuffer.SetNumUninitialized(Size, false);
|
RecvBuffer.SetNumUninitialized(Size, false);
|
||||||
|
|
||||||
OnRecv.Broadcast(RecvBuffer);
|
OnRecv.Broadcast(RecvBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle timeout
|
void URedNetworkClient::HandleTimeout()
|
||||||
{
|
{
|
||||||
if (IsLogged() && NowTime - LastRecvTime > TimeoutLimit)
|
if (IsLogged() && NowTime - LastRecvTime > TimeoutLimit)
|
||||||
{
|
{
|
||||||
ClientPass.ID = 0;
|
ClientPass.Reset();
|
||||||
ClientPass.Key = 0;
|
|
||||||
|
|
||||||
KCPUnit = nullptr;
|
KCPUnit = nullptr;
|
||||||
|
|
||||||
@ -171,7 +131,19 @@ void URedNetworkClient::Tick(float DeltaTime)
|
|||||||
|
|
||||||
OnUnlogin.Broadcast();
|
OnUnlogin.Broadcast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void URedNetworkClient::Tick(float DeltaTime)
|
||||||
|
{
|
||||||
|
if (!IsActive()) return;
|
||||||
|
|
||||||
|
NowTime = FDateTime::Now();
|
||||||
|
|
||||||
|
UpdateKCP();
|
||||||
|
SendHeartbeat();
|
||||||
|
HandleSocketRecv();
|
||||||
|
HandleKCPRecv();
|
||||||
|
HandleTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void URedNetworkClient::Activate(bool bReset)
|
void URedNetworkClient::Activate(bool bReset)
|
||||||
@ -215,8 +187,7 @@ void URedNetworkClient::Activate(bool bReset)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientPass.ID = 0;
|
ClientPass.Reset();
|
||||||
ClientPass.Key = 0;
|
|
||||||
LastRecvTime = FDateTime::Now();
|
LastRecvTime = FDateTime::Now();
|
||||||
LastHeartbeat = FDateTime::MinValue();
|
LastHeartbeat = FDateTime::MinValue();
|
||||||
UE_LOG(LogRedNetwork, Log, TEXT("Red Network Client activate."));
|
UE_LOG(LogRedNetwork, Log, TEXT("Red Network Client activate."));
|
||||||
@ -239,10 +210,8 @@ void URedNetworkClient::Deactivate()
|
|||||||
|
|
||||||
SendBuffer.SetNum(0);
|
SendBuffer.SetNum(0);
|
||||||
RecvBuffer.SetNum(0);
|
RecvBuffer.SetNum(0);
|
||||||
DataBuffer.SetNum(0);
|
|
||||||
|
|
||||||
ClientPass.ID = 0;
|
ClientPass.Reset();
|
||||||
ClientPass.Key = 0;
|
|
||||||
|
|
||||||
KCPUnit = nullptr;
|
KCPUnit = nullptr;
|
||||||
|
|
||||||
|
@ -6,289 +6,233 @@
|
|||||||
#include "IPAddress.h"
|
#include "IPAddress.h"
|
||||||
#include "SocketSubsystem.h"
|
#include "SocketSubsystem.h"
|
||||||
#include "HAL/UnrealMemory.h"
|
#include "HAL/UnrealMemory.h"
|
||||||
|
#include "..\Public\RedNetworkServer.h"
|
||||||
|
|
||||||
bool URedNetworkServer::Send(int32 ClientID, const TArray<uint8>& Data)
|
bool URedNetworkServer::Send(int32 ClientID, const TArray<uint8>& Data)
|
||||||
{
|
{
|
||||||
if (!IsActive() || !Registration.Contains(ClientID)) return false;
|
if (!IsActive() || !Connections.Contains(ClientID)) return false;
|
||||||
|
|
||||||
const FRegistrationInfo& Info = Registration[ClientID];
|
const FConnectionInfo& Info = Connections[ClientID];
|
||||||
|
|
||||||
return !Info.KCPUnit->Send(Data.GetData(), Data.Num());
|
return Info.KCPUnit->Send(Data.GetData(), Data.Num()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 URedNetworkServer::UDPSend(int32 ClientID, const uint8* Data, int32 Count)
|
void URedNetworkServer::UDPSend(int32 ClientID, const uint8* Data, int32 Count)
|
||||||
{
|
{
|
||||||
if (!IsActive() || !Registration.Contains(ClientID)) return false;
|
if (!IsActive() || !Connections.Contains(ClientID)) return;
|
||||||
|
|
||||||
const FRegistrationInfo& Info = Registration[ClientID];
|
const FConnectionInfo& Info = Connections[ClientID];
|
||||||
|
|
||||||
SendBuffer.SetNumUninitialized(8, false);
|
SendBuffer.SetNumUninitialized(8, false);
|
||||||
|
|
||||||
SendBuffer[0] = Info.Pass.ID >> 0;
|
Info.Pass.ToBytes(SendBuffer.GetData());
|
||||||
SendBuffer[1] = Info.Pass.ID >> 8;
|
|
||||||
SendBuffer[2] = Info.Pass.ID >> 16;
|
|
||||||
SendBuffer[3] = Info.Pass.ID >> 24;
|
|
||||||
|
|
||||||
SendBuffer[4] = Info.Pass.Key >> 0;
|
if (Count != 0) SendBuffer.Append(Data, Count);
|
||||||
SendBuffer[5] = Info.Pass.Key >> 8;
|
|
||||||
SendBuffer[6] = Info.Pass.Key >> 16;
|
|
||||||
SendBuffer[7] = Info.Pass.Key >> 24;
|
|
||||||
|
|
||||||
SendBuffer.Append(Data, Count);
|
|
||||||
|
|
||||||
int32 BytesSend;
|
int32 BytesSend;
|
||||||
SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *Info.Addr);
|
SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *Info.Addr);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void URedNetworkServer::Tick(float DeltaTime)
|
void URedNetworkServer::UpdateKCP()
|
||||||
{
|
{
|
||||||
if (!IsActive()) return;
|
|
||||||
|
|
||||||
ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get();
|
|
||||||
check(SocketSubsystem);
|
|
||||||
|
|
||||||
const FDateTime NowTime = FDateTime::Now();
|
|
||||||
|
|
||||||
// update kcp
|
|
||||||
{
|
|
||||||
TArray<int32> RegistrationAddr;
|
|
||||||
Registration.GetKeys(RegistrationAddr);
|
|
||||||
|
|
||||||
int32 Current = FPlatformTime::Cycles64() / 1000;
|
int32 Current = FPlatformTime::Cycles64() / 1000;
|
||||||
|
|
||||||
for (int32 ID : RegistrationAddr)
|
for (auto Info : Connections)
|
||||||
{
|
{
|
||||||
Registration[ID].KCPUnit->Update(Current);
|
Info.Value.KCPUnit->Update(Current);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// send heartbeat
|
void URedNetworkServer::SendHeartbeat()
|
||||||
|
{
|
||||||
|
for (auto Info : Connections)
|
||||||
{
|
{
|
||||||
TArray<int32> RegistrationAddr;
|
UDPSend(Info.Key, nullptr, 0);
|
||||||
Registration.GetKeys(RegistrationAddr);
|
|
||||||
|
|
||||||
for (int32 ID : RegistrationAddr)
|
|
||||||
{
|
|
||||||
if (NowTime - Registration[ID].Heartbeat > Heartbeat)
|
|
||||||
{
|
|
||||||
SendBuffer.SetNum(8, false);
|
|
||||||
|
|
||||||
SendBuffer[0] = Registration[ID].Pass.ID >> 0;
|
|
||||||
SendBuffer[1] = Registration[ID].Pass.ID >> 8;
|
|
||||||
SendBuffer[2] = Registration[ID].Pass.ID >> 16;
|
|
||||||
SendBuffer[3] = Registration[ID].Pass.ID >> 24;
|
|
||||||
|
|
||||||
SendBuffer[4] = Registration[ID].Pass.Key >> 0;
|
|
||||||
SendBuffer[5] = Registration[ID].Pass.Key >> 8;
|
|
||||||
SendBuffer[6] = Registration[ID].Pass.Key >> 16;
|
|
||||||
SendBuffer[7] = Registration[ID].Pass.Key >> 24;
|
|
||||||
|
|
||||||
int32 BytesSend;
|
|
||||||
if (SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *Registration[ID].Addr) && BytesSend == SendBuffer.Num())
|
|
||||||
{
|
|
||||||
Registration[ID].Heartbeat = NowTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// handle socket recv
|
void URedNetworkServer::HandleSocketRecv()
|
||||||
{
|
{
|
||||||
|
ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get();
|
||||||
|
check(SocketSubsystem);
|
||||||
|
check(SocketPtr);
|
||||||
int32 BytesRead;
|
int32 BytesRead;
|
||||||
TSharedRef<FInternetAddr> SourceAddr = SocketSubsystem->CreateInternetAddr();
|
|
||||||
|
|
||||||
while (SocketPtr) {
|
while (SocketPtr) {
|
||||||
|
|
||||||
|
TSharedRef<FInternetAddr> SourceAddr = SocketSubsystem->CreateInternetAddr();
|
||||||
|
|
||||||
RecvBuffer.SetNumUninitialized(65535, false);
|
RecvBuffer.SetNumUninitialized(65535, false);
|
||||||
|
|
||||||
if (!SocketPtr->RecvFrom(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead, *SourceAddr)) break;
|
if (!SocketPtr->RecvFrom(RecvBuffer.GetData(), RecvBuffer.Num(), BytesRead, *SourceAddr)) break;
|
||||||
|
|
||||||
if (BytesRead < 8) continue;
|
if (RecvBuffer.Num() < 8) continue;
|
||||||
RecvBuffer.SetNumUninitialized(BytesRead, false);
|
RecvBuffer.SetNumUninitialized(BytesRead, false);
|
||||||
|
|
||||||
FRedNetworkPass SourcePass;
|
FRedNetworkPass SourcePass(RecvBuffer.GetData());
|
||||||
SourcePass.ID = 0;
|
|
||||||
SourcePass.Key = 0;
|
|
||||||
|
|
||||||
SourcePass.ID |= (int32)RecvBuffer[0] << 0;
|
if (!SourcePass.IsValid())
|
||||||
SourcePass.ID |= (int32)RecvBuffer[1] << 8;
|
|
||||||
SourcePass.ID |= (int32)RecvBuffer[2] << 16;
|
|
||||||
SourcePass.ID |= (int32)RecvBuffer[3] << 24;
|
|
||||||
|
|
||||||
SourcePass.Key |= (int32)RecvBuffer[4] << 0;
|
|
||||||
SourcePass.Key |= (int32)RecvBuffer[5] << 8;
|
|
||||||
SourcePass.Key |= (int32)RecvBuffer[6] << 16;
|
|
||||||
SourcePass.Key |= (int32)RecvBuffer[7] << 24;
|
|
||||||
|
|
||||||
FString SourceAddrStr = SourceAddr->ToString(true);
|
|
||||||
|
|
||||||
// is pre-register pass request
|
|
||||||
if (!(SourcePass.ID | SourcePass.Key))
|
|
||||||
{
|
{
|
||||||
if (!PreRegistration.Contains(SourceAddrStr))
|
SendReadyPass(SourceAddr);
|
||||||
{
|
continue;
|
||||||
FPreRegistrationInfo NewRegistration;
|
|
||||||
NewRegistration.Time = NowTime;
|
|
||||||
NewRegistration.Pass.ID = NextRegistrationID++;
|
|
||||||
NewRegistration.Pass.Key ^= FMath::Rand() << 0;
|
|
||||||
NewRegistration.Pass.Key ^= FMath::Rand() << 8;
|
|
||||||
NewRegistration.Pass.Key ^= FMath::Rand() << 16;
|
|
||||||
NewRegistration.Pass.Key ^= FMath::Rand() << 24;
|
|
||||||
|
|
||||||
PreRegistration.Add(SourceAddrStr, NewRegistration);
|
|
||||||
|
|
||||||
UE_LOG(LogRedNetwork, Log, TEXT("Pre-register pass %i from %s."), NewRegistration.Pass.ID, *SourceAddrStr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const FRedNetworkPass& Pass = PreRegistration[SourceAddrStr].Pass;
|
RedirectConnection(SourcePass, SourceAddr);
|
||||||
|
RegisterConnection(SourcePass, SourceAddr);
|
||||||
|
|
||||||
|
if (!Connections.Contains(SourcePass.ID)) continue;
|
||||||
|
|
||||||
|
Connections[SourcePass.ID].RecvTime = NowTime;
|
||||||
|
|
||||||
|
if (RecvBuffer.Num() == 8) continue;
|
||||||
|
|
||||||
|
if (Connections.Contains(SourcePass.ID))
|
||||||
|
{
|
||||||
|
Connections[SourcePass.ID].KCPUnit->Input(RecvBuffer.GetData() + 8, RecvBuffer.Num() - 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void URedNetworkServer::SendReadyPass(const TSharedRef<FInternetAddr>& SourceAddr)
|
||||||
|
{
|
||||||
|
FString SourceAddrStr = SourceAddr->ToString(true);
|
||||||
|
|
||||||
|
if (!ReadyPass.Contains(SourceAddrStr))
|
||||||
|
{
|
||||||
|
FReadyInfo NewReadyPass;
|
||||||
|
NewReadyPass.Time = NowTime;
|
||||||
|
NewReadyPass.Pass.ID = NextReadyID++;
|
||||||
|
NewReadyPass.Pass.RandKey();
|
||||||
|
|
||||||
|
ReadyPass.Add(SourceAddrStr, NewReadyPass);
|
||||||
|
|
||||||
|
UE_LOG(LogRedNetwork, Log, TEXT("Ready pass %i from %s."), NewReadyPass.Pass.ID, *SourceAddrStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const FRedNetworkPass& Pass = ReadyPass[SourceAddrStr].Pass;
|
||||||
|
|
||||||
SendBuffer.SetNum(8, false);
|
SendBuffer.SetNum(8, false);
|
||||||
|
|
||||||
SendBuffer[0] = Pass.ID >> 0;
|
Pass.ToBytes(SendBuffer.GetData());
|
||||||
SendBuffer[1] = Pass.ID >> 8;
|
|
||||||
SendBuffer[2] = Pass.ID >> 16;
|
|
||||||
SendBuffer[3] = Pass.ID >> 24;
|
|
||||||
|
|
||||||
SendBuffer[4] = Pass.Key >> 0;
|
|
||||||
SendBuffer[5] = Pass.Key >> 8;
|
|
||||||
SendBuffer[6] = Pass.Key >> 16;
|
|
||||||
SendBuffer[7] = Pass.Key >> 24;
|
|
||||||
|
|
||||||
int32 BytesSend;
|
int32 BytesSend;
|
||||||
if (SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *SourceAddr) && BytesSend == SendBuffer.Num())
|
SocketPtr->SendTo(SendBuffer.GetData(), SendBuffer.Num(), BytesSend, *SourceAddr);
|
||||||
{
|
|
||||||
UE_LOG(LogRedNetwork, Log, TEXT("Send pre-registration pass %i to %s."), Pass.ID, *SourceAddrStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// redirect connection
|
|
||||||
if (Registration.Contains(SourcePass.ID))
|
|
||||||
{
|
|
||||||
if (!(*Registration[SourcePass.ID].Addr == *SourceAddr))
|
|
||||||
{
|
|
||||||
Registration[SourcePass.ID].Addr = SourceAddr;
|
|
||||||
|
|
||||||
UE_LOG(LogRedNetwork, Log, TEXT("Redirect connection %i."), SourcePass.ID);
|
UE_LOG(LogRedNetwork, Log, TEXT("Send ready pass %i to %s."), Pass.ID, *SourceAddrStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void URedNetworkServer::RedirectConnection(const FRedNetworkPass& SourcePass, const TSharedRef<FInternetAddr>& SourceAddr)
|
||||||
|
{
|
||||||
|
if (!Connections.Contains(SourcePass.ID) || Connections[SourcePass.ID].Pass.Key != SourcePass.Key) return;
|
||||||
|
|
||||||
|
if (!(*Connections[SourcePass.ID].Addr == *SourceAddr))
|
||||||
|
{
|
||||||
|
UE_LOG(LogRedNetwork, Log, TEXT("Redirect connection %i from %s to %s."), SourcePass.ID, *Connections[SourcePass.ID].Addr->ToString(true), *SourceAddr->ToString(true));
|
||||||
|
|
||||||
|
Connections[SourcePass.ID].Addr = SourceAddr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
void URedNetworkServer::RegisterConnection(const FRedNetworkPass& SourcePass, const TSharedRef<FInternetAddr>& SourceAddr)
|
||||||
|
{
|
||||||
|
FString SourceAddrStr = SourceAddr->ToString(true);
|
||||||
|
|
||||||
// register connection
|
if (!ReadyPass.Contains(SourceAddrStr)) return;
|
||||||
{
|
if (ReadyPass[SourceAddrStr].Pass.ID != SourcePass.ID || ReadyPass[SourceAddrStr].Pass.Key != SourcePass.Key) return;
|
||||||
bool bIsValidRegistration = false;
|
|
||||||
if (PreRegistration.Contains(SourceAddrStr))
|
|
||||||
{
|
|
||||||
if (PreRegistration[SourceAddrStr].Pass.ID == SourcePass.ID && PreRegistration[SourceAddrStr].Pass.Key == SourcePass.Key)
|
|
||||||
{
|
|
||||||
bIsValidRegistration = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bIsValidRegistration)
|
FConnectionInfo NewConnections;
|
||||||
{
|
NewConnections.Pass = SourcePass;
|
||||||
FRegistrationInfo NewRegistration;
|
NewConnections.RecvTime = NowTime;
|
||||||
NewRegistration.Pass = SourcePass;
|
NewConnections.Heartbeat = FDateTime::MinValue();
|
||||||
NewRegistration.RecvTime = NowTime;
|
NewConnections.Addr = SourceAddr;
|
||||||
NewRegistration.Heartbeat = FDateTime::MinValue();
|
|
||||||
NewRegistration.Addr = SourceAddr;
|
|
||||||
|
|
||||||
NewRegistration.KCPUnit = MakeShared<FKCPWrap>(NewRegistration.Pass.ID, FString::Printf(TEXT("Server-%i"), NewRegistration.Pass.ID));
|
NewConnections.KCPUnit = MakeShared<FKCPWrap>(NewConnections.Pass.ID, FString::Printf(TEXT("Server-%i"), NewConnections.Pass.ID));
|
||||||
NewRegistration.KCPUnit->SetTurboMode();
|
NewConnections.KCPUnit->SetTurboMode();
|
||||||
NewRegistration.KCPUnit->GetKCPCB().logmask = KCPLogMask;
|
NewConnections.KCPUnit->GetKCPCB().logmask = KCPLogMask;
|
||||||
|
|
||||||
NewRegistration.KCPUnit->OutputFunc = [this, ID = NewRegistration.Pass.ID](const uint8* Data, int32 Count) -> int32
|
NewConnections.KCPUnit->OutputFunc = [this, ID = NewConnections.Pass.ID](const uint8* Data, int32 Count)->int32
|
||||||
{
|
{
|
||||||
return UDPSend(ID, Data, Count);
|
UDPSend(ID, Data, Count);
|
||||||
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Registration.Add(SourcePass.ID, NewRegistration);
|
Connections.Add(SourcePass.ID, NewConnections);
|
||||||
|
|
||||||
PreRegistration.Remove(SourceAddrStr);
|
ReadyPass.Remove(SourceAddrStr);
|
||||||
|
|
||||||
UE_LOG(LogRedNetwork, Log, TEXT("Register connection %i."), SourcePass.ID);
|
UE_LOG(LogRedNetwork, Log, TEXT("Register connection %i."), SourcePass.ID);
|
||||||
|
|
||||||
OnLogin.Broadcast(SourcePass.ID);
|
OnLogin.Broadcast(SourcePass.ID);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Registration.Contains(SourcePass.ID))
|
void URedNetworkServer::HandleKCPRecv()
|
||||||
|
{
|
||||||
|
for (auto Info : Connections)
|
||||||
{
|
{
|
||||||
Registration[SourcePass.ID].RecvTime = NowTime;
|
while (Info.Value.KCPUnit)
|
||||||
}
|
|
||||||
|
|
||||||
// is heartbeat request
|
|
||||||
if ((SourcePass.ID | SourcePass.Key) && RecvBuffer.Num() == 8) continue;
|
|
||||||
|
|
||||||
// is client request
|
|
||||||
if (Registration.Contains(SourcePass.ID))
|
|
||||||
{
|
{
|
||||||
Registration[SourcePass.ID].KCPUnit->Input(RecvBuffer.GetData() + 8, RecvBuffer.Num() - 8);
|
int32 Size = Info.Value.KCPUnit->PeekSize();
|
||||||
}
|
|
||||||
|
if (Size < 0) break;
|
||||||
|
|
||||||
|
RecvBuffer.SetNumUninitialized(Size, false);
|
||||||
|
|
||||||
|
Size = Info.Value.KCPUnit->Recv(RecvBuffer.GetData(), RecvBuffer.Num());
|
||||||
|
|
||||||
|
if (Size < 0) break;
|
||||||
|
|
||||||
|
RecvBuffer.SetNumUninitialized(Size, false);
|
||||||
|
|
||||||
|
OnRecv.Broadcast(Info.Key, RecvBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// handle pre-registration timeout
|
void URedNetworkServer::HandleExpiredReadyPass()
|
||||||
{
|
{
|
||||||
TArray<FString> PreRegistrationAddr;
|
TArray<FString> ReadyPassAddr;
|
||||||
PreRegistration.GetKeys(PreRegistrationAddr);
|
ReadyPass.GetKeys(ReadyPassAddr);
|
||||||
|
|
||||||
for (const FString& Addr : PreRegistrationAddr)
|
for (const FString& Addr : ReadyPassAddr)
|
||||||
{
|
{
|
||||||
if (NowTime - PreRegistration[Addr].Time > TimeoutLimit)
|
if (NowTime - ReadyPass[Addr].Time > TimeoutLimit)
|
||||||
{
|
{
|
||||||
UE_LOG(LogRedNetwork, Log, TEXT("Pre-registration pass %i timeout."), PreRegistration[Addr].Pass.ID);
|
UE_LOG(LogRedNetwork, Log, TEXT("Ready pass %i timeout."), ReadyPass[Addr].Pass.ID);
|
||||||
|
|
||||||
PreRegistration.Remove(Addr);
|
ReadyPass.Remove(Addr);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// handle running timeout
|
void URedNetworkServer::HandleExpiredConnection()
|
||||||
{
|
{
|
||||||
TArray<int32> RegistrationAddr;
|
TArray<int32> ConnectionsAddr;
|
||||||
Registration.GetKeys(RegistrationAddr);
|
Connections.GetKeys(ConnectionsAddr);
|
||||||
|
|
||||||
for (int32 ID : RegistrationAddr)
|
for (int32 ID : ConnectionsAddr)
|
||||||
{
|
{
|
||||||
if (NowTime - Registration[ID].RecvTime > TimeoutLimit)
|
if (NowTime - Connections[ID].RecvTime > TimeoutLimit)
|
||||||
{
|
{
|
||||||
UE_LOG(LogRedNetwork, Log, TEXT("Registration connection %i timeout."), Registration[ID].Pass.ID);
|
UE_LOG(LogRedNetwork, Log, TEXT("Connections connection %i timeout."), Connections[ID].Pass.ID);
|
||||||
|
|
||||||
Registration.Remove(ID);
|
Connections.Remove(ID);
|
||||||
|
|
||||||
OnUnlogin.Broadcast(ID);
|
OnUnlogin.Broadcast(ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle kcp recv
|
void URedNetworkServer::Tick(float DeltaTime)
|
||||||
{
|
{
|
||||||
TArray<int32> RegistrationAddr;
|
if (!IsActive()) return;
|
||||||
Registration.GetKeys(RegistrationAddr);
|
NowTime = FDateTime::Now();
|
||||||
|
|
||||||
for (int32 ID : RegistrationAddr)
|
UpdateKCP();
|
||||||
{
|
SendHeartbeat();
|
||||||
while (Registration[ID].KCPUnit)
|
HandleSocketRecv();
|
||||||
{
|
HandleKCPRecv();
|
||||||
int32 Size = Registration[ID].KCPUnit->PeekSize();
|
HandleExpiredReadyPass();
|
||||||
|
HandleExpiredConnection();
|
||||||
if (Size <= 0) break;
|
|
||||||
|
|
||||||
RecvBuffer.SetNumUninitialized(Size, false);
|
|
||||||
|
|
||||||
Size = Registration[ID].KCPUnit->Recv(RecvBuffer.GetData(), RecvBuffer.Num());
|
|
||||||
|
|
||||||
if (Size <= 0) break;
|
|
||||||
|
|
||||||
RecvBuffer.SetNumUninitialized(Size, false);
|
|
||||||
|
|
||||||
OnRecv.Broadcast(ID, RecvBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void URedNetworkServer::Activate(bool bReset)
|
void URedNetworkServer::Activate(bool bReset)
|
||||||
@ -331,7 +275,7 @@ void URedNetworkServer::Activate(bool bReset)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NextRegistrationID = 1;
|
NextReadyID = 1;
|
||||||
|
|
||||||
UE_LOG(LogRedNetwork, Log, TEXT("Red Network Server activate."));
|
UE_LOG(LogRedNetwork, Log, TEXT("Red Network Server activate."));
|
||||||
|
|
||||||
@ -342,10 +286,10 @@ void URedNetworkServer::Deactivate()
|
|||||||
{
|
{
|
||||||
if (!bIsActive) return;
|
if (!bIsActive) return;
|
||||||
|
|
||||||
TArray<int32> RegistrationAddr;
|
TArray<int32> ConnectionsAddr;
|
||||||
Registration.GetKeys(RegistrationAddr);
|
Connections.GetKeys(ConnectionsAddr);
|
||||||
|
|
||||||
for (int32 ID : RegistrationAddr)
|
for (int32 ID : ConnectionsAddr)
|
||||||
{
|
{
|
||||||
OnUnlogin.Broadcast(ID);
|
OnUnlogin.Broadcast(ID);
|
||||||
}
|
}
|
||||||
@ -356,10 +300,9 @@ void URedNetworkServer::Deactivate()
|
|||||||
|
|
||||||
SendBuffer.SetNum(0);
|
SendBuffer.SetNum(0);
|
||||||
RecvBuffer.SetNum(0);
|
RecvBuffer.SetNum(0);
|
||||||
DataBuffer.SetNum(0);
|
|
||||||
|
|
||||||
PreRegistration.Reset();
|
ReadyPass.Reset();
|
||||||
Registration.Reset();
|
Connections.Reset();
|
||||||
|
|
||||||
UE_LOG(LogRedNetwork, Log, TEXT("Red Network Server deactivate."));
|
UE_LOG(LogRedNetwork, Log, TEXT("Red Network Server deactivate."));
|
||||||
|
|
||||||
|
@ -1 +1,62 @@
|
|||||||
#include "RedNetworkType.h"
|
#include "RedNetworkType.h"
|
||||||
|
#include "..\Public\RedNetworkType.h"
|
||||||
|
|
||||||
|
FRedNetworkPass::FRedNetworkPass()
|
||||||
|
: ID(0)
|
||||||
|
, Key(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FRedNetworkPass::FRedNetworkPass(uint8 * Data)
|
||||||
|
: FRedNetworkPass()
|
||||||
|
{
|
||||||
|
FromBytes(Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FRedNetworkPass::FromBytes(const uint8 * Data)
|
||||||
|
{
|
||||||
|
ID = 0;
|
||||||
|
Key = 0;
|
||||||
|
|
||||||
|
ID |= (int32)Data[0] << 0;
|
||||||
|
ID |= (int32)Data[1] << 8;
|
||||||
|
ID |= (int32)Data[2] << 16;
|
||||||
|
ID |= (int32)Data[3] << 24;
|
||||||
|
|
||||||
|
Key |= (int32)Data[4] << 0;
|
||||||
|
Key |= (int32)Data[5] << 8;
|
||||||
|
Key |= (int32)Data[6] << 16;
|
||||||
|
Key |= (int32)Data[7] << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FRedNetworkPass::ToBytes(uint8 * Data) const
|
||||||
|
{
|
||||||
|
Data[0] = ID >> 0;
|
||||||
|
Data[1] = ID >> 8;
|
||||||
|
Data[2] = ID >> 16;
|
||||||
|
Data[3] = ID >> 24;
|
||||||
|
|
||||||
|
Data[4] = Key >> 0;
|
||||||
|
Data[5] = Key >> 8;
|
||||||
|
Data[6] = Key >> 16;
|
||||||
|
Data[7] = Key >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FRedNetworkPass::RandKey()
|
||||||
|
{
|
||||||
|
Key ^= FMath::Rand() << 0;
|
||||||
|
Key ^= FMath::Rand() << 8;
|
||||||
|
Key ^= FMath::Rand() << 16;
|
||||||
|
Key ^= FMath::Rand() << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FRedNetworkPass::Reset()
|
||||||
|
{
|
||||||
|
ID = 0;
|
||||||
|
Key = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FRedNetworkPass::IsValid() const
|
||||||
|
{
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
@ -43,7 +43,7 @@ public:
|
|||||||
void Deactivate();
|
void Deactivate();
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, Category = "Red|Network")
|
UFUNCTION(BlueprintCallable, Category = "Red|Network")
|
||||||
bool IsLogged() const { return ClientPass.ID | ClientPass.Key; }
|
bool IsLogged() const { return ClientPass.IsValid(); }
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable, Category = "Red|Network")
|
UFUNCTION(BlueprintCallable, Category = "Red|Network")
|
||||||
bool Send(const TArray<uint8>& Data);
|
bool Send(const TArray<uint8>& Data);
|
||||||
@ -72,7 +72,6 @@ private:
|
|||||||
|
|
||||||
TArray<uint8> SendBuffer;
|
TArray<uint8> SendBuffer;
|
||||||
TArray<uint8> RecvBuffer;
|
TArray<uint8> RecvBuffer;
|
||||||
TArray<uint8> DataBuffer;
|
|
||||||
|
|
||||||
FRedNetworkPass ClientPass;
|
FRedNetworkPass ClientPass;
|
||||||
|
|
||||||
@ -81,7 +80,16 @@ private:
|
|||||||
|
|
||||||
TSharedPtr<FKCPWrap> KCPUnit;
|
TSharedPtr<FKCPWrap> KCPUnit;
|
||||||
|
|
||||||
int32 UDPSend(const uint8* Data, int32 Count);
|
void UDPSend(const uint8* Data, int32 Count);
|
||||||
|
|
||||||
|
FDateTime NowTime;
|
||||||
|
|
||||||
|
void UpdateKCP();
|
||||||
|
void SendHeartbeat();
|
||||||
|
void HandleSocketRecv();
|
||||||
|
void HandleLoginRecv(const FRedNetworkPass& SourcePass);
|
||||||
|
void HandleKCPRecv();
|
||||||
|
void HandleTimeout();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
class FSocket;
|
class FSocket;
|
||||||
class FKCPWrap;
|
class FKCPWrap;
|
||||||
|
class FInternetAddr;
|
||||||
|
|
||||||
UCLASS(BlueprintType)
|
UCLASS(BlueprintType)
|
||||||
class REDNETWORK_API URedNetworkServer : public UObject, public FTickableGameObject
|
class REDNETWORK_API URedNetworkServer : public UObject, public FTickableGameObject
|
||||||
@ -67,19 +68,18 @@ private:
|
|||||||
|
|
||||||
TArray<uint8> SendBuffer;
|
TArray<uint8> SendBuffer;
|
||||||
TArray<uint8> RecvBuffer;
|
TArray<uint8> RecvBuffer;
|
||||||
TArray<uint8> DataBuffer;
|
|
||||||
|
|
||||||
int32 NextRegistrationID;
|
int32 NextReadyID;
|
||||||
|
|
||||||
struct FPreRegistrationInfo
|
struct FReadyInfo
|
||||||
{
|
{
|
||||||
FDateTime Time;
|
FDateTime Time;
|
||||||
FRedNetworkPass Pass;
|
FRedNetworkPass Pass;
|
||||||
};
|
};
|
||||||
|
|
||||||
TMap<FString, FPreRegistrationInfo> PreRegistration;
|
TMap<FString, FReadyInfo> ReadyPass;
|
||||||
|
|
||||||
struct FRegistrationInfo
|
struct FConnectionInfo
|
||||||
{
|
{
|
||||||
FRedNetworkPass Pass;
|
FRedNetworkPass Pass;
|
||||||
FDateTime RecvTime;
|
FDateTime RecvTime;
|
||||||
@ -88,9 +88,21 @@ private:
|
|||||||
TSharedPtr<FKCPWrap> KCPUnit;
|
TSharedPtr<FKCPWrap> KCPUnit;
|
||||||
};
|
};
|
||||||
|
|
||||||
TMap<int32, FRegistrationInfo> Registration;
|
TMap<int32, FConnectionInfo> Connections;
|
||||||
|
|
||||||
int32 UDPSend(int32 ClientID, const uint8* Data, int32 Count);
|
void UDPSend(int32 ClientID, const uint8* Data, int32 Count);
|
||||||
|
|
||||||
|
FDateTime NowTime;
|
||||||
|
|
||||||
|
void UpdateKCP();
|
||||||
|
void SendHeartbeat();
|
||||||
|
void HandleSocketRecv();
|
||||||
|
void SendReadyPass(const TSharedRef<FInternetAddr>& SourceAddr);
|
||||||
|
void RedirectConnection(const FRedNetworkPass& SourcePass, const TSharedRef<FInternetAddr>& SourceAddr);
|
||||||
|
void RegisterConnection(const FRedNetworkPass& SourcePass, const TSharedRef<FInternetAddr>& SourceAddr);
|
||||||
|
void HandleKCPRecv();
|
||||||
|
void HandleExpiredReadyPass();
|
||||||
|
void HandleExpiredConnection();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -6,4 +6,15 @@ struct REDNETWORK_API FRedNetworkPass
|
|||||||
{
|
{
|
||||||
int32 ID;
|
int32 ID;
|
||||||
int32 Key;
|
int32 Key;
|
||||||
|
|
||||||
|
FRedNetworkPass();
|
||||||
|
FRedNetworkPass(uint8* Data);
|
||||||
|
|
||||||
|
void FromBytes(const uint8* Data);
|
||||||
|
void ToBytes(uint8* Data) const;
|
||||||
|
|
||||||
|
void RandKey();
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
bool IsValid() const;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user