#include #include #include #include #include #include #include #include #include namespace net { #pragma pack(push, 1) struct ReceivedDatagram { uint32_t number; uint32_t localTime; float posX; float posY; float posZ; float angle; uint8_t pressedButtons; }; struct PlayerDatagramToSend { uint16_t type; uint16_t state; float posX; float posY; float posZ; float angle; float velX; float velY; float velZ; }; struct ServerDatagramToSend { uint32_t number; uint32_t localTime; uint16_t yourType; uint16_t numberOfPlayers; std::array players; }; #pragma pack(pop) } struct ServerPlayerStruct { uint32_t lastReceivedDatagramNumber = 0; uint32_t lastReceivedLocalTime = 0; net::PlayerDatagramToSend clientPlayer; }; using boost::asio::ip::udp; std::map clientMap; std::mutex clientMapMutex; volatile bool quit = false; uint16_t currentTypeIndex = 1; uint32_t currentNumber = 1; ServerPlayerStruct CreateNewPlayer() { ServerPlayerStruct result; result.clientPlayer.type = 0; result.clientPlayer.state = 0; result.clientPlayer.posX = 0; result.clientPlayer.posY = 0; result.clientPlayer.posZ = 0; result.clientPlayer.angle = 0; result.clientPlayer.velX = 0; result.clientPlayer.velY = 0; result.clientPlayer.velZ = 0; result.clientPlayer.type = currentTypeIndex++; return result; } void HandleReceivedData(udp::endpoint& sender, const std::array& datagram) { std::lock_guard lock(clientMapMutex); net::ReceivedDatagram receivedDatagram; std::copy(&datagram[0], &datagram[0] + sizeof(net::ReceivedDatagram), reinterpret_cast(&receivedDatagram)); if (clientMap.count(sender.address()) == 0) { clientMap[sender.address()] = CreateNewPlayer(); } ServerPlayerStruct& currentPlayer = clientMap[sender.address()]; if (receivedDatagram.number <= currentPlayer.lastReceivedDatagramNumber) { return; } currentPlayer.lastReceivedDatagramNumber = receivedDatagram.number; currentPlayer.lastReceivedLocalTime = receivedDatagram.localTime; currentPlayer.clientPlayer.posX = receivedDatagram.posX; currentPlayer.clientPlayer.posY = receivedDatagram.posY; currentPlayer.clientPlayer.posZ = receivedDatagram.posZ; currentPlayer.clientPlayer.angle = currentPlayer.clientPlayer.angle; } void UdpSendTimerHandler(const boost::system::error_code& /*e*/, boost::asio::steady_timer& t, boost::asio::io_context& udpSenderIoContext) { std::lock_guard lock(clientMapMutex); std::array arrayBuffer; arrayBuffer.fill(0); net::ServerDatagramToSend data; data.localTime = 0; data.yourType = 0; data.number = currentNumber++; data.numberOfPlayers = clientMap.size(); uint32_t count = clientMap.size() > 4 ? 4 : clientMap.size(); auto clientMapIterator = clientMap.begin(); for (size_t i = 0; i < count; i++) { data.players[i] = clientMapIterator->second.clientPlayer; clientMapIterator++; } std::cout << "Timer run!!!\n"; for (auto& c : clientMap) { data.yourType = c.second.clientPlayer.type; //std::copy(&arrayBuffer[0], &arrayBuffer[0] + sizeof(net::ServerDatagramToSend), reinterpret_cast(&data)); std::copy(reinterpret_cast(&data), reinterpret_cast(&data) + sizeof(net::ServerDatagramToSend), &arrayBuffer[0]); udp::socket socket(udpSenderIoContext); udp::endpoint remote_endpoint = udp::endpoint(boost::asio::ip::make_address("127.0.0.1"), 14); socket.open(udp::v4()); boost::system::error_code err; auto sent = socket.send_to(boost::asio::buffer(arrayBuffer), remote_endpoint, 0, err); socket.close(); std::cout << "Sent Payload --- " << sent << "\n"; } if (!quit) { t.expires_at(t.expiry() + boost::asio::chrono::milliseconds(50)); t.async_wait(boost::bind(&UdpSendTimerHandler, boost::asio::placeholders::error, boost::ref(t), boost::ref(udpSenderIoContext))); } } class UdpReceiver { public: UdpReceiver(boost::asio::io_context& io_context) : socket_(io_context, udp::endpoint(udp::v4(), 13)) { start_receive(); } private: void start_receive() { socket_.async_receive_from( boost::asio::buffer(recv_buffer_), remote_endpoint_, boost::bind(&UdpReceiver::handle_receive, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } void handle_receive(const boost::system::error_code& error, std::size_t /*bytes_transferred*/) { if (!error) { HandleReceivedData(remote_endpoint_, recv_buffer_); start_receive(); } } void handle_send(boost::shared_ptr /*message*/, const boost::system::error_code& /*error*/, std::size_t /*bytes_transferred*/) { } udp::socket socket_; udp::endpoint remote_endpoint_; std::array recv_buffer_; }; int main() { try { boost::asio::io_context udpSenderIoContext; boost::asio::steady_timer sendTimer(udpSenderIoContext, boost::asio::chrono::milliseconds(50)); sendTimer.async_wait(boost::bind(&UdpSendTimerHandler, boost::asio::placeholders::error, boost::ref(sendTimer), boost::ref(udpSenderIoContext))); std::thread timerThread(boost::bind(&boost::asio::io_context::run, &udpSenderIoContext)); boost::asio::io_context udpReceiverIoContext; UdpReceiver server(udpReceiverIoContext); udpReceiverIoContext.run(); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return 0; }