From 2247dd3dc7e3cfc1b91e3af5249e5fb3eded3672 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gustaf=20Alh=C3=A4ll?= <gustaf@hanicef.me>
Date: Mon, 13 Jan 2025 19:51:29 +0100
Subject: [PATCH] Ensure all acks are responded to

---
 src/netcode/d_net.c | 130 +++++++++++++++++++++++---------------------
 1 file changed, 69 insertions(+), 61 deletions(-)

diff --git a/src/netcode/d_net.c b/src/netcode/d_net.c
index 4860d8688b..6e6e95674f 100644
--- a/src/netcode/d_net.c
+++ b/src/netcode/d_net.c
@@ -307,6 +307,52 @@ static void RemoveAck(INT32 i)
 		Net_CloseConnection(node);
 }
 
+static void CreateAckpak(node_t *node)
+{
+	UINT8 hm1; // head - 1
+	boolean change = true;
+
+	// Is a good packet so increment the acknowledge number,
+	// Then search for a "hole" in the queue
+	UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
+	if (!nextfirstack)
+		nextfirstack = 1;
+
+	node->firstacktosend = nextfirstack++;
+	if (!nextfirstack)
+		nextfirstack = 1;
+	hm1 = (UINT8)((node->acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND);
+	while (change)
+	{
+		change = false;
+		for (INT32 i = node->acktosend_tail; i != node->acktosend_head;
+			i = (i+1) % MAXACKTOSEND)
+		{
+			if (cmpack(node->acktosend[i], nextfirstack) <= 0)
+			{
+				if (node->acktosend[i] == nextfirstack)
+				{
+					node->firstacktosend = nextfirstack++;
+					if (!nextfirstack)
+						nextfirstack = 1;
+					change = true;
+				}
+				if (i == node->acktosend_tail)
+				{
+					node->acktosend[node->acktosend_tail] = 0;
+					node->acktosend_tail = (UINT8)((i+1) % MAXACKTOSEND);
+				}
+				else if (i == hm1)
+				{
+					node->acktosend[hm1] = 0;
+					node->acktosend_head = hm1;
+					hm1 = (UINT8)((hm1-1+MAXACKTOSEND) % MAXACKTOSEND);
+				}
+			}
+		}
+	}
+}
+
 // We have got a packet, proceed the ack request and ack return
 static int Processackpak(void)
 {
@@ -331,76 +377,38 @@ static int Processackpak(void)
 	{
 		UINT8 ack = netbuffer->ack;
 		getackpacket++;
-		if (cmpack(ack, node->firstacktosend) <= 0)
-		{
-			DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
-			duppacket++;
-			goodpacket = 1; // Discard packet (duplicate)
-		}
-		else
-		{
-			// Check if it is not already in the queue
-			for (INT32 i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
-				if (node->acktosend[i] == ack)
-				{
-					DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
-					duppacket++;
-					goodpacket = 1; // Discard packet (duplicate)
-					break;
-				}
-			if (goodpacket == 0)
+		// Check if it is not already in the queue
+		for (INT32 i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
+			if (node->acktosend[i] == ack)
 			{
-				// Is a good packet so increment the acknowledge number,
-				// Then search for a "hole" in the queue
-				UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
-				if (!nextfirstack)
-					nextfirstack = 1;
+				DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
+				duppacket++;
+				goodpacket = 1; // Discard packet (duplicate)
+				break;
+			}
 
-				if (ack == nextfirstack)
+		if (goodpacket == 0)
+		{
+			if (cmpack(ack, node->firstacktosend) <= 0)
+			{
+				// even if this is a duplicate packet, register it in acktosend so we can respond to it
+				CreateAckpak(node);
+				DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
+				duppacket++;
+				goodpacket = 1; // Discard packet (duplicate)
+			}
+			else
+			{
+				if (ack == node->firstacktosend + 1)
 				{
-					UINT8 hm1; // head - 1
-					boolean change = true;
-
-					node->firstacktosend = nextfirstack++;
-					if (!nextfirstack)
-						nextfirstack = 1;
-					hm1 = (UINT8)((node->acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND);
-					while (change)
-					{
-						change = false;
-						for (INT32 i = node->acktosend_tail; i != node->acktosend_head;
-							i = (i+1) % MAXACKTOSEND)
-						{
-							if (cmpack(node->acktosend[i], nextfirstack) <= 0)
-							{
-								if (node->acktosend[i] == nextfirstack)
-								{
-									node->firstacktosend = nextfirstack++;
-									if (!nextfirstack)
-										nextfirstack = 1;
-									change = true;
-								}
-								if (i == node->acktosend_tail)
-								{
-									node->acktosend[node->acktosend_tail] = 0;
-									node->acktosend_tail = (UINT8)((i+1) % MAXACKTOSEND);
-								}
-								else if (i == hm1)
-								{
-									node->acktosend[hm1] = 0;
-									node->acktosend_head = hm1;
-									hm1 = (UINT8)((hm1-1+MAXACKTOSEND) % MAXACKTOSEND);
-								}
-							}
-						}
-					}
+					CreateAckpak(node);
 				}
 				else // Out of order packet
 				{
 					// Don't increment firsacktosend, put it in asktosend queue
 					// Will be incremented when the nextfirstack comes (code above)
 					UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND);
-					DEBFILE(va("out of order packet (%d expected)\n", nextfirstack));
+					DEBFILE(va("out of order packet (%d expected)\n", node->firstacktosend + 1));
 					if (newhead != node->acktosend_tail)
 					{
 						node->acktosend[node->acktosend_head] = ack;
-- 
GitLab