From: Daniel Karbach Date: Thu, 5 Nov 2015 13:20:13 +0000 (+0100) Subject: decrease packet frequency X-Git-Url: http://git.localhorst.tv/?a=commitdiff_plain;h=56069d41c1553d87a8759713ef391d3a908adc0e;hp=da06ac178d2c083249f8cb2b2c0bef799c079cfd;p=blank.git decrease packet frequency --- diff --git a/src/net/CongestionControl.hpp b/src/net/CongestionControl.hpp index 7d4baca..76f98f6 100644 --- a/src/net/CongestionControl.hpp +++ b/src/net/CongestionControl.hpp @@ -23,6 +23,8 @@ public: Mode GetMode() const noexcept { return mode; } /// according to current mode, drop this many unimportant packets unsigned int SuggestedPacketSkip() const noexcept { return (1 << mode) - 1; } + /// according to current mode, pause between large uncritical packets for this many ticks + unsigned int SuggestedPacketHold() const noexcept { return (1 << (mode + 1)) - 1; } /// packet loss as factor float PacketLoss() const noexcept { return packet_loss; } @@ -45,6 +47,7 @@ private: void UpdateRTT(std::uint16_t) noexcept; bool SamplePacket(std::uint16_t) const noexcept; + std::size_t SampleIndex(std::uint16_t) const noexcept; void UpdateStats() noexcept; @@ -64,7 +67,6 @@ private: float packet_loss; Uint32 stamps[16]; - std::size_t stamp_cursor; std::uint16_t stamp_last; float rtt; diff --git a/src/net/Packet.hpp b/src/net/Packet.hpp index 97b76c8..7dede0d 100644 --- a/src/net/Packet.hpp +++ b/src/net/Packet.hpp @@ -206,6 +206,10 @@ struct Packet { static constexpr std::size_t MAX_LEN = MAX_PAYLOAD_LEN; static constexpr std::size_t MAX_DATA_LEN = MAX_LEN - 12; + static constexpr std::size_t GetSize(std::size_t data_len) noexcept { + return data_len + 12; + } + void WriteTransmissionId(std::uint32_t) noexcept; void ReadTransmissionId(std::uint32_t &) const noexcept; void WriteDataOffset(std::uint32_t) noexcept; diff --git a/src/net/net.cpp b/src/net/net.cpp index 2e202e0..7de901e 100644 --- a/src/net/net.cpp +++ b/src/net/net.cpp @@ -41,7 +41,6 @@ CongestionControl::CongestionControl() , packets_lost(0) , packets_received(0) , packet_loss(0.0f) -, stamp_cursor(15) , stamp_last(0) , rtt(64.0f) , next_sample(1000) @@ -50,11 +49,11 @@ CongestionControl::CongestionControl() , tx_kbps(0.0f) , rx_kbps(0.0f) , mode(GOOD) -// rtt > 100ms or packet loss > 5% is BAD -, bad_rtt(100.0f) +// rtt > 75ms or packet loss > 5% is BAD +, bad_rtt(75.0f) , bad_loss(0.05f) -// rtt > 250ms or packet loss > 15% is UGLY -, ugly_rtt(250.0f) +// rtt > 150ms or packet loss > 15% is UGLY +, ugly_rtt(150.0f) , ugly_loss(0.15f) , mode_keep_time(1000) { Uint32 now = SDL_GetTicks(); @@ -71,8 +70,7 @@ void CongestionControl::PacketSent(uint16_t seq) noexcept { if (!SamplePacket(seq)) { return; } - stamp_cursor = (stamp_cursor + 1) % 16; - stamps[stamp_cursor] = SDL_GetTicks(); + stamps[SampleIndex(seq)] = SDL_GetTicks(); stamp_last = seq; } @@ -97,22 +95,25 @@ void CongestionControl::UpdatePacketLoss() noexcept { } } -void CongestionControl::UpdateRTT(std::uint16_t seq) noexcept { +void CongestionControl::UpdateRTT(uint16_t seq) noexcept { if (!SamplePacket(seq)) return; - int16_t diff = int16_t(seq) - int16_t(stamp_last); - diff /= sample_skip; - if (diff > 0 || diff < -15) { - // packet outside observed time frame + int16_t diff = int16_t(stamp_last) - int16_t(seq); + if (diff < 0 || diff > int(15 * sample_skip)) { + // packet outside observed frame return; } - int cur_rtt = SDL_GetTicks() - stamps[(stamp_cursor + diff + 16) % 16]; + int cur_rtt = SDL_GetTicks() - stamps[SampleIndex(seq)]; rtt += (cur_rtt - rtt) * 0.1f; } -bool CongestionControl::SamplePacket(std::uint16_t seq) const noexcept { +bool CongestionControl::SamplePacket(uint16_t seq) const noexcept { return seq % sample_skip == 0; } +size_t CongestionControl::SampleIndex(uint16_t seq) const noexcept { + return (seq / sample_skip) % 16; +} + void CongestionControl::PacketIn(const UDPpacket &pack) noexcept { rx_bytes += pack.len + packet_overhead; UpdateStats(); @@ -197,7 +198,9 @@ CongestionControl::Mode CongestionControl::Conditions() const noexcept { Connection::Connection(const IPaddress &addr) : handler(nullptr) , addr(addr) -, send_timer(500) +// make sure a packet is sent at least every 50ms since packets contains +// acks that the remote end will use to measure RTT +, send_timer(50) , recv_timer(10000) , ctrl_out{ 0, 0xFFFF, 0xFFFFFFFF } , ctrl_in{ 0, 0xFFFF, 0xFFFFFFFF } diff --git a/src/server/ClientConnection.hpp b/src/server/ClientConnection.hpp index 16beccf..bd42241 100644 --- a/src/server/ClientConnection.hpp +++ b/src/server/ClientConnection.hpp @@ -46,7 +46,7 @@ public: } /// send the previously prepared packet std::uint16_t Send(); - /// send the previously prepared packet of non-default length + /// send the previously prepared packet of given payload length std::uint16_t Send(std::size_t len); void AttachPlayer(Player &); @@ -85,12 +85,13 @@ private: void On(const Packet::PlayerUpdate &) override; void On(const Packet::Message &) override; + void CheckEntities(); bool CanSpawn(const Entity &) const noexcept; bool CanDespawn(const Entity &) const noexcept; void SendSpawn(SpawnStatus &); void SendDespawn(SpawnStatus &); - /// true if updates are pushed to the client this frame + /// true if entity updates are pushed to the client this frame bool SendingUpdates() const noexcept; void QueueUpdate(SpawnStatus &); void SendUpdates(); @@ -118,6 +119,7 @@ private: ChunkTransmitter transmitter; std::deque chunk_queue; glm::ivec3 old_base; + unsigned int chunk_blocks_skipped; }; diff --git a/src/server/net.cpp b/src/server/net.cpp index 38266d7..47342ff 100644 --- a/src/server/net.cpp +++ b/src/server/net.cpp @@ -162,7 +162,7 @@ void ChunkTransmitter::SendData(size_t i) { if (data_packets[i] == -1) { ++confirm_wait; } - data_packets[i] = conn.Send(); + data_packets[i] = conn.Send(Packet::ChunkData::GetSize(len)); } void ChunkTransmitter::Release() { @@ -188,7 +188,8 @@ ClientConnection::ClientConnection(Server &server, const IPaddress &addr) , old_actions(0) , transmitter(*this) , chunk_queue() -, old_base() { +, old_base() +, chunk_blocks_skipped(0) { conn.SetHandler(this); } @@ -202,58 +203,60 @@ void ClientConnection::Update(int dt) { return; } if (HasPlayer()) { - // sync entities - auto global_iter = server.GetWorld().Entities().begin(); - auto global_end = server.GetWorld().Entities().end(); - auto local_iter = spawns.begin(); - auto local_end = spawns.end(); - - while (global_iter != global_end && local_iter != local_end) { - if (global_iter->ID() == local_iter->entity->ID()) { - // they're the same - if (CanDespawn(*global_iter)) { - SendDespawn(*local_iter); - } else if (SendingUpdates()) { - // update - QueueUpdate(*local_iter); - } - ++global_iter; - ++local_iter; - } else if (global_iter->ID() < local_iter->entity->ID()) { - // global entity was inserted - if (CanSpawn(*global_iter)) { - auto spawned = spawns.emplace(local_iter, *global_iter); - SendSpawn(*spawned); - } - ++global_iter; - } else { - // global entity was removed + CheckPlayerFix(); + CheckChunkQueue(); + CheckEntities(); + SendUpdates(); + } + if (conn.ShouldPing()) { + conn.SendPing(server.GetPacket(), server.GetSocket()); + } +} + +void ClientConnection::CheckEntities() { + auto global_iter = server.GetWorld().Entities().begin(); + auto global_end = server.GetWorld().Entities().end(); + auto local_iter = spawns.begin(); + auto local_end = spawns.end(); + + while (global_iter != global_end && local_iter != local_end) { + if (global_iter->ID() == local_iter->entity->ID()) { + // they're the same + if (CanDespawn(*global_iter)) { SendDespawn(*local_iter); - ++local_iter; + } else if (SendingUpdates()) { + // update + QueueUpdate(*local_iter); } - } - - // leftover spawns - while (global_iter != global_end) { + ++global_iter; + ++local_iter; + } else if (global_iter->ID() < local_iter->entity->ID()) { + // global entity was inserted if (CanSpawn(*global_iter)) { - spawns.emplace_back(*global_iter); - SendSpawn(spawns.back()); + auto spawned = spawns.emplace(local_iter, *global_iter); + SendSpawn(*spawned); } ++global_iter; - } - - // leftover despawns - while (local_iter != local_end) { + } else { + // global entity was removed SendDespawn(*local_iter); ++local_iter; } - SendUpdates(); + } - CheckPlayerFix(); - CheckChunkQueue(); + // leftover spawns + while (global_iter != global_end) { + if (CanSpawn(*global_iter)) { + spawns.emplace_back(*global_iter); + SendSpawn(spawns.back()); + } + ++global_iter; } - if (conn.ShouldPing()) { - conn.SendPing(server.GetPacket(), server.GetSocket()); + + // leftover despawns + while (local_iter != local_end) { + SendDespawn(*local_iter); + ++local_iter; } } @@ -311,7 +314,7 @@ void ClientConnection::SendDespawn(SpawnStatus &status) { } bool ClientConnection::SendingUpdates() const noexcept { - return entity_updates_skipped >= NetStat().SuggestedPacketSkip(); + return entity_updates_skipped >= NetStat().SuggestedPacketHold(); } void ClientConnection::QueueUpdate(SpawnStatus &status) { @@ -399,13 +402,14 @@ void ClientConnection::CheckChunkQueue() { old_base = PlayerChunks().Base(); sort(chunk_queue.begin(), chunk_queue.end(), QueueCompare(old_base)); } - // if we have packet skip enabled and just pushed an entity - // update, don't also send chunk data - if (NetStat().SuggestedPacketSkip() > 0 && entity_updates_skipped == 0) { + // don't push entity updates and chunk data in the same tick + if (chunk_blocks_skipped >= NetStat().SuggestedPacketHold() && !SendingUpdates()) { + ++chunk_blocks_skipped; return; } if (transmitter.Transmitting()) { transmitter.Transmit(); + chunk_blocks_skipped = 0; return; } if (transmitter.Idle()) { @@ -418,6 +422,7 @@ void ClientConnection::CheckChunkQueue() { Chunk *chunk = PlayerChunks().Get(pos); if (chunk) { transmitter.Send(*chunk); + chunk_blocks_skipped = 0; return; } else { chunk_queue.push_back(pos);