Bind reliable windows to the RUDP ACK horizon

This commit is contained in:
Meta Vens 2026-08-23 18:54:18 +02:00
commit a2e3d3fa35
7 changed files with 16 additions and 7 deletions

View file

@ -258,7 +258,7 @@ Current progress:
echo against C#/Kotlin/Python/Rust UDP peers; local runtime tests prove timeout
state transitions.
- TypeScript, C#, Rust, Python, and Kotlin now share bounded reliable-send
backpressure for RUDP sessions. At most 64 reliable packets are admitted to
backpressure for RUDP sessions. At most 32 reliable packets are admitted to
the wire at once; later fragments remain in a session-owned FIFO and exact
acknowledgements promote the next packets. This keeps the send frontier well
inside the 4,096-sequence receive history instead of blasting an entire large

View file

@ -396,7 +396,7 @@ def create_rudp_transport_profile(
class CultNetRudpSession:
RELIABLE_SEND_WINDOW_PACKETS = 64
RELIABLE_SEND_WINDOW_PACKETS = 32
RECEIVED_SEQUENCE_WINDOW = 4_096
def __init__(self, options: CultNetRudpSessionOptions) -> None:

View file

@ -2621,7 +2621,7 @@ private data class FragmentBuffer(
class CultNetRudpSession(options: CultNetRudpSessionOptions) {
companion object {
const val ReliableSendWindowPackets = 64
const val ReliableSendWindowPackets = 32
private const val ReceivedSequenceWindow = 4_096
}

View file

@ -29,7 +29,7 @@ const RUDP_MAGIC: [u8; 4] = [0x43, 0x4e, 0x52, 0x30];
const RUDP_VERSION: u8 = 0;
const RUDP_FIXED_HEADER_BYTES: usize = 36;
pub const CULTNET_RUDP_DEFAULT_MAX_PAYLOAD_BYTES: usize = 16 * 1024 * 1024;
pub const CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS: usize = 64;
pub const CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS: usize = 32;
const RUDP_RECEIVED_SEQUENCE_WINDOW: usize = 4_096;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]

View file

@ -68,6 +68,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration as StdDuration;
use std::time::Instant as StdInstant;
const TS_HELLO_FRAME: &[u8] = include_bytes!("fixtures/cultnet-ts-hello.frame");
const TS_LEGACY_LOGIN_FRAME: &[u8] = include_bytes!("fixtures/cultnet-ts-legacy-login.frame");
@ -1370,7 +1371,15 @@ fn rudp_socket_flush_waits_for_large_fragment_delivery() -> Result<()> {
CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS + 17
);
let server_worker = thread::spawn(move || receive_rudp_frame(&mut server));
let server_worker = thread::spawn(move || -> Result<CultNetTransportFrame> {
let delivered = receive_rudp_frame(&mut server)?;
let linger_deadline = StdInstant::now() + StdDuration::from_millis(250);
while StdInstant::now() < linger_deadline {
let _ = server.receive_once()?;
server.poll_resends()?;
}
Ok(delivered)
});
client.flush_reliable(StdDuration::from_secs(5))?;
let delivered = server_worker
.join()

View file

@ -16,7 +16,7 @@ const RUDP_MAGIC = [0x43, 0x4e, 0x52, 0x30] as const; // CNR0
const RUDP_VERSION = 0;
const RUDP_FIXED_HEADER_BYTES = 36;
const MAX_CHANNEL_ID_BYTES = 255;
export const CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS = 64;
export const CULTNET_RUDP_RELIABLE_SEND_WINDOW_PACKETS = 32;
const RUDP_RECEIVED_SEQUENCE_WINDOW = 4_096;
export type CultNetRudpPacketType =

View file

@ -870,7 +870,7 @@ namespace GameCult.Networking
public sealed class CultNetRudpSession
{
/// <summary>Maximum reliable packets admitted to the wire before acknowledgements advance the window.</summary>
public const int ReliableSendWindowPackets = 64;
public const int ReliableSendWindowPackets = 32;
private const int ReceivedSequenceWindow = 4096;
private sealed class PendingReliablePacket
{