From 65f36973cfe3c5fb56ae84bb22225be1f28ab9b9 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Wed, 9 Sep 2026 23:07:17 +0200 Subject: [PATCH] feat: build out Transport --- core/src/Transport.cpp | 84 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/core/src/Transport.cpp b/core/src/Transport.cpp index 669a3dd..d5e8be6 100644 --- a/core/src/Transport.cpp +++ b/core/src/Transport.cpp @@ -482,3 +482,87 @@ bool Transport::buildDatagram(Datagram& out) { unreliable.dropOutgoing(); } + return !out.fragments.empty(); +} + +void Transport::flush(uint64_t tick) { + for (std::size_t i = 0; i < inFlight.size();) { + if (tick - inFlight[i].sentTick < config.retransmitTimeoutTicks) { + ++i; + continue; + } + ++statistics.datagramsLost; + for (uint64_t key : inFlight[i].reliableKeys) { + if (reliable.fragment(key) == nullptr) continue; + reliable.markLost(key); + ++statistics.retransmitted; + } + inFlight.erase(inFlight.begin() + static_cast(i)); + } + + bool sentAnything = false; + while (inFlight.size() < config.sendWindow) { + Datagram datagram; + if (!buildDatagram(datagram)) break; + + datagram.sequence = nextSequence++; + datagram.ackLatest = remoteLatest; + datagram.ackHistory = remoteHistory; + datagram.ackValid = anyReceived; + + InFlightDatagram record; + record.sequence = datagram.sequence; + record.sentTick = tick; + for (const Datagram::Fragment& piece : datagram.fragments) + if (piece.reliable) + record.reliableKeys.push_back( + ReliableChannel::fragmentKey(piece.messageId, piece.fragmentIndex)); + inFlight.push_back(std::move(record)); + + ByteWriter writer; + datagram.encode(writer); + ++statistics.datagramsSent; + statistics.bytesSent += writer.size(); + link->send(endpoint, writer.bytes(), tick); + sentAnything = true; + } + + // A pure ack keeps the peer's window moving when traffic is one-directional. + // It carries no fragments, so it cannot itself provoke another ack. + if (!sentAnything && ackPending) { + Datagram datagram; + datagram.sequence = nextSequence++; + datagram.ackLatest = remoteLatest; + datagram.ackHistory = remoteHistory; + datagram.ackValid = anyReceived; + ByteWriter writer; + datagram.encode(writer); + ++statistics.datagramsSent; + statistics.bytesSent += writer.size(); + link->send(endpoint, writer.bytes(), tick); + } + ackPending = false; +} + +void Transport::update(uint64_t tick) { + pump(tick); + flush(tick); +} + +bool Transport::popReliable(ByteBuffer& out) { + if (!reliable.popDelivered(out)) return false; + ++statistics.messagesDelivered; + return true; +} + +bool Transport::popUnreliable(ByteBuffer& out) { + if (!unreliable.popDelivered(out)) return false; + ++statistics.messagesDelivered; + return true; +} + +std::size_t Transport::pendingOutgoingCount() const { + return reliable.readyFragmentCount() + unreliable.outgoingFragmentCount(); +} + +} // namespace vf