← Back to file list Raw

src/CServer.cpp

#include "CServer.h"
#include "CEngine.h"
#include "CConVarManager.h"
#include "CBufferWrapper.h"
#include "U_Networking.h"
#include "CClient.h"
CServer::CClient::CClient(const CEndPoint& point) : EndPoint(point) {}
void CServer::V_PostInit()
{
unsigned short port = Networking::HostPort;
COMPONENT_CALL_GET(port, CConVarManager, GetConVarValue<unsigned short>("net.hostport", Networking::HostPort));
Transceiver = std::make_unique<CNetTransceiver>(port);
Transceiver->Queue.Enabled = true;
Transceiver->StartAsync();
}
void CServer::ProcessDatagram(boost::asio::ip::udp::endpoint point, std::vector<std::uint8_t>& buffer, CTimePoint ptime)
{
//Log::Instance() << "[SV] There's a datagram from " << point.address().to_string() << ":" << point.port() << Log::Endl;
CBufferWrapper packet(buffer);
if(IsClientExist(point))
{
auto& client = GetClient(point);
client.LastPacket = ptime;
if(!client.Authorized)
{
auto message = packet.ReadLenString<std::uint8_t, std::string>();
if(message == "EngineGL 5.0 Ready For Transmit")
{
client.Authorized = true;
Log::Instance() << "Client authorized!\n";
SendServerInfoTo(client);
}
}
else
{
HandleClientPacket(client, buffer, ptime);
}
}
else
{
auto message = packet.ReadLenString<std::uint8_t, std::string>();
if(message == "EngineGL 5.0 Connection Cookie")
{
auto nickname = packet.ReadLenString<std::uint8_t, std::u16string>();
auto id = GetFreeID();
CClient client(point);
client.NickName = StringUtils::U16ToWstr(nickname);
client.LastPacket = ptime;
client.MessagesManager.UserData = static_cast<size_t>(id);
client.MessagesManager.PackDelay = 1.0 / m_svRate;
Clients.emplace(id, std::move(client));
std::vector<std::uint8_t> answer_buf;
CBufferWrapper answer(answer_buf);
answer.WriteLenString<std::uint8_t, std::string>("EngineGL 5.0 Connection Accepted");
Transceiver->SendAsync(point, answer_buf);
Log::Instance() << "[Server] Client #" << id << " connected from " << point.address().to_string() << ":" << point.port();
Log::Instance() << " with a nickname of \"" << StringUtils::U16ToWstr(nickname) << "\"\n";
}
}
}
void CServer::HandleClientPacket(CClient& client, std::vector<std::uint8_t>& buffer, CTimePoint ptime)
{
client.MessagesManager.AddReceivedPacket(std::move(buffer), ptime);
}
bool CServer::CClient::operator==(const CClient& other) const
{
return EndPoint == other.EndPoint;
}
void CServer::SendReliableMessageTo(CClient& client, std::shared_ptr<CNetMessage> msg)
{
client.MessagesManager.SendReliable(msg);
}
void CServer::SendUnreliableMessageTo(CClient& client, std::shared_ptr<CNetMessage> msg)
{
client.MessagesManager.SendUnreliable(msg);
}
void CServer::SendReliableMessageToAll(std::shared_ptr<CNetMessage> msg)
{
for(auto& kv : Clients)
{
auto& client = kv.second;
client.MessagesManager.SendReliable(msg); //DONE msg used to be invalid after first send
}
}
void CServer::SendUnreliableMessageToAll(std::shared_ptr<CNetMessage> msg)
{
for(auto& kv : Clients)
{
auto& client = kv.second;
client.MessagesManager.SendUnreliable(msg); //DONE msg used to be invalid after first send
}
}
void CServer::SendServerInfoTo(CClient& client)
{
auto msg = std::make_shared<CNetServerInfo>();
SendReliableMessageTo(client, msg);
}
void CServer::SendServerInfoToAll()
{
auto msg = std::make_shared<CNetServerInfo>();
SendReliableMessageToAll(msg);
}
void CServer::SetRate(double timesPerSecond)
{
m_svRate = timesPerSecond;
for(auto& kv : Clients)
{
auto& client = kv.second;
client.MessagesManager.PackDelay = 1.0 / m_svRate;
}
SendServerInfoToAll();
}
void CServer::CClient::Update()
{
if(Authorized)
{
auto server = CEngine::GetInstance()->Components.GetComponentTyped<CServer>();
MessagesManager.ProcessPackets();
MessagesManager.ProcessMessages();
std::vector<std::uint8_t> snapshot;
if(MessagesManager.PackSnapshot(snapshot))
{
server->Transceiver->SendAsync(EndPoint, snapshot);
}
}
}
void CServer::V_Update()
{
std::uint32_t timeout = 20000;
COMPONENT_CALL_GET(timeout, CConVarManager, GetConVarValue<std::uint32_t>("net.timeout", 20000));
std::vector<clientid_t> ToKick;
for(auto& kv : Clients)
{
auto& client = kv.second;
auto diff = CEngine::GetInstance()->Time.GetCurrent() - client.LastPacket;
if(diff >= std::chrono::milliseconds(timeout))
{
ToKick.push_back(kv.first);
}
}
for(auto tokick : ToKick)
{
//TODO kick client
}
std::vector<CNetTransceiver::CPacket> packets;
{
std::lock_guard<std::mutex> _lock(Transceiver->Queue.Mutex);
packets.swap(Transceiver->Queue.Container);
}
for(auto& pack : packets)
{
ProcessDatagram(pack.From, pack.Data, pack.ReceivedAt);
}
for(auto& kv : Clients)
{
auto& client = kv.second;
client.Update();
}
}
clientid_t CServer::GetFreeID()
{
clientid_t max = std::numeric_limits<clientid_t>::max();
for(clientid_t i = 0; i <= max; i++)
{
auto it = Clients.find(i);
if(it == Clients.end())
{
return i;
}
}
return max;
}
bool CServer::IsClientExist(const CEndPoint& endpoint)
{
return m_getClientIterator(endpoint) != Clients.end();
}
CServer::CClient& CServer::GetClient(const CEndPoint& endpoint)
{
return m_getClientIterator(endpoint)->second;
}
std::unordered_map<clientid_t, CServer::CClient>::iterator CServer::m_getClientIterator(const CEndPoint& endpoint)
{
return std::find_if(Clients.begin(), Clients.end(), [&endpoint](auto& kv) -> bool { return kv.second.EndPoint == endpoint; });
}
double CServer::GetRate() const
{
return m_svRate;
}
void CNetServerInfo::V_Write(CBufferWrapper& wrapper)
{
auto server = CEngine::GetInstance()->Components.GetComponentTyped<CServer>();
if(!server) { return; }
wrapper.Write<double>(server->GetRate());
}
void CNetServerInfo::V_Read(CBufferWrapper& wrapper)
{
Rate = wrapper.Read<double>();
}
void CNetServerInfo::Process()
{
auto client = CEngine::GetInstance()->Components.GetComponentTyped<CClient>();
if(!client) { return; }
client->SetServerRate(Rate);
}
LINK_SOL_USERTYPE(CServer);
LINK_NET_MESSAGE_TO_CLASS(CNetServerInfo, serverinfo);
LINK_COMPONENT_TO_CLASS(CServer, server);