Ack Cut 3: a direct send behind a queued packet is refused and takes no sequence

The FIFO test now also pins the single-packet send's refusal while an earlier
packet waits in the queue, in Rust, C#, TypeScript and Python.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-30 00:57:21 +02:00
commit 4f13eb6689
4 changed files with 13 additions and 0 deletions

View file

@ -963,6 +963,10 @@ class CultNetTests(unittest.TestCase):
g = self._flow_send(sender, 1)[0]
self.assertEqual(len(self._flow_send(sender, 3 * self.MIB)), 1)
self.assertEqual(len(self._flow_send(sender, 2 * self.MIB)), 0)
# A direct send refuses instead of queueing behind it, and takes no sequence.
with self.assertRaises(ValueError):
sender.send("state", bytes(1), CultNetRudpSendOptions(reliable=True))
self.assertEqual(sender.queued_reliable_packet_count, 1)
# One byte would fit above g, but the 2 MiB packet is ahead of it.
self.assertEqual(len(self._flow_send(sender, 1)), 0)
promoted = sender.receive(self._flow_ack(g.sequence), 1).ready_to_send

View file

@ -164,6 +164,9 @@ fn a_small_packet_does_not_overtake_a_queued_large_one() -> Result<()> {
let g = send(&mut sender, 1)?.remove(0);
assert_eq!(send(&mut sender, 3 * MIB)?.len(), 1);
assert!(send(&mut sender, 2 * MIB)?.is_empty());
// A direct send refuses instead of queueing behind it, and takes no sequence.
assert!(sender.send("state", vec![7], reliable()).is_err());
assert_eq!(sender.queued_reliable_packet_count(), 1);
// One byte would fit above g, but the 2 MiB packet is ahead of it.
assert!(send(&mut sender, 1)?.is_empty());
let promoted = sender.receive(&ack_for(g.sequence), 1)?.ready_to_send;

View file

@ -1503,6 +1503,9 @@ test("a small packet does not overtake a queued large one", () => {
const g = flowSend(sender, 1)[0]!;
assert.equal(flowSend(sender, 3 * MIB).length, 1);
assert.equal(flowSend(sender, 2 * MIB).length, 0);
// A direct send refuses instead of queueing behind it, and takes no sequence.
assert.throws(() => sender.send("state", new Uint8Array(1), { reliable: true }));
assert.equal(sender.queuedReliablePacketCount, 1);
// One byte would fit above g, but the 2 MiB packet is ahead of it.
assert.equal(flowSend(sender, 1).length, 0);
assert.deepEqual(sequencesOf(sender.receive(flowAck(g.sequence), 1).readyToSend), [g.sequence + 2, g.sequence + 3]);

View file

@ -1268,6 +1268,9 @@ namespace GameCult.Networking.Tests
var g = FlowSend(sender, 1).Single();
Assert.That(FlowSend(sender, 3 * Mib), Has.Count.EqualTo(1));
Assert.That(FlowSend(sender, 2 * Mib), Is.Empty);
// A direct send refuses instead of queueing behind it, and takes no sequence.
Assert.Throws<InvalidOperationException>(() => sender.Send("state", new byte[1], new CultNetRudpSendOptions { Reliable = true }));
Assert.That(sender.QueuedReliablePacketCount, Is.EqualTo(1));
// One byte would fit above g, but the 2 MiB packet is ahead of it.
Assert.That(FlowSend(sender, 1), Is.Empty);
var promoted = sender.Receive(FlowAck(g.Sequence), 1).ReadyToSend;