#include "CClient.h" #include "CEngine.h" #include "CConVarManager.h" #include "U_Networking.h" #include "CBufferWrapper.h" void CClient::Connect(const CEndPoint& srv) { ServerPoint = srv; unsigned short port = Networking::ClientPort; COMPONENT_CALL_GET(port, CConVarManager, GetConVarValue("net.clientport", Networking::ClientPort)); Transceiver = std::make_unique(port); Transceiver->Queue.Enabled = true; Transceiver->SetInverseFilter(true); Transceiver->SetPeerProperty(ServerPoint, CPeerProperty::CType::Allow, CPeerProperty::CType::Allow); Log::Instance() << "Connecting to " << ServerPoint.address().to_string() << ":" << ServerPoint.port() << "\n"; Transceiver->StartAsync(); SendConnectionCookie(); } void CClient::Connect(const std::string& hostname) { CEndPoint endpoint; bool success = Networking::ParseEndpoint(endpoint, Transceiver->IoContext, hostname, Networking::HostPort); if(!success) { Log::ErrInstance() << "Couldn't parse hostname \"" << hostname << "\"\n"; return Reset(); } return Connect(endpoint); } void CClient::SendReliableMessage(std::shared_ptr msg) { NetMessagesManager.SendReliable(msg); } void CClient::SendUnreliableMessage(std::shared_ptr msg) { NetMessagesManager.SendUnreliable(msg); } void CClient::SetServerRate(double timesPerSecond) { m_svRate = timesPerSecond; Log::Instance() << "Set server rate to " << m_svRate << Log::Endl; } double CClient::GetServerRate() const { return m_svRate; } void CClient::V_Update() { if(!Transceiver) { return; } std::vector packets; { std::lock_guard _lock(Transceiver->Queue.Mutex); packets.swap(Transceiver->Queue.Container); } for(auto& pack : packets) { ProcessDatagram(pack.From, pack.Data, pack.ReceivedAt); if(pack.ReceivedAt > LastPacket) { LastPacket = pack.ReceivedAt; } } std::uint32_t maxAttempts = 3; std::uint32_t timeout = 10000; COMPONENT_CALL_GET(maxAttempts, CConVarManager, GetConVarValue("net.retries", 3)); COMPONENT_CALL_GET(timeout, CConVarManager, GetConVarValue("net.connection_timeout", 10000)); auto diff = CEngine::GetInstance()->Time.GetCurrent() - Transceiver->GetLastSendTime(); if(packets.empty() && SentCookie && !Authorized && diff >= std::chrono::milliseconds(timeout)) { if(ConnectionAttempts <= maxAttempts) { SentCookie = false; SendConnectionCookie(); Log::Instance() << "Retrying...\n"; } else { Disconnected = true; Log::ErrInstance() << "Connection timed out\n"; } } if(Authorized) { NetMessagesManager.ProcessPackets(); NetMessagesManager.ProcessMessages(); //Log::Instance() << "CL PROCESS\n"; } if(Disconnected) { Reset(); } else { std::vector snapshot; if(NetMessagesManager.PackSnapshot(snapshot)) { //Log::Instance() << "CL SENT SNAPSHOT\n"; Transceiver->SendAsync(ServerPoint, snapshot); } } } void CClient::ProcessDatagram(boost::asio::ip::udp::endpoint point, std::vector& buffer, CTimePoint ptime) { //Log::Instance() << "[CL] There's a datagram from " << point.address().to_string() << ":" << point.port() << Log::Endl; CBufferWrapper packet(buffer); if(!Authorized) { auto answer_string = packet.ReadLenString(); if(answer_string == "EngineGL 5.0 Connection Accepted") { std::vector cl_answer_buf; CBufferWrapper cl_answer(cl_answer_buf); cl_answer.WriteLenString("EngineGL 5.0 Ready For Transmit"); Transceiver->SendAsync(ServerPoint, cl_answer_buf, [this](boost::system::error_code ec, std::size_t bs, CTimePoint tp) { Authorized = true; Log::Instance() << "[CL] I'm authorized!\n"; }); } else { auto reason_string_u16 = packet.ReadLenString(); auto reason_string = StringUtils::U16ToWstr(reason_string_u16); Log::ErrInstance() << "Couldn't connect with reason of \"" << reason_string << "\"\n"; Disconnected = true; } } else { HandleServerPacket(buffer, ptime); } } void CClient::HandleServerPacket(std::vector& buffer, CTimePoint ptime) { NetMessagesManager.AddReceivedPacket(std::move(buffer), ptime); } void CClient::SendConnectionCookie() { std::wstring nickname = L"player"; COMPONENT_CALL_GET(nickname, CConVarManager, GetConVarValue("cl.nickname")); std::vector cookie_buf; CBufferWrapper cookie(cookie_buf); cookie.WriteLenString("EngineGL 5.0 Connection Cookie"); cookie.WriteLenString(StringUtils::WstrToU16(nickname)); Transceiver->SendAsync(ServerPoint, cookie_buf, [this](boost::system::error_code ec, std::size_t bs, CTimePoint tp) { SentCookie = true; ConnectionAttempts++; }); } void CClient::Reset() { ServerPoint = {}; NetMessagesManager = {}; Authorized = false; Disconnected = false; SentCookie = false; ConnectionAttempts = 0; Transceiver.reset(); } LINK_COMPONENT_TO_CLASS(CClient, client);