From c7718dea79c0ea13acbf2131b845c5e839e70c86 Mon Sep 17 00:00:00 2001 From: Alug Date: Fri, 23 May 2025 16:40:38 +0200 Subject: [PATCH 01/15] fixup! i_tcp technically make ipv6 work,, but its disabled by default --- src/i_tcp.c | 94 +++++++++++++++++++++++++++++++++++++++++------------ src/mserv.h | 4 +++ 2 files changed, 77 insertions(+), 21 deletions(-) diff --git a/src/i_tcp.c b/src/i_tcp.c index 8151abce0..eb882f9b6 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -371,8 +371,16 @@ static inline void I_UPnP_rem(const char *port, const char * servicetype) static const char *SOCK_AddrToStr(mysockaddr_t *sk) { - static char s[64]; // 255.255.255.255:65535 or IPv6:65535 + static char s[64]; // 255.255.255.255:65535 or + // [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535 + #ifdef HAVE_NTOP +#ifdef HAVE_IPV6 + int v6 = (sk->any.sa_family == AF_INET6); +#else + int v6 = 0; +#endif + void *addr; int e = 0; // save error code so it can't be modified later code and avoid calling WSAGetLastError() more then once @@ -387,14 +395,20 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk) if(addr == NULL) sprintf(s, "No address"); - else if(inet_ntop(sk->any.sa_family, addr, s, sizeof (s)) == NULL) + else if(inet_ntop(sk->any.sa_family, addr, &s[v6], sizeof (s) - v6) == NULL) { e = errno; sprintf(s, "Unknown family type, error #%u: %s", e, strerror(e)); } #ifdef HAVE_IPV6 - else if(sk->any.sa_family == AF_INET6 && sk->ip6.sin6_port != 0) - strcat(s, va(":%d", ntohs(sk->ip6.sin6_port))); + else if(sk->any.sa_family == AF_INET6) + { + s[0] = '['; + strcat(s, "]"); + + if (sk->ip6.sin6_port != 0) + strcat(s, va(":%d", ntohs(sk->ip6.sin6_port))); + } #endif else if(sk->any.sa_family == AF_INET && sk->ip4.sin_port != 0) strcat(s, va(":%d", ntohs(sk->ip4.sin_port))); @@ -486,10 +500,30 @@ static time_t SOCK_GetUnbanTime(size_t ban) } #ifndef NONET + +#ifdef HAVE_IPV6 +static boolean SOCK_cmpipv6(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask) +{ + UINT8 bitmask; + I_Assert(mask <= 128); + if (mask == 0) + mask = 128; + if (memcmp(&a->ip6.sin6_addr.s6_addr, &b->ip6.sin6_addr.s6_addr, mask / 8) != 0) + return false; + if (mask % 8 == 0) + return true; + bitmask = 255 << (mask % 8); + return (a->ip6.sin6_addr.s6_addr[mask / 8] & bitmask) == (b->ip6.sin6_addr.s6_addr[mask / 8] & bitmask); +} +#endif + static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask) { UINT32 bitmask = INADDR_NONE; + if (a->any.sa_family != b->any.sa_family) + return false; + if (mask && mask < 32) bitmask = htonl((UINT32)(-1) << (32 - mask)); @@ -498,13 +532,14 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask) && (b->ip4.sin_port == 0 || (a->ip4.sin_port == b->ip4.sin_port)); #ifdef HAVE_IPV6 else if (b->any.sa_family == AF_INET6) - return memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(b->ip6.sin6_addr)) + return SOCK_cmpipv6(a, b, mask) && (b->ip6.sin6_port == 0 || (a->ip6.sin6_port == b->ip6.sin6_port)); #endif else return false; } + // This is a hack. For some reason, nodes aren't being freed properly. // This goes through and cleans up what nodes were supposed to be freed. /** \warning This function causes the file downloading to stop if someone joins. @@ -659,6 +694,7 @@ static boolean SOCK_Get(void) fromlen = (socklen_t)sizeof(fromaddress); c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0, (void *)&fromaddress, &fromlen); + if (c > 0) { #ifdef USE_STUN @@ -868,11 +904,11 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen unsigned long trueval = true; #endif mysockaddr_t straddr; - struct sockaddr_in sin; - socklen_t len = sizeof(sin); + socklen_t len = sizeof(straddr); if (s == (SOCKET_TYPE)ERRSOCKET) return (SOCKET_TYPE)ERRSOCKET; + #ifdef USE_WINSOCK { // Alam_GBC: disable the new UDP connection reset behavior for Win2k and up #ifdef USE_WINSOCK2 @@ -892,14 +928,12 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen } #endif - straddr.any = *addr; + memcpy(&straddr, addr, addrlen); I_OutputMsg("Binding to %s\n", SOCK_AddrToStr(&straddr)); if (family == AF_INET) { - mysockaddr_t tmpaddr; - tmpaddr.any = *addr ; - if (tmpaddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY)) + if (straddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY)) { opt = true; opts = (socklen_t)sizeof(opt); @@ -924,7 +958,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen #ifdef HAVE_IPV6 else if (family == AF_INET6) { - if (memcmp(addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL + if (memcmp(&straddr.ip6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL { opt = true; opts = (socklen_t)sizeof(opt); @@ -939,7 +973,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen // make it IPv6 ony opt = true; opts = (socklen_t)sizeof(opt); - rc = setsockopt(s, SOL_SOCKET, IPV6_V6ONLY, (char *)&opt, opts); + rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, opts); if (rc <= -1) { e = errno; @@ -969,7 +1003,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen inet_pton(AF_INET6, IPV6_MULTICAST_ADDRESS, &maddr.ipv6mr_multiaddr); maddr.ipv6mr_interface = 0; - rc = setsockopt(s, SOL_SOCKET, IPV6_JOIN_GROUP, (const char *)&maddr, sizeof(maddr)); + rc = setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char *)&maddr, sizeof(maddr)); if (rc <= -1) { e = errno; @@ -1032,7 +1066,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10); } - rc = getsockname(s, (struct sockaddr *)&sin, &len); + rc = getsockname(s, &straddr.any, &len); if (rc != 0) { e = errno; @@ -1040,7 +1074,14 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen I_OutputMsg("getsockname failed: #%u, %s\n", e, strerror(e)); } else - current_port = (UINT16)ntohs(sin.sin_port); + { + if (family == AF_INET) + current_port = (UINT16)ntohs(straddr.ip4.sin_port); +#ifdef HAVE_IPV6 + else if (family == AF_INET6) + current_port = (UINT16)ntohs(straddr.ip6.sin6_port); +#endif + } return s; } @@ -1121,6 +1162,7 @@ static boolean UDP_Socket(void) I_freeaddrinfo(ai); } } + #ifdef HAVE_IPV6 if (b_ipv6) { @@ -1319,12 +1361,13 @@ static boolean SOCK_GetAddr(struct sockaddr_in *sin, const char *address, const { struct my_addrinfo *ai = NULL, *runp, hints; int gaie; + size_t i; if (!port || !port[0]) port = DEFAULTPORT; memset (&hints, 0x00, sizeof (hints)); - hints.ai_flags = 0; + hints.ai_flags = AI_ADDRCONFIG; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; @@ -1343,10 +1386,19 @@ static boolean SOCK_GetAddr(struct sockaddr_in *sin, const char *address, const { while (runp != NULL) { - if (sendto(mysockets[0], NULL, 0, 0, runp->ai_addr, runp->ai_addrlen) == 0) - break; + // test ip address of server + for (i = 0; i < mysocketses; ++i) + { + if (runp->ai_addr->sa_family == myfamily[i]) + { + break; + } + } - runp = runp->ai_next; + if (i >= mysocketses) + runp = runp->ai_next; + else + break; } } @@ -1742,7 +1794,7 @@ boolean I_InitTcpNetwork(void) // server address only in ip if (serverhostname[0]) - { + { CONS_Printf("SERVERNAME: %s\n", serverhostname); COM_BufAddText("connect \""); COM_BufAddText(serverhostname); diff --git a/src/mserv.h b/src/mserv.h index 8142716ef..0b4e09bb8 100644 --- a/src/mserv.h +++ b/src/mserv.h @@ -30,7 +30,11 @@ typedef union typedef struct { msg_header_t header; +#ifndef HAVE_IPV6 char ip[16]; +#else + char ip[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; +#endif char port[8]; char contact[32]; char version[8]; // format is: x.yy.z (like 1.30.2 or 1.31) -- 2.54.0 From 9ad5f5189ca73ea0797020eb7771e5af1aa2e890 Mon Sep 17 00:00:00 2001 From: Alug Date: Fri, 23 May 2025 16:43:02 +0200 Subject: [PATCH 02/15] split portnum retrieval into own function --- src/d_net.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/d_net.c b/src/d_net.c index 0e64205ea..9a5c65121 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -1220,6 +1220,18 @@ static void Internal_FreeNodenum(INT32 nodenum) (void)nodenum; } +static char *I_NetSplitAddress(char *host, char **port) +{ + boolean v4 = (host[0] != '['); + + host = strtok(host, v4 ? ":" : "[]"); + + if (port) + *port = strtok(NULL, ":"); + + return host; +} + SINT8 I_NetMakeNode(const char *hostname) { SINT8 newnode = -1; @@ -1227,20 +1239,14 @@ SINT8 I_NetMakeNode(const char *hostname) if (I_NetMakeNodewPort) { char *localhostname = strdup(hostname); - char *t = localhostname; - const char *port; + char *port; if (!localhostname) return newnode; + // retrieve portnum from address! - strtok(localhostname, ":"); - port = strtok(NULL, ":"); + hostname = I_NetSplitAddress(localhostname, &port); - // remove the port in the hostname as we've it already - while ((*t != ':') && (*t != '\0')) - t++; - *t = '\0'; - - newnode = I_NetMakeNodewPort(localhostname, port); + newnode = I_NetMakeNodewPort(hostname, port); free(localhostname); } return newnode; -- 2.54.0 From 3233df9c6c0987582b7127f1e68cb1f4b058dc59 Mon Sep 17 00:00:00 2001 From: Alug Date: Fri, 23 May 2025 16:43:24 +0200 Subject: [PATCH 03/15] do not resolve ipv4 in curl when using ipv6 --- src/http-mserv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/http-mserv.c b/src/http-mserv.c index 30a6f977d..61db5b103 100644 --- a/src/http-mserv.c +++ b/src/http-mserv.c @@ -220,7 +220,11 @@ HMS_connect (const char *format, ...) curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + +#ifdef HAVE_IPV6 + if (!M_CheckParm("-ipv6")) +#endif + curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); curl_easy_setopt(curl, CURLOPT_TIMEOUT, cv_masterserver_timeout.value); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read); -- 2.54.0 From 877bd640f3a446464eef4d411d73fabd1d3d6f1f Mon Sep 17 00:00:00 2001 From: Alug Date: Fri, 23 May 2025 16:43:52 +0200 Subject: [PATCH 04/15] fix destinationnode check in Processackpak --- src/d_net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_net.c b/src/d_net.c index 9a5c65121..201654802 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -307,7 +307,7 @@ static boolean Processackpak(void) // Search the ackbuffer and free it for (i = 0; i < MAXACKPACKETS; i++) { - if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes + if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode && cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0) { RemoveAck(i); -- 2.54.0 From c3129742c37e263225ce7df3182fb00500fa1065 Mon Sep 17 00:00:00 2001 From: Alug Date: Fri, 23 May 2025 16:44:52 +0200 Subject: [PATCH 05/15] simplify cmpack --- src/d_net.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/d_net.c b/src/d_net.c index 201654802..c930f3cf8 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -209,13 +209,9 @@ static node_t nodes[MAXNETNODES]; // 0 if a = n (mod 256) // >0 if a > b (mod 256) // mnemonic: to use it compare to 0: cmpack(a,b)<0 is "a < b" ... -FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b) +FUNCMATH static inline INT32 cmpack(UINT8 a, UINT8 b) { - register INT32 d = a - b; - - if (d >= 127 || d < -128) - return -d; - return d; + return (SINT8)(a - b); } /** Sets freeack to a free acknum and copies the netbuffer in the ackpak table -- 2.54.0 From 083ddb63965098e83250781b9ec2d6d8c45b3c50 Mon Sep 17 00:00:00 2001 From: Alug Date: Fri, 23 May 2025 16:48:34 +0200 Subject: [PATCH 06/15] Refactor netbuffer out of global namespace https://git.do.srb2.org/Hanicef/SRB2Classic/-/commit/079fd2cef97a9cf22fb5d2b66a9b500914efbc72 + move some things into functions --- src/d_clisrv.c | 429 ++++++++++++++++++++++++++++--------------------- src/d_clisrv.h | 1 - src/d_net.c | 20 ++- src/d_netfil.c | 6 + src/i_net.h | 2 + 5 files changed, 270 insertions(+), 188 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 9625934fc..01cc4f393 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1082,6 +1082,8 @@ static void SV_SendResynch(INT32 node) { INT32 i, j; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + if (!nodeingame[node]) { // player left during resynch @@ -1140,6 +1142,7 @@ static void SV_SendResynch(INT32 node) static void CL_AcknowledgeResynch(resynch_pak *rsp) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); resynch_read_player(rsp); netbuffer->packettype = PT_RESYNCHGET; @@ -1461,6 +1464,7 @@ static inline void CL_DrawConnectionStatus(void) static boolean CL_AskFileList(INT32 firstfile) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); netbuffer->packettype = PT_TELLFILESNEEDED; netbuffer->u.filesneedednum = firstfile; @@ -1480,6 +1484,9 @@ static boolean CL_AskFileList(INT32 firstfile) static boolean CL_SendJoin(void) { UINT8 localplayers = 1; + + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + if (netgame) CONS_Printf(M_GetText("Sending join request...\n")); netbuffer->packettype = PT_CLIENTJOIN; @@ -1576,6 +1583,8 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) ? gametype : cv_kartgametypepreference.value; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + netbuffer->packettype = PT_SERVERINFO; netbuffer->u.serverinfo._255 = 255; netbuffer->u.serverinfo.packetversion = PACKETVERSION; @@ -1683,6 +1692,8 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) static void SV_SendPlayerInfo(INT32 node) { UINT8 i; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + netbuffer->packettype = PT_PLAYERINFO; for (i = 0; i < MSCOMPAT_MAXPLAYERS; i++) @@ -1760,6 +1771,8 @@ static boolean SV_SendServerConfig(INT32 node) UINT8 *p, *op; boolean waspacketsent; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + netbuffer->packettype = PT_SERVERCFG; netbuffer->u.servercfg.version = VERSION; @@ -1964,6 +1977,8 @@ static void CL_LoadReceivedSavegame(boolean reloading) size_t length, decompressedlen; char tmpsave[264]; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); length = FIL_ReadFile(tmpsave, &save.buffer); @@ -2081,6 +2096,8 @@ static void SendAskInfo(INT32 node) asktime = I_GetTime(); + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + netbuffer->packettype = PT_ASKINFO; netbuffer->u.askinfo.version = VERSION; netbuffer->u.askinfo.time = (tic_t)LONG(asktime); @@ -4075,6 +4092,8 @@ static void Command_ResendGamestate(void) { SINT8 playernum; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + if (COM_Argc() == 1) { CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); @@ -4092,6 +4111,7 @@ static void Command_ResendGamestate(void) // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on netbuffer->packettype = PT_WILLRESENDGAMESTATE; + if (!HSendPacket(playernode[playernum], true, 0, 0)) { CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n")); @@ -4343,6 +4363,8 @@ static inline void SV_GenContext(void) // void D_QuitNetGame(void) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + if (!netgame || !netbuffer) return; @@ -4592,6 +4614,7 @@ static boolean SV_AddWaitingPlayers(void) #ifdef SATURNPAK static inline void SendSaturnInfo(INT32 node) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); netbuffer->packettype = PT_ISSATURN; HSendPacket(node, true, 0, 0); } @@ -4684,6 +4707,8 @@ void SV_StartSinglePlayerServer(void) static void SV_SendRefuse(INT32 node, const char *reason) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + strcpy(netbuffer->u.serverrefuse.reason, reason); netbuffer->packettype = PT_SERVERREFUSE; @@ -4724,6 +4749,8 @@ static void HandleConnect(SINT8 node) if (playernode[i] != UINT8_MAX) // We use this to count players because it is affected by SV_AddWaitingPlayers when more than one client joins on the same tic, unlike playeringame and D_NumPlayers. UINT8_MAX denotes no node for that player connectedplayers++; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + if (bannednode && bannednode[node].banid != SIZE_MAX) { const char *reason = NULL; @@ -4899,6 +4926,8 @@ static void HandleTimeout(SINT8 node) static void HandleServerInfo(SINT8 node) { char servername[MAXSERVERNAME]; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + // compute ping in ms const tic_t ticnow = I_GetTime(); const tic_t ticthen = (tic_t)LONG(netbuffer->u.serverinfo.time); @@ -4916,6 +4945,198 @@ static void HandleServerInfo(SINT8 node) if (client && cl_mode > CL_SEARCHING && node == servernode) memcpy(connectedservername, netbuffer->u.serverinfo.servername, MAXSERVERNAME); } + +// Helper function for packets that should only be sent by the server +// If it is NOT from the server, bail out and close the connection! +static boolean ServerOnly(SINT8 node) +{ + if (node == servernode) + return false; + + Net_CloseConnection(node); + return true; +} + +static void PT_TellFilesNeeded(SINT8 node) +{ + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + + if (server && serverrunning) + { + UINT8 *p; + INT32 firstfile = netbuffer->u.filesneedednum; + + netbuffer->packettype = PT_MOREFILESNEEDED; + netbuffer->u.filesneededcfg.first = firstfile; + netbuffer->u.filesneededcfg.more = 0; + + p = PutFileNeeded(firstfile); + + HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); + } + else // Shouldn't get this if you aren't the server...? + Net_CloseConnection(node); +} + +static void PT_MoreFilesNeeded(SINT8 node) +{ + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + + if (server && serverrunning) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + return; + } + + if (ServerOnly(node)) + return; + + if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum) + { + D_ParseFileneeded(netbuffer->u.filesneededcfg.num, netbuffer->u.filesneededcfg.files, netbuffer->u.filesneededcfg.first); + if (!netbuffer->u.filesneededcfg.more) + cl_lastcheckedfilecount = UINT16_MAX; // Got the whole file list + } +} + +// Negative response of client join request +static void PT_ServerRefuse(SINT8 node) +{ + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + + if (server && serverrunning) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + return; + } + + if (ServerOnly(node)) + return; + + if (cl_mode == CL_WAITJOINRESPONSE) + { + // Save the reason so it can be displayed after quitting the netgame + char *reason = strdup(netbuffer->u.serverrefuse.reason); + if (!reason) + I_Error("Out of memory!\n"); + + if (strstr(reason, "Maximum players reached")) + { + serverisfull = true; + //Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer + //We set it back to the value of cv_nettimeout.value in CL_Reset + connectiontimeout = NEWTICRATE*7; + cl_mode = CL_ASKJOIN; + free(reason); + return; + } + + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + + if (reason[1] == '|') + { + M_StartMessage(va("You have been %sfrom the server\n\nReason:\n%s", + (reason[0] == 'B') ? "banned\n" : "temporarily\nkicked ", + reason+2), NULL, MM_NOTHING); + } + else + { + M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), + reason), NULL, MM_NOTHING); + } + + free(reason); + + // Will be reset by caller. Signals refusal. + cl_mode = CL_ABORTED; + } +} + +// Positive response of client join request +static void PT_ServerCFG(SINT8 node) +{ + INT32 j; + UINT8 *scp; + + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + + if (server && serverrunning && node != servernode) + { // but wait I thought I'm the server? + Net_CloseConnection(node); + return; + } + + if (ServerOnly(node)) + return; + + /// \note how would this happen? and is it doing the right thing if it does? + if (!(cl_mode == CL_WAITJOINRESPONSE || cl_mode == CL_ASKJOIN)) + return; + + if (client) + { + maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); + if ((gametype = netbuffer->u.servercfg.gametype) >= NUMGAMETYPES) + I_Error("Bad gametype in cliserv!"); + modifiedgame = netbuffer->u.servercfg.modifiedgame; + for (j = 0; j < MAXPLAYERS; j++) + adminplayers[j] = netbuffer->u.servercfg.adminplayers[j]; + memcpy(server_context, netbuffer->u.servercfg.server_context, 8); + } + +#ifdef HAVE_DISCORDRPC + discordInfo.maxPlayers = netbuffer->u.servercfg.maxplayer; + discordInfo.joinsAllowed = netbuffer->u.servercfg.allownewplayer; + discordInfo.everyoneCanInvite = netbuffer->u.servercfg.discordinvites; +#endif + + nodeingame[(UINT8)servernode] = true; + serverplayer = netbuffer->u.servercfg.serverplayer; + doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum); + mynode = netbuffer->u.servercfg.clientnode; + if (serverplayer >= 0) + playernode[(UINT8)serverplayer] = servernode; + + if (netgame) +#ifdef JOININGAME + CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n")); +#else + CONS_Printf(M_GetText("Join accepted, waiting for next level change...\n")); +#endif + DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); + +#ifdef SATURNPAK + SendSaturnInfo(node); +#endif + memset(playeringame, 0, sizeof(playeringame)); + for (j = 0; j < MAXPLAYERS; j++) + { + if (netbuffer->u.servercfg.playerskins[j] == 0xFF + && netbuffer->u.servercfg.playercolor[j] == 0xFF) + continue; // not in game + + playeringame[j] = true; + SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]); + players[j].skincolor = netbuffer->u.servercfg.playercolor[j]; + } + + scp = netbuffer->u.servercfg.varlengthinputs; + CV_LoadPlayerNames(&scp); + CV_LoadNetVars(&scp); +#ifdef JOININGAME + /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? + /// Shouldn't them be downloaded even at intermission time? + /// Also, according to HandleConnect, the server will send the savegame even during intermission... + /// Sryder 2018-07-05: If we don't want to send the player config another way we need to send the gamestate + /// At almost any gamestate there could be joiners... So just always send gamestate? + cl_mode = ((server) ? CL_CONNECTED : CL_DOWNLOADSAVEGAME); +#else + cl_mode = CL_CONNECTED; +#endif +} + #endif #ifdef SATURNPAK @@ -4926,6 +5147,8 @@ static void PT_WillResendGamestate(void) if (server || cl_redownloadinggamestate) return; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + // Send back a PT_CANRECEIVEGAMESTATE packet to the server // so they know they can start sending the game state netbuffer->packettype = PT_CANRECEIVEGAMESTATE; @@ -4969,75 +5192,20 @@ static void HandlePacketFromAwayNode(SINT8 node) if (node != servernode) DEBFILE(va("Received packet from unknown host %d\n", node)); -// macro for packets that should only be sent by the server -// if it is NOT from the server, bail out and close the connection! -#define SERVERONLY \ - if (node != servernode) \ - { \ - Net_CloseConnection(node); \ - break; \ - } + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + switch (netbuffer->packettype) { case PT_ASKINFOVIAMS: -#if 0 - if (server && serverrunning) - { - INT32 clientnode; - if (ms_RoomId < 0) // ignore if we're not actually on the MS right now - { - Net_CloseConnection(node); // and yes, close connection - return; - } - clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr); - if (clientnode != -1) - { - SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time)); - SV_SendPlayerInfo(clientnode); // Send extra info - Net_CloseConnection(clientnode); - // Don't close connection to MS... - } - else - Net_CloseConnection(node); // ...unless the IP address is not valid - } - else - Net_CloseConnection(node); // you're not supposed to get it, so ignore it -#else Net_CloseConnection(node); -#endif break; case PT_TELLFILESNEEDED: - if (server && serverrunning) - { - UINT8 *p; - INT32 firstfile = netbuffer->u.filesneedednum; - - netbuffer->packettype = PT_MOREFILESNEEDED; - netbuffer->u.filesneededcfg.first = firstfile; - netbuffer->u.filesneededcfg.more = 0; - - p = PutFileNeeded(firstfile); - - HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); - } - else // Shouldn't get this if you aren't the server...? - Net_CloseConnection(node); + PT_TellFilesNeeded(node); break; case PT_MOREFILESNEEDED: - if (server && serverrunning) - { // But wait I thought I'm the server? - Net_CloseConnection(node); - break; - } - SERVERONLY - if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum) - { - D_ParseFileneeded(netbuffer->u.filesneededcfg.num, netbuffer->u.filesneededcfg.files, netbuffer->u.filesneededcfg.first); - if (!netbuffer->u.filesneededcfg.more) - cl_lastcheckedfilecount = UINT16_MAX; // Got the whole file list - } + PT_MoreFilesNeeded(node); break; case PT_ASKINFO: @@ -5050,131 +5218,12 @@ static void HandlePacketFromAwayNode(SINT8 node) break; case PT_SERVERREFUSE: // Negative response of client join request - if (server && serverrunning) - { // But wait I thought I'm the server? - Net_CloseConnection(node); - break; - } - SERVERONLY - if (cl_mode == CL_WAITJOINRESPONSE) - { - // Save the reason so it can be displayed after quitting the netgame - char *reason = strdup(netbuffer->u.serverrefuse.reason); - if (!reason) - I_Error("Out of memory!\n"); - - if (strstr(reason, "Maximum players reached")) - { - serverisfull = true; - //Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer - //We set it back to the value of cv_nettimeout.value in CL_Reset - connectiontimeout = NEWTICRATE*7; - cl_mode = CL_ASKJOIN; - free(reason); - break; - } - - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - - if (reason[1] == '|') - { - M_StartMessage(va("You have been %sfrom the server\n\nReason:\n%s", - (reason[0] == 'B') ? "banned\n" : "temporarily\nkicked ", - reason+2), NULL, MM_NOTHING); - } - else - { - M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), - reason), NULL, MM_NOTHING); - } - - free(reason); - - // Will be reset by caller. Signals refusal. - cl_mode = CL_ABORTED; - } + PT_ServerRefuse(node); break; case PT_SERVERCFG: // Positive response of client join request - { - INT32 j; - UINT8 *scp; - - if (server && serverrunning && node != servernode) - { // but wait I thought I'm the server? - Net_CloseConnection(node); - break; - } - SERVERONLY - /// \note how would this happen? and is it doing the right thing if it does? - if (!(cl_mode == CL_WAITJOINRESPONSE || cl_mode == CL_ASKJOIN)) - break; - - if (client) - { - maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); - if ((gametype = netbuffer->u.servercfg.gametype) >= NUMGAMETYPES) - I_Error("Bad gametype in cliserv!"); - modifiedgame = netbuffer->u.servercfg.modifiedgame; - for (j = 0; j < MAXPLAYERS; j++) - adminplayers[j] = netbuffer->u.servercfg.adminplayers[j]; - memcpy(server_context, netbuffer->u.servercfg.server_context, 8); - } - -#ifdef HAVE_DISCORDRPC - discordInfo.maxPlayers = netbuffer->u.servercfg.maxplayer; - discordInfo.joinsAllowed = netbuffer->u.servercfg.allownewplayer; - discordInfo.everyoneCanInvite = netbuffer->u.servercfg.discordinvites; -#endif - - nodeingame[(UINT8)servernode] = true; - serverplayer = netbuffer->u.servercfg.serverplayer; - doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum); - mynode = netbuffer->u.servercfg.clientnode; - if (serverplayer >= 0) - playernode[(UINT8)serverplayer] = servernode; - - if (netgame) -#ifdef JOININGAME - CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n")); -#else - CONS_Printf(M_GetText("Join accepted, waiting for next level change...\n")); -#endif - DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); - -#ifdef SATURNPAK - SendSaturnInfo(node); -#endif - memset(playeringame, 0, sizeof(playeringame)); - for (j = 0; j < MAXPLAYERS; j++) - { - if (netbuffer->u.servercfg.playerskins[j] == 0xFF - && netbuffer->u.servercfg.playercolor[j] == 0xFF) - continue; // not in game - - playeringame[j] = true; - SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]); - players[j].skincolor = netbuffer->u.servercfg.playercolor[j]; - } - - scp = netbuffer->u.servercfg.varlengthinputs; - CV_LoadPlayerNames(&scp); - CV_LoadNetVars(&scp); -#ifdef JOININGAME - /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? - /// Shouldn't them be downloaded even at intermission time? - /// Also, according to HandleConnect, the server will send the savegame even during intermission... - /// Sryder 2018-07-05: If we don't want to send the player config another way we need to send the gamestate - /// At almost any gamestate there could be joiners... So just always send gamestate? - cl_mode = ((server) ? CL_CONNECTED : CL_DOWNLOADSAVEGAME); -#else - cl_mode = CL_CONNECTED; -#endif + PT_ServerCFG(node); break; - } - // Handled in d_netfil.c case PT_FILEFRAGMENT: if (server) @@ -5182,7 +5231,10 @@ static void HandlePacketFromAwayNode(SINT8 node) Net_CloseConnection(node); break; } - SERVERONLY + + if (ServerOnly(node)) + break; + Got_Filetxpak(); break; @@ -5217,7 +5269,6 @@ static void HandlePacketFromAwayNode(SINT8 node) break; // Ignore it } -#undef SERVERONLY } /** Checks ticcmd for "speed hacks" @@ -5257,6 +5308,8 @@ static void HandlePacketFromPlayer(SINT8 node) txtpak = NULL; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + if (dedicated && node == 0) netconsole = 0; else @@ -5762,6 +5815,8 @@ static void GetPackets(void) { SINT8 node; // The packet sender + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + while (HGetPacket()) { node = (SINT8)doomcom->remotenode; @@ -5976,8 +6031,8 @@ static INT16 Consistancy(void) // used during wipes to tell the server that a node is still connected static void CL_SendClientKeepAlive(void) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); netbuffer->packettype = PT_BASICKEEPALIVE; - HSendPacket(servernode, false, 0, 0); } @@ -5985,6 +6040,8 @@ static void SV_SendServerKeepAlive(void) { INT32 n; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + for (n = 1; n < MAXNETNODES; n++) { if (nodeingame[n]) @@ -6001,6 +6058,8 @@ static void CL_SendClientCmd(void) size_t packetsize = 0; boolean mis = false; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + netbuffer->packettype = PT_CLIENTCMD; if (cl_packetmissed) @@ -6153,6 +6212,8 @@ static void SV_SendTics(void) UINT8 *bufpos; UINT8 *ntextcmd; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + // send to all client but not to me // for each node create a packet with x tics and send it // x is computed using supposedtics[n], max packet size and maketic @@ -6476,6 +6537,8 @@ static inline void PingUpdate(void) memset(pingkick, 0, sizeof(pingkick)); + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + netbuffer->packettype = PT_PING; //check for ping limit breakage. diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 6202c8c52..f735846e6 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -529,7 +529,6 @@ extern UINT32 serverlistultimatecount; extern INT32 mapchangepending; // Points inside doomcom -extern doomdata_t *netbuffer; extern consvar_t cv_stunserver; extern consvar_t cv_httpsource; extern consvar_t cv_kicktime; diff --git a/src/d_net.c b/src/d_net.c index c930f3cf8..aceec8fed 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -48,8 +48,7 @@ tic_t connectiontimeout = (10*TICRATE); /// \brief network packet doomcom_t *doomcom = NULL; -/// \brief network packet data, points inside doomcom -doomdata_t *netbuffer = NULL; + /// \brief hole punching packet, also points inside doomcom #ifdef HOLEPUNCH holepunch_t *holepunchpacket = NULL; @@ -225,6 +224,8 @@ static boolean GetFreeAcknum(UINT8 *freeack) node_t *node = &nodes[doomcom->remotenode]; INT32 i, numfreeslot = 0; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0) { DEBFILE(va("too fast %d %d\n",node->remotefirstack,node->nextacknum)); @@ -294,6 +295,7 @@ static boolean Processackpak(void) INT32 i; boolean goodpacket = true; node_t *node = &nodes[doomcom->remotenode]; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); // Received an ack return, so remove the ack in the list if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0) @@ -419,6 +421,7 @@ void Net_SendAcks(INT32 node) #ifdef NONET (void)node; #else + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); netbuffer->packettype = PT_NOTHING; M_Memcpy(netbuffer->u.textcmd, nodes[node].acktosend, MAXACKTOSEND); HSendPacket(node, false, 0, MAXACKTOSEND); @@ -430,6 +433,8 @@ static void GotAcks(void) { INT32 i, j; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + for (j = 0; j < MAXACKTOSEND; j++) { if (netbuffer->u.textcmd[j]) @@ -483,6 +488,8 @@ void Net_AckTicker(void) #ifndef NONET INT32 i; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + for (i = 0; i < MAXACKPACKETS; i++) { const INT32 nodei = ackpak[i].destinationnode; @@ -538,6 +545,7 @@ void Net_UnAcknowledgePacket(INT32 node) #ifdef NONET (void)node; #else + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); INT32 hm1 = (nodes[node].acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND; DEBFILE(va("UnAcknowledge node %d\n", node)); @@ -732,6 +740,7 @@ void Net_CloseConnection(INT32 node) // static UINT32 NetbufferChecksum(void) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); UINT32 c = 0x1234567; const INT32 l = doomcom->datalength - 4; const UINT8 *buf = (UINT8 *)netbuffer + 4; @@ -848,6 +857,8 @@ const char *Net_GetPacketName(UINT8 packettype) static void DebugPrintpacket(const char *header) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + fprintf(debugfile, "%-12s (node %d,ack %d,ackret %d,size %d) type(%d) : %s\n", header, doomcom->remotenode, netbuffer->ack, netbuffer->ackreturn, doomcom->datalength, netbuffer->packettype, Net_GetPacketName(netbuffer->packettype)); @@ -1017,6 +1028,7 @@ void Command_Droprate(void) #ifndef NONET static boolean ShouldDropPacket(void) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); return (packetdropquantity[netbuffer->packettype]) || (packetdroprate != 0 && rand() < (((double)RAND_MAX) * (packetdroprate / 100.f))) || packetdroprate == 100; } @@ -1028,6 +1040,7 @@ static boolean ShouldDropPacket(void) // boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE); if (node == 0) // Packet is to go back to us @@ -1128,7 +1141,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen // boolean HGetPacket(void) { - //boolean nodejustjoined; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); // Get a packet from self if (rebound_tail != rebound_head) @@ -1334,7 +1347,6 @@ boolean D_CheckNetGame(void) if (doomcom->numnodes > MAXNETNODES) I_Error("Too many nodes (%d), max:%d", doomcom->numnodes, MAXNETNODES); - netbuffer = (doomdata_t *)(void *)&doomcom->data; #ifdef HOLEPUNCH holepunchpacket = (holepunch_t *)(void *)&doomcom->data; #endif diff --git a/src/d_netfil.c b/src/d_netfil.c index 0650f3c34..07401eb46 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -140,6 +140,7 @@ UINT8 *PutFileNeeded(UINT16 firstfile) { size_t i; UINT8 count = 0; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded; UINT8 *p = p_start; char wadfilename[MAX_WADPATH] = ""; @@ -321,6 +322,7 @@ boolean CL_SendRequestFile(void) #ifdef MORELEGACYDOWNLOADER boolean firstloop = true; #endif + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); #ifdef PARANOIA if (M_CheckParm("-nodownload")) @@ -449,9 +451,11 @@ tryagain: // returns false if a requested file was not found or cannot be sent boolean Got_RequestFilePak(INT32 node) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); char wad[MAX_WADPATH+1]; UINT8 *p = netbuffer->u.textcmd; UINT8 id; + while (p < netbuffer->u.textcmd + MAXTEXTCMD) // Don't allow hacked client to overflow { id = READUINT8(p); @@ -815,6 +819,7 @@ void SV_FileSendTicker(void) size_t size; filetx_t *f; INT32 packetsent, ram, i, j; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); if (!filestosend) // No file to send return; @@ -943,6 +948,7 @@ void SV_FileSendTicker(void) void Got_Filetxpak(void) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); INT32 filenum = netbuffer->u.filetxpak.fileid; fileneeded_t *file = &fileneeded[filenum]; char *filename = file->filename; diff --git a/src/i_net.h b/src/i_net.h index 098a6563d..59bcca955 100644 --- a/src/i_net.h +++ b/src/i_net.h @@ -78,6 +78,8 @@ typedef struct char data[MAXPACKETLENGTH]; } ATTRPACK doomcom_t; +#define DOOMCOM_DATA(d) (doomdata_t *)&(d)->data + #ifdef HOLEPUNCH typedef struct { -- 2.54.0 From b04f017ab62991de7f8e0f59a08d75e8bdc4b502 Mon Sep 17 00:00:00 2001 From: Alug Date: Fri, 23 May 2025 16:51:10 +0200 Subject: [PATCH 07/15] change ticqueue system to be more like srb 2.2 mostly just renaming lel --- src/d_clisrv.c | 119 ++++++++++++++++++++++++------------------------- src/d_clisrv.h | 4 +- src/doomstat.h | 2 +- src/g_game.c | 2 +- src/p_setup.c | 2 +- 5 files changed, 63 insertions(+), 66 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 01cc4f393..93c0e82f0 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -142,7 +142,7 @@ static tic_t firstticstosend; // min of the nettics static tic_t tictoclear = 0; // optimize d_clearticcmd static tic_t maketic; -static INT16 consistancy[TICQUEUE]; +static INT16 consistancy[BACKUPTICS]; // Resynching shit! static UINT32 resynch_score[MAXNETNODES]; // "score" for kicking -- if this gets too high then cfail kick @@ -216,7 +216,7 @@ struct textcmdbuf_s static textcmdbuf_t *textcmdbuf[MAXSPLITSCREENPLAYERS] = {NULL}; -ticcmd_t netcmds[TICQUEUE][MAXPLAYERS]; +ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; static textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL}; consvar_t cv_showjoinaddress = {"showjoinaddress", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -528,9 +528,9 @@ static void D_Clearticcmd(tic_t tic) D_FreeTextcmd(tic); for (i = 0; i < MAXPLAYERS; i++) - netcmds[tic%TICQUEUE][i].angleturn = 0; + netcmds[tic%BACKUPTICS][i].angleturn = 0; - DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%TICQUEUE)); + DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS)); } void D_ResetTiccmds(void) @@ -2033,7 +2033,7 @@ static void CL_LoadReceivedSavegame(boolean reloading) save.p = NULL; if (unlink(tmpsave) == -1) CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave); - consistancy[gametic%TICQUEUE] = Consistancy(); + consistancy[gametic%BACKUPTICS] = Consistancy(); CON_ToggleOff(); #ifdef SATURNPAK @@ -2060,8 +2060,7 @@ static void CL_ReloadReceivedSavegame(void) CL_LoadReceivedSavegame(true); - if (neededtic < gametic) - neededtic = gametic; + neededtic = max(neededtic, gametic); maketic = neededtic; // we dont have P_ForceLocalAngle so were setting it manually here @@ -4680,7 +4679,7 @@ void SV_StopServer(void) for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) localtextcmd[i][0] = 0; - for (i = firstticstosend; i < firstticstosend + TICQUEUE; i++) + for (i = firstticstosend; i < firstticstosend + BACKUPTICS; i++) D_Clearticcmd(i); consoleplayer = 0; @@ -5280,9 +5279,9 @@ static void HandlePacketFromAwayNode(SINT8 node) */ static boolean CheckForSpeedHacks(UINT8 p) { - if (netcmds[maketic%TICQUEUE][p].forwardmove > MAXPLMOVE || netcmds[maketic%TICQUEUE][p].forwardmove < -MAXPLMOVE - || netcmds[maketic%TICQUEUE][p].sidemove > MAXPLMOVE || netcmds[maketic%TICQUEUE][p].sidemove < -MAXPLMOVE - || netcmds[maketic%TICQUEUE][p].driftturn > KART_FULLTURN || netcmds[maketic%TICQUEUE][p].driftturn < -KART_FULLTURN) + if (netcmds[maketic%BACKUPTICS][p].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][p].forwardmove < -MAXPLMOVE + || netcmds[maketic%BACKUPTICS][p].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][p].sidemove < -MAXPLMOVE + || netcmds[maketic%BACKUPTICS][p].driftturn > KART_FULLTURN || netcmds[maketic%BACKUPTICS][p].driftturn < -KART_FULLTURN) { CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), playernode[p]); SendKick(p, KICK_MSG_CON_FAIL); @@ -5379,8 +5378,8 @@ static void HandlePacketFromPlayer(SINT8 node) // If we've alredy received a ticcmd for this tic, just submit it for the next one. tic_t faketic = maketic; - if ((!!(netcmds[maketic % TICQUEUE][netconsole].angleturn & TICCMD_RECEIVED)) - && (maketic - firstticstosend < TICQUEUE - 1)) + if ((!!(netcmds[maketic % BACKUPTICS][netconsole].angleturn & TICCMD_RECEIVED)) + && (maketic - firstticstosend < BACKUPTICS - 1)) faketic++; // Don't do anything for packets of type NODEKEEPALIVE? @@ -5390,7 +5389,7 @@ static void HandlePacketFromPlayer(SINT8 node) break; // Copy ticcmd - G_MoveTiccmd(&netcmds[faketic%TICQUEUE][netconsole], &netbuffer->u.clientpak.cmd, 1); + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); // Check ticcmd for "speed hacks" if (CheckForSpeedHacks((UINT8)netconsole)) @@ -5402,7 +5401,7 @@ static void HandlePacketFromPlayer(SINT8 node) || (netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS)) && (nodetoplayer2[node] >= 0)) { - G_MoveTiccmd(&netcmds[faketic%TICQUEUE][(UINT8)nodetoplayer2[node]], + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], &netbuffer->u.client2pak.cmd2, 1); if (CheckForSpeedHacks((UINT8)nodetoplayer2[node])) @@ -5413,7 +5412,7 @@ static void HandlePacketFromPlayer(SINT8 node) || (netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS)) && (nodetoplayer3[node] >= 0)) { - G_MoveTiccmd(&netcmds[faketic%TICQUEUE][(UINT8)nodetoplayer3[node]], + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer3[node]], &netbuffer->u.client3pak.cmd3, 1); if (CheckForSpeedHacks((UINT8)nodetoplayer3[node])) @@ -5423,7 +5422,7 @@ static void HandlePacketFromPlayer(SINT8 node) if ((netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS) && (nodetoplayer4[node] >= 0)) { - G_MoveTiccmd(&netcmds[faketic%TICQUEUE][(UINT8)nodetoplayer4[node]], + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer4[node]], &netbuffer->u.client4pak.cmd4, 1); if (CheckForSpeedHacks((UINT8)nodetoplayer4[node])) @@ -5448,8 +5447,8 @@ static void HandlePacketFromPlayer(SINT8 node) // Check player consistancy during the level if (gamestate == GS_LEVEL - && (realstart > gametic - TICQUEUE+1 && realstart <= gametic) - && consistancy[realstart%TICQUEUE] != SHORT(netbuffer->u.clientpak.consistancy) + && (realstart > gametic - BACKUPTICS+1 && realstart <= gametic) + && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) && (!UseSaturnSynch(node) || (!resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime() && !SV_ResendingSavegameToAnyone()))) { resendingsavegame[node] = false; // reset this before just in case @@ -5480,10 +5479,10 @@ static void HandlePacketFromPlayer(SINT8 node) if (cv_blamecfail.value) CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), netconsole+1, player_names[netconsole], - consistancy[realstart%TICQUEUE], + consistancy[realstart%BACKUPTICS], SHORT(netbuffer->u.clientpak.consistancy)); DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", - netconsole, realstart, consistancy[realstart%TICQUEUE], + netconsole, realstart, consistancy[realstart%BACKUPTICS], SHORT(netbuffer->u.clientpak.consistancy))); break; } @@ -5491,7 +5490,7 @@ static void HandlePacketFromPlayer(SINT8 node) { SendKick(netconsole, KICK_MSG_CON_FAIL); DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", - netconsole, realstart, consistancy[realstart%TICQUEUE], + netconsole, realstart, consistancy[realstart%BACKUPTICS], SHORT(netbuffer->u.clientpak.consistancy))); break; } @@ -5501,8 +5500,8 @@ static void HandlePacketFromPlayer(SINT8 node) break; #else // Check player consistancy during the level - if (realstart <= gametic && realstart > gametic - TICQUEUE+1 && gamestate == GS_LEVEL - && consistancy[realstart%TICQUEUE] != SHORT(netbuffer->u.clientpak.consistancy)) + if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 && gamestate == GS_LEVEL + && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy)) { SV_RequireResynch(node); @@ -5511,10 +5510,10 @@ static void HandlePacketFromPlayer(SINT8 node) if (cv_blamecfail.value) CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), netconsole+1, player_names[netconsole], - consistancy[realstart%TICQUEUE], + consistancy[realstart%BACKUPTICS], SHORT(netbuffer->u.clientpak.consistancy)); DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", - netconsole, realstart, consistancy[realstart%TICQUEUE], + netconsole, realstart, consistancy[realstart%BACKUPTICS], SHORT(netbuffer->u.clientpak.consistancy))); break; } @@ -5522,7 +5521,7 @@ static void HandlePacketFromPlayer(SINT8 node) { SendKick(netconsole, KICK_MSG_CON_FAIL); DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", - netconsole, realstart, consistancy[realstart%TICQUEUE], + netconsole, realstart, consistancy[realstart%BACKUPTICS], SHORT(netbuffer->u.clientpak.consistancy))); break; } @@ -5599,10 +5598,10 @@ static void HandlePacketFromPlayer(SINT8 node) // search a tic that have enougth space in the ticcmd while ((textcmd = D_GetExistingTextcmd(tic, netconsole)), (TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD) - && tic < firstticstosend + TICQUEUE) + && tic < firstticstosend + BACKUPTICS) tic++; - if (tic >= firstticstosend + TICQUEUE) + if (tic >= firstticstosend + BACKUPTICS) { DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, " "tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)), @@ -5680,8 +5679,8 @@ static void HandlePacketFromPlayer(SINT8 node) txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots * netbuffer->u.serverpak.numtics]; - if (realend > gametic + BACKUPTICS) - realend = gametic + BACKUPTICS; + if (realend > gametic + CLIENTBACKUPTICS) + realend = gametic + CLIENTBACKUPTICS; cl_packetmissed = realstart > neededtic; if (realstart <= neededtic && realend > neededtic) @@ -5695,7 +5694,7 @@ static void HandlePacketFromPlayer(SINT8 node) D_Clearticcmd(i); // copy the tics - pak = G_ScpyTiccmd(netcmds[i%TICQUEUE], pak, + pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak, netbuffer->u.serverpak.numslots*sizeof (ticcmd_t)); // copy the textcmds @@ -6133,7 +6132,7 @@ static void CL_SendClientCmd(void) packetsize = sizeof (clientcmd_pak); G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds[0][lagDelay], 1); - netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic % TICQUEUE]); + netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic % BACKUPTICS]); if (splitscreen || botingame) // Send a special packet with 2 cmd for splitscreen { @@ -6223,11 +6222,8 @@ static void SV_SendTics(void) continue; // assert supposedtics[n]>=nettics[n] - realfirsttic = supposedtics[n]; - lasttictosend = maketic; - - if (lasttictosend - nettics[n] >= BACKUPTICS) - lasttictosend = nettics[n] + BACKUPTICS-1; + realfirsttic = max(supposedtics[n], firstticstosend); + lasttictosend = min(maketic, nettics[n] + CLIENTBACKUPTICS); if (realfirsttic >= lasttictosend) { @@ -6236,15 +6232,14 @@ static void SV_SendTics(void) // packet detection work when we have received packet with firsttic > neededtic // (getpacket servertics case) DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n", - n, lasttictosend, supposedtics[n], nettics[n])); + n, lasttictosend, supposedtics[n], nettics[n])); realfirsttic = nettics[n]; if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) // all tic are ok continue; DEBFILE(va("Sent %d anyway\n", realfirsttic)); } - if (realfirsttic < firstticstosend) - realfirsttic = firstticstosend; + realfirsttic = max(realfirsttic, firstticstosend); // compute the length of the packet and cut it if too large packsize = BASESERVERTICSSIZE; @@ -6288,7 +6283,7 @@ static void SV_SendTics(void) for (i = realfirsttic; i < lasttictosend; i++) { - bufpos = G_DcpyTiccmd(bufpos, netcmds[i%TICQUEUE], doomcom->numslots * sizeof (ticcmd_t)); + bufpos = G_DcpyTiccmd(bufpos, netcmds[i%BACKUPTICS], doomcom->numslots * sizeof (ticcmd_t)); } // add textcmds @@ -6310,15 +6305,17 @@ static void SV_SendTics(void) } } } - packsize = bufpos - (UINT8 *)&(netbuffer->u); + packsize = bufpos - (UINT8 *)&(netbuffer->u); HSendPacket(n, false, 0, packsize); + // when tic are too large, only one tic is sent so don't go backward! if (lasttictosend-doomcom->extratics > realfirsttic) supposedtics[n] = lasttictosend-doomcom->extratics; else supposedtics[n] = lasttictosend; - if (supposedtics[n] < nettics[n]) supposedtics[n] = nettics[n]; + + supposedtics[n] = max(supposedtics[n], nettics[n]); } // node 0 is me! supposedtics[0] = maketic; @@ -6375,16 +6372,16 @@ void SV_SpawnPlayer(INT32 playernum, INT32 x, INT32 y, angle_t angle) for (tic = server ? maketic : (neededtic - 1); tic >= gametic; tic--) { - if (numadjust++ == TICQUEUE) + if (numadjust++ == BACKUPTICS) { DEBFILE(va("SV_SpawnPlayer: All netcmds for player %d adjusted!\n", playernum)); // We already adjusted them all, waste of time doing the same thing over and over // This shouldn't happen normally though, either gametic was 0 (which is handled now anyway) - // or maketic >= gametic + TICQUEUE + // or maketic >= gametic + BACKUPTICS // -- Monster Iestyn 16/01/18 break; } - netcmds[tic%TICQUEUE][playernum].angleturn = (INT16)((angle>>16) | TICCMD_RECEIVED); + netcmds[tic%BACKUPTICS][playernum].angleturn = (INT16)((angle>>16) | TICCMD_RECEIVED); if (!tic) // failsafe for gametic == 0 -- Monster Iestyn 16/01/18 break; @@ -6402,7 +6399,7 @@ static void SV_Maketic(void) continue; INT32 player = nodetoplayer[j]; - if ((netcmds[maketic%TICQUEUE][player].angleturn & TICCMD_RECEIVED) == 0) + if ((netcmds[maketic%BACKUPTICS][player].angleturn & TICCMD_RECEIVED) == 0) { // we didn't receive this tic INT32 i; @@ -6417,8 +6414,8 @@ static void SV_Maketic(void) else if (i == 1) player = nodetoplayer2[j]; else if (i == 2) player = nodetoplayer3[j]; else if (i == 3) player = nodetoplayer4[j]; - netcmds[maketic%TICQUEUE][player] = netcmds[(maketic-1)%TICQUEUE][player]; - netcmds[maketic%TICQUEUE][player].angleturn &= ~TICCMD_RECEIVED; + netcmds[maketic%BACKUPTICS][player] = netcmds[(maketic-1)%BACKUPTICS][player]; + netcmds[maketic%BACKUPTICS][player].angleturn &= ~TICCMD_RECEIVED; } } } @@ -6493,7 +6490,7 @@ boolean TryRunTics(tic_t realtics) G_Ticker((gametic % NEWTICRATERATIO) == 0); ExtraDataTicker(); gametic++; - consistancy[gametic%TICQUEUE] = Consistancy(); + consistancy[gametic%BACKUPTICS] = Consistancy(); if (update_stats) { @@ -6526,7 +6523,7 @@ boolean TryRunTics(tic_t realtics) static INT32 pingtimeout[MAXPLAYERS]; -#define PINGKICK_TICQUEUE 2 +#define PINGKICK_BACKUPTICS 2 #define PINGKICK_LIMIT 1 static inline void PingUpdate(void) @@ -6542,7 +6539,7 @@ static inline void PingUpdate(void) netbuffer->packettype = PT_PING; //check for ping limit breakage. - //if (cv_maxping.value) -- always check for TICQUEUE overrun + //if (cv_maxping.value) -- always check for BACKUPTICS overrun { for (i = 0; i < MAXPLAYERS; i++) { @@ -6552,10 +6549,10 @@ static inline void PingUpdate(void) continue; } - if ((maketic + 5) >= nettics[playernode[i]] + (TICQUEUE-(2*TICRATE))) + if ((maketic + 5) >= nettics[playernode[i]] + (BACKUPTICS-(2*TICRATE))) { - // Anyone who's gobbled most of the TICQUEUE and is likely to halt the server the next few times this runs has to die *right now*. (See also NetUpdate) - pingkick[i] = PINGKICK_TICQUEUE; + // Anyone who's gobbled most of the BACKUPTICS and is likely to halt the server the next few times this runs has to die *right now*. (See also NetUpdate) + pingkick[i] = PINGKICK_BACKUPTICS; } else if ((cv_maxping.value) && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value)) @@ -6578,9 +6575,9 @@ static inline void PingUpdate(void) //kick lagging players... unless everyone but the server's ping sucks. //in that case, it is probably the server's fault. - // Always kick TICQUEUE-overrunners, too. + // Always kick BACKUPTICS-overrunners, too. { - UINT8 minimumkicklevel = (nonlaggers > 0) ? PINGKICK_LIMIT : PINGKICK_TICQUEUE; + UINT8 minimumkicklevel = (nonlaggers > 0) ? PINGKICK_LIMIT : PINGKICK_BACKUPTICS; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || pingkick[i] < minimumkicklevel) @@ -6909,7 +6906,7 @@ void NetUpdate(void) continue; if (nettics[i] < firstticstosend) firstticstosend = nettics[i]; - if (maketic + counts >= nettics[i] + (TICQUEUE - TICRATE)) + if (maketic + counts >= nettics[i] + (BACKUPTICS - TICRATE)) Net_ConnectionTimeout(i); } @@ -6924,8 +6921,8 @@ void NetUpdate(void) if (counts != -666) { // See also PingUpdate - if (maketic + counts >= firstticstosend + TICQUEUE) - counts = firstticstosend+TICQUEUE-maketic-1; + if (maketic + counts >= firstticstosend + BACKUPTICS) + counts = firstticstosend+BACKUPTICS-maketic-1; for (i = 0; i < counts; i++) SV_Maketic(); // Create missed tics and increment maketic diff --git a/src/d_clisrv.h b/src/d_clisrv.h index f735846e6..d16f4d71f 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -38,8 +38,8 @@ applications may follow different packet versions. #define VANILLA_GT_MATCH 3 // Networking and tick handling related. -#define BACKUPTICS 32 -#define TICQUEUE 512 // more than enough for most timeouts.... +#define BACKUPTICS 512 // more than enough for most timeouts.... +#define CLIENTBACKUPTICS 32 #define MAXTEXTCMD 256 // No. of tics your controls can be delayed by. diff --git a/src/doomstat.h b/src/doomstat.h index f8a3899ca..00355817f 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -575,7 +575,7 @@ extern consvar_t cv_downloading; // allow clients to downloading WADs. extern consvar_t cv_nettimeout; // SRB2Kart: Advanced server options menu extern consvar_t cv_jointimeout; extern consvar_t cv_maxping; -extern ticcmd_t netcmds[TICQUEUE][MAXPLAYERS]; +extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; extern INT32 serverplayer; extern INT32 adminplayers[MAXPLAYERS]; diff --git a/src/g_game.c b/src/g_game.c index 200ce7834..620abdca3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1854,7 +1854,7 @@ void G_Ticker(boolean run) } } - buf = gametic % TICQUEUE; + buf = gametic % BACKUPTICS; if (!demo.playback) { diff --git a/src/p_setup.c b/src/p_setup.c index fe3a0d7fc..db4641373 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3047,7 +3047,7 @@ boolean P_SetupLevel(boolean fromnetsave, boolean reloadinggamestate) if (!fromnetsave) // uglier hack { // to make a newly loaded level start on the second frame. - INT32 buf = gametic % TICQUEUE; + INT32 buf = gametic % BACKUPTICS; for (i = 0; i < MAXPLAYERS; i++) { -- 2.54.0 From 17bc8a4a3663a8e48e8f5270b2e17da23b8bf35e Mon Sep 17 00:00:00 2001 From: Alug Date: Sun, 27 Apr 2025 06:50:35 +0200 Subject: [PATCH 08/15] delet tic resending stuff --- src/d_clisrv.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 93c0e82f0..8827d91b8 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5676,11 +5676,8 @@ static void HandlePacketFromPlayer(SINT8 node) realend = realstart + netbuffer->u.serverpak.numtics; if (!txtpak) - txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots - * netbuffer->u.serverpak.numtics]; + txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots * netbuffer->u.serverpak.numtics]; - if (realend > gametic + CLIENTBACKUPTICS) - realend = gametic + CLIENTBACKUPTICS; cl_packetmissed = realstart > neededtic; if (realstart <= neededtic && realend > neededtic) @@ -6225,22 +6222,6 @@ static void SV_SendTics(void) realfirsttic = max(supposedtics[n], firstticstosend); lasttictosend = min(maketic, nettics[n] + CLIENTBACKUPTICS); - if (realfirsttic >= lasttictosend) - { - // well we have sent all tics we will so use extrabandwidth - // to resent packet that are supposed lost (this is necessary since lost - // packet detection work when we have received packet with firsttic > neededtic - // (getpacket servertics case) - DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n", - n, lasttictosend, supposedtics[n], nettics[n])); - realfirsttic = nettics[n]; - if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) - // all tic are ok - continue; - DEBFILE(va("Sent %d anyway\n", realfirsttic)); - } - realfirsttic = max(realfirsttic, firstticstosend); - // compute the length of the packet and cut it if too large packsize = BASESERVERTICSSIZE; for (i = realfirsttic; i < lasttictosend; i++) -- 2.54.0 From c3458afe2b250288d173c6c4595327617a89c7e3 Mon Sep 17 00:00:00 2001 From: Alug Date: Fri, 23 May 2025 16:53:42 +0200 Subject: [PATCH 09/15] unglobalise holepunchpacket aswell --- src/d_net.c | 9 --------- src/i_net.h | 6 ++---- src/i_tcp.c | 4 ++++ 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/d_net.c b/src/d_net.c index aceec8fed..3a75a29a4 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -49,11 +49,6 @@ tic_t connectiontimeout = (10*TICRATE); /// \brief network packet doomcom_t *doomcom = NULL; -/// \brief hole punching packet, also points inside doomcom -#ifdef HOLEPUNCH -holepunch_t *holepunchpacket = NULL; -#endif - #ifdef DEBUGFILE FILE *debugfile = NULL; // put some net info in a file during the game #endif @@ -1347,10 +1342,6 @@ boolean D_CheckNetGame(void) if (doomcom->numnodes > MAXNETNODES) I_Error("Too many nodes (%d), max:%d", doomcom->numnodes, MAXNETNODES); -#ifdef HOLEPUNCH - holepunchpacket = (holepunch_t *)(void *)&doomcom->data; -#endif - #ifdef DEBUGFILE if (M_CheckParm("-debugfile")) { diff --git a/src/i_net.h b/src/i_net.h index 59bcca955..812664f0d 100644 --- a/src/i_net.h +++ b/src/i_net.h @@ -87,6 +87,8 @@ typedef struct INT32 addr; INT16 port; } ATTRPACK holepunch_t; + +#define HOLEPUNCH_DATA(d) (holepunch_t *)&(d)->data #endif #if defined(_MSC_VER) @@ -95,10 +97,6 @@ typedef struct extern doomcom_t *doomcom; -#ifdef HOLEPUNCH -extern holepunch_t *holepunchpacket; -#endif - /** \brief return packet in doomcom struct */ extern boolean (*I_NetGet)(void); diff --git a/src/i_tcp.c b/src/i_tcp.c index eb882f9b6..37c08f6d5 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -655,6 +655,7 @@ is_external_address (UINT32 p) static boolean hole_punch(ssize_t c) { + holepunch_t *holepunchpacket = HOLEPUNCH_DATA(doomcom); /* See ../doc/Holepunch-Protocol.txt */ if (cv_rendezvousserver.string[0] && @@ -1442,6 +1443,8 @@ static void rendezvous(int size) tic_t tic = I_GetTime(); + holepunch_t *holepunchpacket = HOLEPUNCH_DATA(doomcom); + if (tic != refreshtic) { if (SOCK_GetAddr(&rzv.ip4, host, (port ? port : "7777"), false)) @@ -1467,6 +1470,7 @@ static void rendezvous(int size) static void SOCK_RequestHolePunch(INT32 node) { mysockaddr_t * addr = &clientaddress[node]; + holepunch_t *holepunchpacket = HOLEPUNCH_DATA(doomcom); holepunchpacket->addr = addr->ip4.sin_addr.s_addr; holepunchpacket->port = addr->ip4.sin_port; -- 2.54.0 From f87bcef07991f78ce8ed311618a53e4e2049614e Mon Sep 17 00:00:00 2001 From: Alug Date: Mon, 19 May 2025 15:59:41 +0200 Subject: [PATCH 10/15] try fixing some crash with bogus netxcmds --- src/d_clisrv.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 8827d91b8..9dae8eaf2 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5696,13 +5696,20 @@ static void HandlePacketFromPlayer(SINT8 node) // copy the textcmds numtxtpak = *txtpak++; + for (j = 0; j < numtxtpak; j++) { - INT32 k = *txtpak++; // playernum + INT32 playernum = *txtpak++; // playernum const size_t txtsize = txtpak[0]+1; + if (playernum < 0 || playernum >= MAXPLAYERS) + { + CONS_Alert(CONS_WARNING, "Got bogus NetXCmd packet targetting player %d\n", playernum); + return; + } + if (i >= gametic) // Don't copy old net commands - M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize); + M_Memcpy(D_GetTextcmd(i, playernum), txtpak, txtsize); txtpak += txtsize; } } -- 2.54.0 From 3685502edf26b581697db5a49864347f819b7a15 Mon Sep 17 00:00:00 2001 From: Alug Date: Mon, 26 May 2025 18:10:03 +0200 Subject: [PATCH 11/15] Revert "delet tic resending stuff" This reverts commit 17bc8a4a3663a8e48e8f5270b2e17da23b8bf35e. --- src/d_clisrv.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 9dae8eaf2..e07df96c3 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5676,8 +5676,11 @@ static void HandlePacketFromPlayer(SINT8 node) realend = realstart + netbuffer->u.serverpak.numtics; if (!txtpak) - txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots * netbuffer->u.serverpak.numtics]; + txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots + * netbuffer->u.serverpak.numtics]; + if (realend > gametic + CLIENTBACKUPTICS) + realend = gametic + CLIENTBACKUPTICS; cl_packetmissed = realstart > neededtic; if (realstart <= neededtic && realend > neededtic) @@ -6229,6 +6232,22 @@ static void SV_SendTics(void) realfirsttic = max(supposedtics[n], firstticstosend); lasttictosend = min(maketic, nettics[n] + CLIENTBACKUPTICS); + if (realfirsttic >= lasttictosend) + { + // well we have sent all tics we will so use extrabandwidth + // to resent packet that are supposed lost (this is necessary since lost + // packet detection work when we have received packet with firsttic > neededtic + // (getpacket servertics case) + DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n", + n, lasttictosend, supposedtics[n], nettics[n])); + realfirsttic = nettics[n]; + if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) + // all tic are ok + continue; + DEBFILE(va("Sent %d anyway\n", realfirsttic)); + } + realfirsttic = max(realfirsttic, firstticstosend); + // compute the length of the packet and cut it if too large packsize = BASESERVERTICSSIZE; for (i = realfirsttic; i < lasttictosend; i++) -- 2.54.0 From f4a827dfc23210cb3594e8b76c180f81ad2ad685 Mon Sep 17 00:00:00 2001 From: Alug Date: Thu, 12 Jun 2025 00:02:55 +0200 Subject: [PATCH 12/15] fix conflicts --- src/d_clisrv.c | 27 ++++++++++++++++++++++----- src/http-mserv.c | 4 ++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index a4a523813..322a3e091 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2394,6 +2394,7 @@ static boolean CL_FinishedFileList(void) char *downloadsize = NULL; //CONS_Printf(M_GetText("Checking files...\n")); i = CL_CheckFiles(); + if (i == 4) // still checking ... { return true; @@ -5026,6 +5027,16 @@ static void HandleServerInfo(SINT8 node) memcpy(connectedservername, netbuffer->u.serverinfo.servername, MAXSERVERNAME); } +static void HandlePlayerInfo(SINT8 node) +{ + (void)node; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + + INT32 i; + for (i = 0; i < MAXPLAYERS; i++) + playerinfo[i] = netbuffer->u.playerinfo[i]; +} + // Helper function for packets that should only be sent by the server // If it is NOT from the server, bail out and close the connection! static boolean ServerOnly(SINT8 node) @@ -5190,7 +5201,9 @@ static void PT_ServerCFG(SINT8 node) #ifdef SATURNPAK SendSaturnInfo(node); #endif + memset(playeringame, 0, sizeof(playeringame)); + for (j = 0; j < MAXPLAYERS; j++) { if (netbuffer->u.servercfg.playerskins[j] == 0xFF @@ -5336,10 +5349,10 @@ static void HandlePacketFromAwayNode(SINT8 node) case PT_CLIENTCMD: break; // This is not an "unknown packet" - - case PT_PLAYERINFO: + + case PT_PLAYERINFO: HandlePlayerInfo(node); - break; + break; case PT_SERVERTICS: // Do not remove my own server (we have just get a out of order packet) @@ -5532,7 +5545,7 @@ static void HandlePacketFromPlayer(SINT8 node) // Check player consistancy during the level if (gamestate == GS_LEVEL - && (realstart > gametic - BACKUPTICS+1 && realstart <= gametic) + && (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic) && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) && (!UseSaturnSynch(node) || (!resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime() && !SV_ResendingSavegameToAnyone()))) { @@ -5948,7 +5961,6 @@ static void GetPackets(void) /*if (netbuffer->packettype == PT_PLAYERINFO) continue; // We do nothing with PLAYERINFO, that's for the MS browser. Not quite true anymore :p*/ - // We also count unknown packets, hence "<=" if (netbuffer->packettype <= NUMPACKETTYPE) ++packetstat[netbuffer->packettype]; @@ -6279,10 +6291,12 @@ static void CL_SendClientCmd(void) } M_Memcpy(netbuffer->u.textcmd, localtextcmd[i], localtextcmd[i][0]+1); + // All extra data have been sent if (HSendPacket(servernode, true, 0, localtextcmd[i][0]+1)) // Send can fail... { localtextcmd[i][0] = 0; + if (textcmdbuf[i] != NULL) { textcmdbuf_t *buf = textcmdbuf[i]; @@ -6339,6 +6353,7 @@ static void SV_SendTics(void) // compute the length of the packet and cut it if too large packsize = BASESERVERTICSSIZE; + for (i = realfirsttic; i < lasttictosend; i++) { packsize += sizeof (ticcmd_t) * doomcom->numslots; @@ -6366,6 +6381,7 @@ static void SV_SendTics(void) DEBFILE("sending it anyway\n"); } } + break; } } @@ -6387,6 +6403,7 @@ static void SV_SendTics(void) { ntextcmd = bufpos++; *ntextcmd = 0; + for (j = 0; j < MAXPLAYERS; j++) { UINT8 *textcmd = D_GetExistingTextcmd(i, j); diff --git a/src/http-mserv.c b/src/http-mserv.c index 74ea2ccd3..4cab52acf 100644 --- a/src/http-mserv.c +++ b/src/http-mserv.c @@ -224,9 +224,9 @@ HMS_connect (const char *format, ...) #ifdef HAVE_IPV6 if (!M_CheckParm("-ipv6")) #endif - curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + curl_easy_setopt(curl, CURLOPT_IPRESOLVE, (long)CURL_IPRESOLVE_V4); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, cv_masterserver_timeout.value); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long)cv_masterserver_timeout.value); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read); curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); -- 2.54.0 From dc069d7bb5ac4745c23ddfd101a2ebe0f0135a96 Mon Sep 17 00:00:00 2001 From: Alug Date: Thu, 12 Jun 2025 00:53:47 +0200 Subject: [PATCH 13/15] unnest HandlePacketFromPlayer + some cleanup --- src/d_clisrv.c | 1150 ++++++++++++++++++++++++++---------------------- 1 file changed, 613 insertions(+), 537 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 322a3e091..298f5f9ee 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1156,6 +1156,9 @@ static void CL_AcknowledgeResynch(resynch_pak *rsp) static void SV_AcknowledgeResynchAck(INT32 node, UINT8 rsg) { + if (client) + return; + if (rsg >= MAXPLAYERS) resynch_score[node] += 16384; // lol. else @@ -4997,6 +5000,17 @@ static void HandleTimeout(SINT8 node) M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING); } +// Helper function for packets that should only be sent by the server +// If it is NOT from the server, bail out and close the connection! +static boolean ServerOnly(SINT8 node) +{ + if (node == servernode) + return false; + + Net_CloseConnection(node); + return true; +} + #ifndef NONET /** Called when a PT_SERVERINFO packet is received * @@ -5027,27 +5041,15 @@ static void HandleServerInfo(SINT8 node) memcpy(connectedservername, netbuffer->u.serverinfo.servername, MAXSERVERNAME); } -static void HandlePlayerInfo(SINT8 node) +static void HandlePlayerInfo(void) { - (void)node; + INT32 i; doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); - INT32 i; for (i = 0; i < MAXPLAYERS; i++) playerinfo[i] = netbuffer->u.playerinfo[i]; } -// Helper function for packets that should only be sent by the server -// If it is NOT from the server, bail out and close the connection! -static boolean ServerOnly(SINT8 node) -{ - if (node == servernode) - return false; - - Net_CloseConnection(node); - return true; -} - static void PT_TellFilesNeeded(SINT8 node) { doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); @@ -5071,7 +5073,7 @@ static void PT_TellFilesNeeded(SINT8 node) static void PT_MoreFilesNeeded(SINT8 node) { - doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + doomdata_t *netbuffer; if (server && serverrunning) { // But wait I thought I'm the server? @@ -5082,6 +5084,8 @@ static void PT_MoreFilesNeeded(SINT8 node) if (ServerOnly(node)) return; + netbuffer = DOOMCOM_DATA(doomcom); + if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum) { D_ParseFileneeded(netbuffer->u.filesneededcfg.num, netbuffer->u.filesneededcfg.files, netbuffer->u.filesneededcfg.first); @@ -5090,10 +5094,23 @@ static void PT_MoreFilesNeeded(SINT8 node) } } +static void PT_AskInfo(SINT8 node) +{ + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + + if (server && serverrunning) + { + SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); + SV_SendPlayerInfo(node); // Send extra info + } + + Net_CloseConnection(node); +} + // Negative response of client join request static void PT_ServerRefuse(SINT8 node) { - doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + doomdata_t *netbuffer; if (server && serverrunning) { // But wait I thought I'm the server? @@ -5104,45 +5121,47 @@ static void PT_ServerRefuse(SINT8 node) if (ServerOnly(node)) return; - if (cl_mode == CL_WAITJOINRESPONSE) + if (cl_mode != CL_WAITJOINRESPONSE) + return; + + netbuffer = DOOMCOM_DATA(doomcom); + + // Save the reason so it can be displayed after quitting the netgame + char *reason = strdup(netbuffer->u.serverrefuse.reason); + if (!reason) + I_Error("Out of memory!\n"); + + if (strstr(reason, "Maximum players reached")) { - // Save the reason so it can be displayed after quitting the netgame - char *reason = strdup(netbuffer->u.serverrefuse.reason); - if (!reason) - I_Error("Out of memory!\n"); - - if (strstr(reason, "Maximum players reached")) - { - serverisfull = true; - //Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer - //We set it back to the value of cv_nettimeout.value in CL_Reset - connectiontimeout = NEWTICRATE*7; - cl_mode = CL_ASKJOIN; - free(reason); - return; - } - - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - - if (reason[1] == '|') - { - M_StartMessage(va("You have been %sfrom the server\n\nReason:\n%s", - (reason[0] == 'B') ? "banned\n" : "temporarily\nkicked ", - reason+2), NULL, MM_NOTHING); - } - else - { - M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), - reason), NULL, MM_NOTHING); - } - + serverisfull = true; + //Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer + //We set it back to the value of cv_nettimeout.value in CL_Reset + connectiontimeout = NEWTICRATE*7; + cl_mode = CL_ASKJOIN; free(reason); - - // Will be reset by caller. Signals refusal. - cl_mode = CL_ABORTED; + return; } + + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + + if (reason[1] == '|') + { + M_StartMessage(va("You have been %sfrom the server\n\nReason:\n%s", + (reason[0] == 'B') ? "banned\n" : "temporarily\nkicked ", + reason+2), NULL, MM_NOTHING); + } + else + { + M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), + reason), NULL, MM_NOTHING); + } + + free(reason); + + // Will be reset by caller. Signals refusal. + cl_mode = CL_ABORTED; } // Positive response of client join request @@ -5150,8 +5169,7 @@ static void PT_ServerCFG(SINT8 node) { INT32 j; UINT8 *scp; - - doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + doomdata_t *netbuffer; if (server && serverrunning && node != servernode) { // but wait I thought I'm the server? @@ -5166,6 +5184,8 @@ static void PT_ServerCFG(SINT8 node) if (!(cl_mode == CL_WAITJOINRESPONSE || cl_mode == CL_ASKJOIN)) return; + netbuffer = DOOMCOM_DATA(doomcom); + if (client) { maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); @@ -5230,6 +5250,31 @@ static void PT_ServerCFG(SINT8 node) #endif } +static void PT_FileFragmentFromAwayNode(SINT8 node) +{ + if (server) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + return; + } + + if (ServerOnly(node)) + return; + + Got_Filetxpak(); +} + +static void PT_RequestFile(SINT8 node) +{ + if (server) + { + if (!cv_downloading.value || !Got_RequestFilePak(node)) + Net_CloseConnection(node); // close connection if one of the requested files could not be sent, or you disabled downloading anyway + } + else + Net_CloseConnection(node); // nope +} + #endif #ifdef SATURNPAK @@ -5245,6 +5290,7 @@ static void PT_WillResendGamestate(void) // Send back a PT_CANRECEIVEGAMESTATE packet to the server // so they know they can start sending the game state netbuffer->packettype = PT_CANRECEIVEGAMESTATE; + if (!HSendPacket(servernode, true, 0, 0)) return; @@ -5282,78 +5328,48 @@ static void PT_CanReceiveGamestate(SINT8 node) */ static void HandlePacketFromAwayNode(SINT8 node) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + if (node != servernode) DEBFILE(va("Received packet from unknown host %d\n", node)); - doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); - switch (netbuffer->packettype) { case PT_ASKINFOVIAMS: Net_CloseConnection(node); break; - case PT_TELLFILESNEEDED: PT_TellFilesNeeded(node); break; - case PT_MOREFILESNEEDED: PT_MoreFilesNeeded(node); break; - case PT_ASKINFO: - if (server && serverrunning) - { - SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); - SV_SendPlayerInfo(node); // Send extra info - } - Net_CloseConnection(node); + PT_AskInfo(node); break; - case PT_SERVERREFUSE: // Negative response of client join request PT_ServerRefuse(node); break; - case PT_SERVERCFG: // Positive response of client join request PT_ServerCFG(node); break; // Handled in d_netfil.c case PT_FILEFRAGMENT: - if (server) - { // But wait I thought I'm the server? - Net_CloseConnection(node); - break; - } - - if (ServerOnly(node)) - break; - - Got_Filetxpak(); + PT_FileFragmentFromAwayNode(node); break; - case PT_REQUESTFILE: - if (server) - { - if (!cv_downloading.value || !Got_RequestFilePak(node)) - Net_CloseConnection(node); // close connection if one of the requested files could not be sent, or you disabled downloading anyway - } - else - Net_CloseConnection(node); // nope + PT_RequestFile(node); break; - case PT_NODETIMEOUT: case PT_CLIENTQUIT: if (server) Net_CloseConnection(node); break; - case PT_CLIENTCMD: break; // This is not an "unknown packet" - case PT_PLAYERINFO: - HandlePlayerInfo(node); - break; - + HandlePlayerInfo(); + break; case PT_SERVERTICS: // Do not remove my own server (we have just get a out of order packet) if (node == servernode) @@ -5361,10 +5377,9 @@ static void HandlePacketFromAwayNode(SINT8 node) /* FALLTHRU */ default: - DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype)); + DEBFILE(va("unknown packet received (%d) from unknown host\n", netbuffer->packettype)); Net_CloseConnection(node); break; // Ignore it - } } @@ -5389,6 +5404,498 @@ static boolean CheckForSpeedHacks(UINT8 p) return false; } +static void PT_ClientCmd(INT32 netconsole, SINT8 node) +{ + doomdata_t *netbuffer; + tic_t realend, realstart; + + if (client) + return; + + // Ignore tics from those not synched + if (resynch_inprogress[node]) + return; + + netbuffer = DOOMCOM_DATA(doomcom); + + // To save bytes, only the low byte of tic numbers are sent + // Use ExpandTics to figure out what the rest of the bytes are + realstart = ExpandTics(netbuffer->u.clientpak.client_tic, nettics[node]); + realend = ExpandTics(netbuffer->u.clientpak.resendfrom, nettics[node]); + + if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS + || netbuffer->packettype == PT_CLIENT3MIS || netbuffer->packettype == PT_CLIENT4MIS + || netbuffer->packettype == PT_NODEKEEPALIVEMIS + || supposedtics[node] < realend) + { + supposedtics[node] = realend; + } + + // Discard out of order packet + if (nettics[node] > realend) + { + DEBFILE(va("out of order ticcmd discarded nettics = %u\n", nettics[node])); + return; + } + + // Update the nettics + nettics[node] = realend; + + // This should probably still timeout though, as the node should always have a player 1 number + if (netconsole == -1) + return; + + // If a client sends a ticcmd it should mean they are done receiving the savegame + sendingsavegame[node] = false; + + // As long as clients send valid ticcmds, the server can keep running, so reset the timeout + /// \todo Use a separate cvar for that kind of timeout? + freezetimeout[node] = I_GetTime() + connectiontimeout; + + // Don't do anything for packets of type NODEKEEPALIVE? + // Sryder 2018/07/01: Update the freezetimeout still! + if (netbuffer->packettype == PT_NODEKEEPALIVE + || netbuffer->packettype == PT_NODEKEEPALIVEMIS) + return; + + // If we've alredy received a ticcmd for this tic, just submit it for the next one. + tic_t faketic = maketic; + if ((!!(netcmds[maketic % BACKUPTICS][netconsole].angleturn & TICCMD_RECEIVED)) + && (maketic - firstticstosend < BACKUPTICS - 1)) + faketic++; + + // Copy ticcmd + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); + + // Check ticcmd for "speed hacks" + if (CheckForSpeedHacks((UINT8)netconsole)) + return; + + // Splitscreen cmd + if (((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) + || (netbuffer->packettype == PT_CLIENT3CMD || netbuffer->packettype == PT_CLIENT3MIS) + || (netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS)) + && (nodetoplayer2[node] >= 0)) + { + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], + &netbuffer->u.client2pak.cmd2, 1); + + if (CheckForSpeedHacks((UINT8)nodetoplayer2[node])) + return; + } + + if (((netbuffer->packettype == PT_CLIENT3CMD || netbuffer->packettype == PT_CLIENT3MIS) + || (netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS)) + && (nodetoplayer3[node] >= 0)) + { + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer3[node]], + &netbuffer->u.client3pak.cmd3, 1); + + if (CheckForSpeedHacks((UINT8)nodetoplayer3[node])) + return; + } + + if ((netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS) + && (nodetoplayer4[node] >= 0)) + { + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer4[node]], + &netbuffer->u.client4pak.cmd4, 1); + + if (CheckForSpeedHacks((UINT8)nodetoplayer4[node])) + return; + } + + // A delay before we check resynching + // Used on join or just after a synch fail + if (resynch_delay[node]) + { + --resynch_delay[node]; + return; + } + +#ifdef SATURNPAK + // this decreases by one point at twice the cooldown time (ex cooldown of 2 seconds means, this counter decreases by one every 4 seconds), pretty much there to prevent a resynch loop + if ((gamestate_resend_counter[node] != 0) && (I_GetTime() % ((max(cv_resynchcooldown.value, 1) * TICRATE) *2) == 0)) + { + gamestate_resend_counter[node]--; + DEBFILE(va("gamestate counter %d for node %d\n", gamestate_resend_counter[node], netconsole)); + } + + // Check player consistancy during the level + if (gamestate == GS_LEVEL + && (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic) + && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) + && (!UseSaturnSynch(node) || (!resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime() && !SV_ResendingSavegameToAnyone()))) + { + resendingsavegame[node] = false; // reset this before just in case + + // Check if a client is saturn before sending ANYTHING! + // this way we only send stuff to clients we know can use the gamestate resend + // and dont have to wait for a response from clients that never would send a response back + if (UseSaturnSynch(node)) + { + // Tell the client we are about to resend them the gamestate + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + HSendPacket(node, true, 0, 0); + resendingsavegame[node] = true; + } + else if (UseVanillaSynch(node)) + { + SV_RequireResynch(node); + } + + if ((UseVanillaSynch(node) && (resynch_score[node] <= (unsigned)cv_resynchattempts.value*250)) || (UseSaturnSynch(node) && (gamestate_resend_counter[node] < cv_gamestateattempts.value))) + { + if (is_client_saturn[node] && resendingsavegame[node]) + { + gamestate_resend_counter[node]++; + DEBFILE(va("gamestate counter %d for node %d\n", gamestate_resend_counter[node], netconsole)); + } + + if (cv_blamecfail.value) + { + CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), + netconsole+1, player_names[netconsole], + consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy)); + } + + DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", + netconsole, realstart, consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy))); + return; + } + else + { + SendKick(netconsole, KICK_MSG_CON_FAIL); + DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", + netconsole, realstart, consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy))); + return; + } + } + else if (resynch_score[node]) + --resynch_score[node]; +#else + // Check player consistancy during the level + if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 && gamestate == GS_LEVEL + && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy)) + { + SV_RequireResynch(node); + + if (cv_resynchattempts.value && resynch_score[node] <= (unsigned)cv_resynchattempts.value*250) + { + if (cv_blamecfail.value) + CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), + netconsole+1, player_names[netconsole], + consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy)); + DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", + netconsole, realstart, consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy))); + return; + } + else + { + SendKick(netconsole, KICK_MSG_CON_FAIL); + DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", + netconsole, realstart, consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy))); + return; + } + } + else if (resynch_score[node]) + --resynch_score[node]; +#endif +} + +static void PT_BasicKeepAlive(INT32 netconsole, SINT8 node) +{ + if (client) + return; + + // This should probably still timeout though, as the node should always have a player 1 number + if (netconsole == -1) + return; + + // If a client sends this it should mean they are done receiving the savegame + sendingsavegame[node] = false; + + // As long as clients send keep alives, the server can keep running, so reset the timeout + /// \todo Use a separate cvar for that kind of timeout? + freezetimeout[node] = I_GetTime() + connectiontimeout; +} + +static void PT_TextCmd(INT32 netconsole, SINT8 node) +{ + doomdata_t *netbuffer; + + if (client) + return; + + netbuffer = DOOMCOM_DATA(doomcom); + + switch (netbuffer->packettype) + { + case PT_TEXTCMD2: // splitscreen special + netconsole = nodetoplayer2[node]; + break; + case PT_TEXTCMD3: + netconsole = nodetoplayer3[node]; + break; + case PT_TEXTCMD4: + netconsole = nodetoplayer4[node]; + break; + default: + break; + } + + if (netconsole < 0 || netconsole >= MAXPLAYERS) + Net_UnAcknowledgePacket(node); + else + { + size_t j; + tic_t tic = maketic; + UINT8 *textcmd; + + // ignore if the textcmd has a reported size of zero + // this shouldn't be sent at all + if (!netbuffer->u.textcmd[0]) + { + DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n", + node, netconsole)); + Net_UnAcknowledgePacket(node); + return; + } + + // ignore if the textcmd size var is actually larger than it should be + // BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength + if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1) + { + DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n", + netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1), + node, netconsole)); + Net_UnAcknowledgePacket(node); + return; + } + + // check if tic that we are making isn't too large else we cannot send it :( + // doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time + j = (software_MAXPACKETLENGTH - (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE + (doomcom->numslots+1)*sizeof(ticcmd_t))); + + // search a tic that have enougth space in the ticcmd + while ((textcmd = D_GetExistingTextcmd(tic, netconsole)), + (TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD) + && tic < firstticstosend + BACKUPTICS) + { + tic++; + } + + if (tic >= firstticstosend + BACKUPTICS) + { + DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, " + "tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)), + maketic, firstticstosend, node, netconsole)); + Net_UnAcknowledgePacket(node); + return; + } + + // Make sure we have a buffer + if (!textcmd) + textcmd = D_GetTextcmd(tic, netconsole); + + DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n", + tic, textcmd[0]+1, netconsole, firstticstosend, maketic)); + + M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]); + textcmd[0] += (UINT8)netbuffer->u.textcmd[0]; + } +} + +static void PT_ClientQuit(INT32 netconsole, SINT8 node) +{ + doomdata_t *netbuffer; + + if (client) + return; + + netbuffer = DOOMCOM_DATA(doomcom); + + // nodeingame will be put false in the execution of kick command + // this allow to send some packets to the quitting client to have their ack back + nodewaiting[node] = 0; + if (netconsole != -1 && playeringame[netconsole]) + { + SendKick(netconsole, (netbuffer->packettype == PT_NODETIMEOUT) ? KICK_MSG_TIMEOUT : KICK_MSG_PLAYER_QUIT); + } + Net_CloseConnection(node); + nodeingame[node] = false; +} + +static boolean FromServer(SINT8 node, const char *str) +{ + // Only accept PT_RESYNCHEND from the server. + if (node != servernode) + { + CONS_Alert(CONS_WARNING, "%s received from non-host %d\n", str, node); + + if (server) + { + SendKick(node, KICK_MSG_CON_FAIL); + } + + return false; + } + + return true; +} + +static void PT_Resynched(SINT8 node) +{ + doomdata_t *netbuffer; + + // Only accept PT_RESYNCHEND from the server. + if (!FromServer(node, "PT_RESYNCHEND")) + return; + + netbuffer = DOOMCOM_DATA(doomcom); + + resynch_local_inprogress = false; + + P_SetRandSeed(netbuffer->u.resynchend.randomseed); + + if (gametype == GT_CTF) + resynch_read_ctf(&netbuffer->u.resynchend); + resynch_read_others(&netbuffer->u.resynchend); +} + +static void PT_ServerTics(SINT8 node) +{ + doomdata_t *netbuffer; + tic_t realend, realstart; + UINT8 *pak, *txtpak = NULL, numtxtpak; + + // Only accept PT_SERVERTICS from the server. + if (!FromServer(node, "PT_SERVERTICS")) + return; + + netbuffer = DOOMCOM_DATA(doomcom); + + realstart = ExpandTics(netbuffer->u.serverpak.starttic, maketic); + realend = realstart + netbuffer->u.serverpak.numtics; + + if (!txtpak) + txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots + * netbuffer->u.serverpak.numtics]; + + if (realend > gametic + CLIENTBACKUPTICS) + realend = gametic + CLIENTBACKUPTICS; + cl_packetmissed = realstart > neededtic; + + if (realstart <= neededtic && realend > neededtic) + { + tic_t i, j; + pak = (UINT8 *)&netbuffer->u.serverpak.cmds; + + for (i = realstart; i < realend; i++) + { + // clear first + D_Clearticcmd(i); + + // copy the tics + pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak, + netbuffer->u.serverpak.numslots*sizeof (ticcmd_t)); + + // copy the textcmds + numtxtpak = *txtpak++; + + for (j = 0; j < numtxtpak; j++) + { + INT32 playernum = *txtpak++; // playernum + const size_t txtsize = txtpak[0]+1; + + if (playernum < 0 || playernum >= MAXPLAYERS) + { + CONS_Alert(CONS_WARNING, "Got bogus NetXCmd packet targetting player %d\n", playernum); + return; + } + + if (i >= gametic) // Don't copy old net commands + M_Memcpy(D_GetTextcmd(i, playernum), txtpak, txtsize); + txtpak += txtsize; + } + } + + neededtic = realend; + } + else + { + DEBFILE(va("frame not in bound: %u (bounds are from %u to %u)\n", neededtic, realstart, realend)); + /*if (realend < neededtic - 2 * TICRATE || neededtic + 2 * TICRATE < realstart) + * I_Error("Received an out of order PT_SERVERTICS packet!\n" + * "Got tics %d-%d, needed tic %d\n\n" + * "Please report this crash on the Master Board,\n" + * "IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/ + } +} + +static void PT_Resynching(SINT8 node) +{ + doomdata_t *netbuffer; + + // Only accept PT_RESYNCHING from the server. + if (!FromServer(node, "PT_RESYNCHING")) + return; + + netbuffer = DOOMCOM_DATA(doomcom); + + resynch_local_inprogress = true; + CL_AcknowledgeResynch(&netbuffer->u.resynchpak); +} + +static void PT_Ping(SINT8 node) +{ + UINT8 i; + doomdata_t *netbuffer; + + // Only accept PT_PING from the server. + if (!FromServer(node, "PT_PING")) + return; + + if (!client) + return; + + netbuffer = DOOMCOM_DATA(doomcom); + + // Update client ping table from the server. + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i]; + } + + servermaxping = (tic_t)netbuffer->u.pingtable[MAXPLAYERS]; +} + +static void PT_FileFragmentFromPlayer(SINT8 node) +{ + // Only accept PT_FILEFRAGMENT from the server. + if (!FromServer(node, "PT_FILEFRAGMENT")) + return; + + if (client) + Got_Filetxpak(); +} + +static void PT_ReceivedGamestate(SINT8 node) +{ + sendingsavegame[node] = false; + resendingsavegame[node] = false; + savegameresendcooldown[node] = I_GetTime() + cv_resynchcooldown.value * TICRATE; // I_GetTime() + 5 * TICRATE; +} + /** Handles a packet received from a node that is in game * * \param node The packet sender @@ -5400,10 +5907,6 @@ static boolean CheckForSpeedHacks(UINT8 p) static void HandlePacketFromPlayer(SINT8 node) { INT32 netconsole; - tic_t realend, realstart; - UINT8 *pak, *txtpak, numtxtpak; - - txtpak = NULL; doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); @@ -5411,6 +5914,7 @@ static void HandlePacketFromPlayer(SINT8 node) netconsole = 0; else netconsole = nodetoplayer[node]; + #ifdef PARANOIA if (netconsole >= MAXPLAYERS) I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole); @@ -5420,8 +5924,6 @@ static void HandlePacketFromPlayer(SINT8 node) { // -------------------------------------------- SERVER RECEIVE ---------- case PT_RESYNCHGET: - if (client) - break; SV_AcknowledgeResynchAck(node, netbuffer->u.resynchgot); break; case PT_CLIENTCMD: @@ -5434,470 +5936,45 @@ static void HandlePacketFromPlayer(SINT8 node) case PT_CLIENT4MIS: case PT_NODEKEEPALIVE: case PT_NODEKEEPALIVEMIS: - if (client) - break; - - // Ignore tics from those not synched - if (resynch_inprogress[node]) - break; - - // To save bytes, only the low byte of tic numbers are sent - // Use ExpandTics to figure out what the rest of the bytes are - realstart = ExpandTics(netbuffer->u.clientpak.client_tic, nettics[node]); - realend = ExpandTics(netbuffer->u.clientpak.resendfrom, nettics[node]); - - if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS - || netbuffer->packettype == PT_CLIENT3MIS || netbuffer->packettype == PT_CLIENT4MIS - || netbuffer->packettype == PT_NODEKEEPALIVEMIS - || supposedtics[node] < realend) - { - supposedtics[node] = realend; - } - // Discard out of order packet - if (nettics[node] > realend) - { - DEBFILE(va("out of order ticcmd discarded nettics = %u\n", nettics[node])); - break; - } - - // Update the nettics - nettics[node] = realend; - - // This should probably still timeout though, as the node should always have a player 1 number - if (netconsole == -1) - break; - - // If a client sends a ticcmd it should mean they are done receiving the savegame - sendingsavegame[node] = false; - - // As long as clients send valid ticcmds, the server can keep running, so reset the timeout - /// \todo Use a separate cvar for that kind of timeout? - freezetimeout[node] = I_GetTime() + connectiontimeout; - - // Don't do anything for packets of type NODEKEEPALIVE? - // Sryder 2018/07/01: Update the freezetimeout still! - if (netbuffer->packettype == PT_NODEKEEPALIVE - || netbuffer->packettype == PT_NODEKEEPALIVEMIS) - break; - - // If we've alredy received a ticcmd for this tic, just submit it for the next one. - tic_t faketic = maketic; - if ((!!(netcmds[maketic % BACKUPTICS][netconsole].angleturn & TICCMD_RECEIVED)) - && (maketic - firstticstosend < BACKUPTICS - 1)) - faketic++; - - // Copy ticcmd - G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); - - // Check ticcmd for "speed hacks" - if (CheckForSpeedHacks((UINT8)netconsole)) - break; - - // Splitscreen cmd - if (((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) - || (netbuffer->packettype == PT_CLIENT3CMD || netbuffer->packettype == PT_CLIENT3MIS) - || (netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS)) - && (nodetoplayer2[node] >= 0)) - { - G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], - &netbuffer->u.client2pak.cmd2, 1); - - if (CheckForSpeedHacks((UINT8)nodetoplayer2[node])) - break; - } - - if (((netbuffer->packettype == PT_CLIENT3CMD || netbuffer->packettype == PT_CLIENT3MIS) - || (netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS)) - && (nodetoplayer3[node] >= 0)) - { - G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer3[node]], - &netbuffer->u.client3pak.cmd3, 1); - - if (CheckForSpeedHacks((UINT8)nodetoplayer3[node])) - break; - } - - if ((netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS) - && (nodetoplayer4[node] >= 0)) - { - G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer4[node]], - &netbuffer->u.client4pak.cmd4, 1); - - if (CheckForSpeedHacks((UINT8)nodetoplayer4[node])) - break; - } - - // A delay before we check resynching - // Used on join or just after a synch fail - if (resynch_delay[node]) - { - --resynch_delay[node]; - break; - } - -#ifdef SATURNPAK - // this decreases by one point at twice the cooldown time (ex cooldown of 2 seconds means, this counter decreases by one every 4 seconds), pretty much there to prevent a resynch loop - if ((gamestate_resend_counter[node] != 0) && (I_GetTime() % ((max(cv_resynchcooldown.value, 1) * TICRATE) *2) == 0)) - { - gamestate_resend_counter[node]--; - DEBFILE(va("gamestate counter %d for node %d\n", gamestate_resend_counter[node], netconsole)); - } - - // Check player consistancy during the level - if (gamestate == GS_LEVEL - && (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic) - && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) - && (!UseSaturnSynch(node) || (!resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime() && !SV_ResendingSavegameToAnyone()))) - { - resendingsavegame[node] = false; // reset this before just in case - - // Check if a client is saturn before sending ANYTHING! - // this way we only send stuff to clients we know can use the gamestate resend - // and dont have to wait for a response from clients that never would send a response back - if (UseSaturnSynch(node)) - { - // Tell the client we are about to resend them the gamestate - netbuffer->packettype = PT_WILLRESENDGAMESTATE; - HSendPacket(node, true, 0, 0); - resendingsavegame[node] = true; - } - else if (UseVanillaSynch(node)) - { - SV_RequireResynch(node); - } - - if ((UseVanillaSynch(node) && (resynch_score[node] <= (unsigned)cv_resynchattempts.value*250)) || (UseSaturnSynch(node) && (gamestate_resend_counter[node] < cv_gamestateattempts.value))) - { - if (is_client_saturn[node] && resendingsavegame[node]) - { - gamestate_resend_counter[node]++; - DEBFILE(va("gamestate counter %d for node %d\n", gamestate_resend_counter[node], netconsole)); - } - - if (cv_blamecfail.value) - { - CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), - netconsole+1, player_names[netconsole], - consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy)); - } - - DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", - netconsole, realstart, consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy))); - break; - } - else - { - SendKick(netconsole, KICK_MSG_CON_FAIL); - DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", - netconsole, realstart, consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy))); - break; - } - } - else if (resynch_score[node]) - --resynch_score[node]; + PT_ClientCmd(netconsole, node); break; -#else - // Check player consistancy during the level - if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 && gamestate == GS_LEVEL - && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy)) - { - SV_RequireResynch(node); - - if (cv_resynchattempts.value && resynch_score[node] <= (unsigned)cv_resynchattempts.value*250) - { - if (cv_blamecfail.value) - CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), - netconsole+1, player_names[netconsole], - consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy)); - DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", - netconsole, realstart, consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy))); - break; - } - else - { - SendKick(netconsole, KICK_MSG_CON_FAIL); - DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", - netconsole, realstart, consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy))); - break; - } - } - else if (resynch_score[node]) - --resynch_score[node]; - break; -#endif - case PT_BASICKEEPALIVE: - if (client) - break; - - // This should probably still timeout though, as the node should always have a player 1 number - if (netconsole == -1) - break; - - // If a client sends this it should mean they are done receiving the savegame - sendingsavegame[node] = false; - - // As long as clients send keep alives, the server can keep running, so reset the timeout - /// \todo Use a separate cvar for that kind of timeout? - freezetimeout[node] = I_GetTime() + connectiontimeout; + PT_BasicKeepAlive(netconsole, node); break; case PT_TEXTCMD: case PT_TEXTCMD2: case PT_TEXTCMD3: case PT_TEXTCMD4: - if (netbuffer->packettype == PT_TEXTCMD2) // splitscreen special - netconsole = nodetoplayer2[node]; - else if (netbuffer->packettype == PT_TEXTCMD3) - netconsole = nodetoplayer3[node]; - else if (netbuffer->packettype == PT_TEXTCMD4) - netconsole = nodetoplayer4[node]; - - if (client) - break; - - if (netconsole < 0 || netconsole >= MAXPLAYERS) - Net_UnAcknowledgePacket(node); - else - { - size_t j; - tic_t tic = maketic; - UINT8 *textcmd; - - // ignore if the textcmd has a reported size of zero - // this shouldn't be sent at all - if (!netbuffer->u.textcmd[0]) - { - DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n", - node, netconsole)); - Net_UnAcknowledgePacket(node); - break; - } - - // ignore if the textcmd size var is actually larger than it should be - // BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength - if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1) - { - DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n", - netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1), - node, netconsole)); - Net_UnAcknowledgePacket(node); - break; - } - - // check if tic that we are making isn't too large else we cannot send it :( - // doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time - j = software_MAXPACKETLENGTH - - (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE - + (doomcom->numslots+1)*sizeof(ticcmd_t)); - - // search a tic that have enougth space in the ticcmd - while ((textcmd = D_GetExistingTextcmd(tic, netconsole)), - (TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD) - && tic < firstticstosend + BACKUPTICS) - tic++; - - if (tic >= firstticstosend + BACKUPTICS) - { - DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, " - "tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)), - maketic, firstticstosend, node, netconsole)); - Net_UnAcknowledgePacket(node); - break; - } - - // Make sure we have a buffer - if (!textcmd) textcmd = D_GetTextcmd(tic, netconsole); - - DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n", - tic, textcmd[0]+1, netconsole, firstticstosend, maketic)); - - M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]); - textcmd[0] += (UINT8)netbuffer->u.textcmd[0]; - } + PT_TextCmd(netconsole, node); break; case PT_NODETIMEOUT: case PT_CLIENTQUIT: - if (client) - break; - - // nodeingame will be put false in the execution of kick command - // this allow to send some packets to the quitting client to have their ack back - nodewaiting[node] = 0; - if (netconsole != -1 && playeringame[netconsole]) - { - SendKick(netconsole, (netbuffer->packettype == PT_NODETIMEOUT) ? KICK_MSG_TIMEOUT : KICK_MSG_PLAYER_QUIT); - } - Net_CloseConnection(node); - nodeingame[node] = false; + PT_ClientQuit(netconsole, node); break; // -------------------------------------------- CLIENT RECEIVE ---------- case PT_RESYNCHEND: - // Only accept PT_RESYNCHEND from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHEND", node); - - if (server) - { - SendKick(node, KICK_MSG_CON_FAIL); - } - - break; - } - resynch_local_inprogress = false; - - P_SetRandSeed(netbuffer->u.resynchend.randomseed); - - if (gametype == GT_CTF) - resynch_read_ctf(&netbuffer->u.resynchend); - resynch_read_others(&netbuffer->u.resynchend); - + PT_Resynched(node); break; case PT_SERVERTICS: - // Only accept PT_SERVERTICS from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node); - - if (server) - { - SendKick(node, KICK_MSG_CON_FAIL); - } - - break; - } - - realstart = ExpandTics(netbuffer->u.serverpak.starttic, maketic); - realend = realstart + netbuffer->u.serverpak.numtics; - - if (!txtpak) - txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots - * netbuffer->u.serverpak.numtics]; - - if (realend > gametic + CLIENTBACKUPTICS) - realend = gametic + CLIENTBACKUPTICS; - cl_packetmissed = realstart > neededtic; - - if (realstart <= neededtic && realend > neededtic) - { - tic_t i, j; - pak = (UINT8 *)&netbuffer->u.serverpak.cmds; - - for (i = realstart; i < realend; i++) - { - // clear first - D_Clearticcmd(i); - - // copy the tics - pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak, - netbuffer->u.serverpak.numslots*sizeof (ticcmd_t)); - - // copy the textcmds - numtxtpak = *txtpak++; - - for (j = 0; j < numtxtpak; j++) - { - INT32 playernum = *txtpak++; // playernum - const size_t txtsize = txtpak[0]+1; - - if (playernum < 0 || playernum >= MAXPLAYERS) - { - CONS_Alert(CONS_WARNING, "Got bogus NetXCmd packet targetting player %d\n", playernum); - return; - } - - if (i >= gametic) // Don't copy old net commands - M_Memcpy(D_GetTextcmd(i, playernum), txtpak, txtsize); - txtpak += txtsize; - } - } - - neededtic = realend; - } - else - { - DEBFILE(va("frame not in bound: %u (bounds are from %u to %u)\n", neededtic, realstart, realend)); - /*if (realend < neededtic - 2 * TICRATE || neededtic + 2 * TICRATE < realstart) - I_Error("Received an out of order PT_SERVERTICS packet!\n" - "Got tics %d-%d, needed tic %d\n\n" - "Please report this crash on the Master Board,\n" - "IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/ - } + PT_ServerTics(node); break; case PT_RESYNCHING: - // Only accept PT_RESYNCHING from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHING", node); - - if (server) - { - SendKick(node, KICK_MSG_CON_FAIL); - } - - break; - } - resynch_local_inprogress = true; - CL_AcknowledgeResynch(&netbuffer->u.resynchpak); + PT_Resynching(node); break; case PT_PING: - // Only accept PT_PING from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node); - - if (server) - { - SendKick(node, KICK_MSG_CON_FAIL); - } - - break; - } - - // Update client ping table from the server. - if (client) - { - UINT8 i; - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i]; - - servermaxping = (tic_t)netbuffer->u.pingtable[MAXPLAYERS]; - } - + PT_Ping(node); break; case PT_SERVERCFG: break; case PT_FILEFRAGMENT: - // Only accept PT_FILEFRAGMENT from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node); - - if (server) - { - SendKick(node, KICK_MSG_CON_FAIL); - } - - break; - } - if (client) - Got_Filetxpak(); + PT_FileFragmentFromPlayer(node); break; #ifdef SATURNPAK case PT_CANRECEIVEGAMESTATE: PT_CanReceiveGamestate(node); break; case PT_RECEIVEDGAMESTATE: - sendingsavegame[node] = false; - resendingsavegame[node] = false; - savegameresendcooldown[node] = I_GetTime() + cv_resynchcooldown.value * TICRATE; // I_GetTime() + 5 * TICRATE; + PT_ReceivedGamestate(node); break; case PT_WILLRESENDGAMESTATE: PT_WillResendGamestate(); @@ -5908,9 +5985,8 @@ static void HandlePacketFromPlayer(SINT8 node) break; #endif default: - DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n", - netbuffer->packettype, node)); - } // end switch + DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n", netbuffer->packettype, node)); + } } /** Handles all received packets, if any -- 2.54.0 From ccc90842a7fe2d796b39af2e1e54fc65862fa38e Mon Sep 17 00:00:00 2001 From: Alug Date: Thu, 12 Jun 2025 17:09:26 +0200 Subject: [PATCH 14/15] move CopyCaretColors to m_misc --- src/d_clisrv.c | 117 +------------------------------------------------ src/m_misc.c | 66 ++++++++++++++++++++++++++++ src/m_misc.h | 2 + 3 files changed, 69 insertions(+), 116 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 298f5f9ee..77b18ef8b 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -567,58 +567,7 @@ void SendKick(UINT8 playernum, UINT8 msg) // end of extra data function // ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// extra data function for lmps -// ----------------------------------------------------------------- - -// if extradatabit is set, after the ziped tic you find this: -// -// type | description -// ---------+-------------- -// byte | size of the extradata -// byte | the extradata (xd) bits: see XD_... -// with this byte you know what parameter folow -// if (xd & XDNAMEANDCOLOR) -// byte | color -// char[MAXPLAYERNAME] | name of the player -// endif -// if (xd & XD_WEAPON_PREF) -// byte | original weapon switch: boolean, true if use the old -// | weapon switch methode -// char[NUMWEAPONS] | the weapon switch priority -// byte | autoaim: true if use the old autoaim system -// endif -/*boolean AddLmpExtradata(UINT8 **demo_point, INT32 playernum) -{ - UINT8 *textcmd = D_GetExistingTextcmd(gametic, playernum); - - if (!textcmd) - return false; - - M_Memcpy(*demo_point, textcmd, textcmd[0]+1); - *demo_point += textcmd[0]+1; - return true; -} - -void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum) -{ - UINT8 nextra; - UINT8 *textcmd; - - if (!demo_pointer) - return; - - textcmd = D_GetTextcmd(gametic, playernum); - nextra = **demo_pointer; - M_Memcpy(textcmd, *demo_pointer, nextra + 1); - // increment demo pointer - *demo_pointer += nextra + 1; -}*/ - -// ----------------------------------------------------------------- -// end extra data function for lmps -// ----------------------------------------------------------------- - +// can we get rid of this finally lmao // ----------------------------------------------------------------- // resynch player data // ----------------------------------------------------------------- @@ -1590,70 +1539,6 @@ static boolean CL_SendJoin(void) return HSendPacket(servernode, false, 0, sizeof (clientconfig_pak)); } -static void -CopyCaretColors (char *p, const char *s, int n) -{ - char *t; - int m; - int c; - if (!n) - return; - while (( t = strchr(s, '^') )) - { - m = ( t - s ); - - if (m >= n) - { - memcpy(p, s, n); - return; - } - else - memcpy(p, s, m); - - p += m; - n -= m; - s += m; - - if (!n) - return; - - if (s[1]) - { - c = toupper(s[1]); - if (isdigit(c)) - c = 0x80 + ( c - '0' ); - else if (c >= 'A' && c <= 'F') - c = 0x80 + ( c - 'A' ); - else - c = 0; - - if (c) - { - *p++ = c; - n--; - - if (!n) - return; - } - else - { - if (n < 2) - break; - - memcpy(p, s, 2); - - p += 2; - n -= 2; - } - - s += 2; - } - else - break; - } - strncpy(p, s, n); -} - static void SV_SendServerInfo(INT32 node, tic_t servertime) { UINT8 *p; diff --git a/src/m_misc.c b/src/m_misc.c index 944fbb73c..5a2bc44e3 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -1805,6 +1805,72 @@ INT32 axtoi(const char *hexStg) return intValue; } +void CopyCaretColors(char *p, const char *s, int n) +{ + char *t; + int m; + int c; + + if (!n) + return; + + while (( t = strchr(s, '^') )) + { + m = ( t - s ); + + if (m >= n) + { + memcpy(p, s, n); + return; + } + else + memcpy(p, s, m); + + p += m; + n -= m; + s += m; + + if (!n) + return; + + if (s[1]) + { + c = toupper(s[1]); + if (isdigit(c)) + c = 0x80 + ( c - '0' ); + else if (c >= 'A' && c <= 'F') + c = 0x80 + ( c - 'A' ); + else + c = 0; + + if (c) + { + *p++ = c; + n--; + + if (!n) + return; + } + else + { + if (n < 2) + break; + + memcpy(p, s, 2); + + p += 2; + n -= 2; + } + + s += 2; + } + else + break; + } + + strncpy(p, s, n); +} + /** Token parser for TEXTURES, ANIMDEFS, and potentially other lumps later down the line. * Was originally R_GetTexturesToken when I was coding up the TEXTURES parser, until I realized I needed it for ANIMDEFS too. * Parses up to the next whitespace character or comma. When finding the start of the next token, whitespace is skipped. diff --git a/src/m_misc.h b/src/m_misc.h index 98fbdaee7..eed9cf552 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -81,6 +81,8 @@ void M_SaveConfig(const char *filename); INT32 axtoi(const char *hexStg); +void CopyCaretColors(char *p, const char *s, int n); + const char *GetRevisionString(void); // Vector/matrix math -- 2.54.0 From 48d9b2bc98075779467ddedaad45760751e74dd6 Mon Sep 17 00:00:00 2001 From: Alug Date: Sat, 26 Jul 2025 16:17:58 +0200 Subject: [PATCH 15/15] reduce netbuffer scope even further --- src/d_clisrv.c | 72 +++++++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 45 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 7187be3a2..5f6a83c8f 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1038,8 +1038,6 @@ static void SV_SendResynch(INT32 node) { INT32 i, j; - doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); - if (!nodeingame[node]) { // player left during resynch @@ -1048,6 +1046,8 @@ static void SV_SendResynch(INT32 node) return; } + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + // resynched? if (!resynch_status[node]) { @@ -1937,8 +1937,6 @@ static void CL_LoadReceivedSavegame(boolean reloading) size_t length, decompressedlen; char tmpsave[264]; - doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); - sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); length = FIL_ReadFile(tmpsave, &save.buffer); @@ -2001,6 +1999,7 @@ static void CL_LoadReceivedSavegame(boolean reloading) // so they know they can resume the game if (reloading) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); netbuffer->packettype = PT_RECEIVEDGAMESTATE; HSendPacket(servernode, true, 0, 0); } @@ -2045,6 +2044,8 @@ static void CL_ReloadReceivedSavegame(void) static void SendAskInfo(INT32 node) { tic_t asktime; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + #ifdef HOLEPUNCH if (node != 0 && node != BROADCASTADDR && cv_rendezvousserver.string[0]) @@ -2055,8 +2056,6 @@ static void SendAskInfo(INT32 node) asktime = I_GetTime(); - doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); - netbuffer->packettype = PT_ASKINFO; netbuffer->u.askinfo.version = VERSION; netbuffer->u.askinfo.time = (tic_t)LONG(asktime); @@ -4045,8 +4044,6 @@ static void Command_ResendGamestate(void) { SINT8 playernum; - doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); - if (COM_Argc() == 1) { CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); @@ -4062,6 +4059,8 @@ static void Command_ResendGamestate(void) if (playernum == -1 || playernum == 0) return; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on netbuffer->packettype = PT_WILLRESENDGAMESTATE; @@ -4694,6 +4693,8 @@ static size_t TotalTextCmdPerTic(tic_t tic) */ static void HandleConnect(SINT8 node) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + // Sal: Dedicated mode is INCREDIBLY hacked together. // If a server filled out, then it'd overwrite the host and turn everyone into weird husks..... // It's too much effort to legimately fix right now. Just prevent it from reaching that state. @@ -4704,8 +4705,6 @@ static void HandleConnect(SINT8 node) if (playernode[i] != UINT8_MAX) // We use this to count players because it is affected by SV_AddWaitingPlayers when more than one client joins on the same tic, unlike playeringame and D_NumPlayers. UINT8_MAX denotes no node for that player connectedplayers++; - doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); - if (bannednode && bannednode[node].banid != SIZE_MAX) { const char *reason = NULL; @@ -4923,10 +4922,9 @@ static void HandlePlayerInfo(void) static void PT_TellFilesNeeded(SINT8 node) { - doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); - if (server && serverrunning) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); UINT8 *p; INT32 firstfile = netbuffer->u.filesneedednum; @@ -4944,8 +4942,6 @@ static void PT_TellFilesNeeded(SINT8 node) static void PT_MoreFilesNeeded(SINT8 node) { - doomdata_t *netbuffer; - if (server && serverrunning) { // But wait I thought I'm the server? Net_CloseConnection(node); @@ -4955,7 +4951,7 @@ static void PT_MoreFilesNeeded(SINT8 node) if (ServerOnly(node)) return; - netbuffer = DOOMCOM_DATA(doomcom); + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum) { @@ -4967,10 +4963,9 @@ static void PT_MoreFilesNeeded(SINT8 node) static void PT_AskInfo(SINT8 node) { - doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); - if (server && serverrunning) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); SV_SendPlayerInfo(node); // Send extra info } @@ -4981,8 +4976,6 @@ static void PT_AskInfo(SINT8 node) // Negative response of client join request static void PT_ServerRefuse(SINT8 node) { - doomdata_t *netbuffer; - if (server && serverrunning) { // But wait I thought I'm the server? Net_CloseConnection(node); @@ -4995,7 +4988,7 @@ static void PT_ServerRefuse(SINT8 node) if (cl_mode != CL_WAITJOINRESPONSE) return; - netbuffer = DOOMCOM_DATA(doomcom); + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); // Save the reason so it can be displayed after quitting the netgame char *reason = strdup(netbuffer->u.serverrefuse.reason); @@ -5040,7 +5033,6 @@ static void PT_ServerCFG(SINT8 node) { INT32 j; UINT8 *scp; - doomdata_t *netbuffer; if (server && serverrunning && node != servernode) { // but wait I thought I'm the server? @@ -5055,7 +5047,7 @@ static void PT_ServerCFG(SINT8 node) if (!(cl_mode == CL_WAITJOINRESPONSE || cl_mode == CL_ASKJOIN)) return; - netbuffer = DOOMCOM_DATA(doomcom); + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); if (client) { @@ -5201,7 +5193,7 @@ static void HandlePacketFromAwayNode(SINT8 node) { doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); - if (node != servernode) + if (UNLIKELY(node != servernode)) DEBFILE(va("Received packet from unknown host %d\n", node)); switch (netbuffer->packettype) @@ -5277,7 +5269,6 @@ static boolean CheckForSpeedHacks(UINT8 p) static void PT_ClientCmd(INT32 netconsole, SINT8 node) { - doomdata_t *netbuffer; tic_t realend, realstart; if (client) @@ -5287,7 +5278,7 @@ static void PT_ClientCmd(INT32 netconsole, SINT8 node) if (resynch_inprogress[node]) return; - netbuffer = DOOMCOM_DATA(doomcom); + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); // To save bytes, only the low byte of tic numbers are sent // Use ExpandTics to figure out what the rest of the bytes are @@ -5499,12 +5490,10 @@ static void PT_BasicKeepAlive(INT32 netconsole, SINT8 node) static void PT_TextCmd(INT32 netconsole, SINT8 node) { - doomdata_t *netbuffer; - if (client) return; - netbuffer = DOOMCOM_DATA(doomcom); + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); switch (netbuffer->packettype) { @@ -5585,18 +5574,16 @@ static void PT_TextCmd(INT32 netconsole, SINT8 node) static void PT_ClientQuit(INT32 netconsole, SINT8 node) { - doomdata_t *netbuffer; if (client) return; - netbuffer = DOOMCOM_DATA(doomcom); - // nodeingame will be put false in the execution of kick command // this allow to send some packets to the quitting client to have their ack back nodewaiting[node] = 0; if (netconsole != -1 && playeringame[netconsole]) { + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); SendKick(netconsole, (netbuffer->packettype == PT_NODETIMEOUT) ? KICK_MSG_TIMEOUT : KICK_MSG_PLAYER_QUIT); } Net_CloseConnection(node); @@ -5623,16 +5610,14 @@ static boolean FromServer(SINT8 node, const char *str) static void PT_Resynched(SINT8 node) { - doomdata_t *netbuffer; - // Only accept PT_RESYNCHEND from the server. if (!FromServer(node, "PT_RESYNCHEND")) return; - netbuffer = DOOMCOM_DATA(doomcom); - resynch_local_inprogress = false; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); + P_SetRandSeed(netbuffer->u.resynchend.randomseed); if (gametype == GT_CTF) @@ -5642,7 +5627,6 @@ static void PT_Resynched(SINT8 node) static void PT_ServerTics(SINT8 node) { - doomdata_t *netbuffer; tic_t realend, realstart; UINT8 *pak, *txtpak = NULL, numtxtpak; @@ -5650,7 +5634,7 @@ static void PT_ServerTics(SINT8 node) if (!FromServer(node, "PT_SERVERTICS")) return; - netbuffer = DOOMCOM_DATA(doomcom); + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); realstart = ExpandTics(netbuffer->u.serverpak.starttic, maketic); realend = realstart + netbuffer->u.serverpak.numtics; @@ -5712,22 +5696,18 @@ static void PT_ServerTics(SINT8 node) static void PT_Resynching(SINT8 node) { - doomdata_t *netbuffer; - // Only accept PT_RESYNCHING from the server. if (!FromServer(node, "PT_RESYNCHING")) return; - netbuffer = DOOMCOM_DATA(doomcom); - resynch_local_inprogress = true; + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); CL_AcknowledgeResynch(&netbuffer->u.resynchpak); } static void PT_Ping(SINT8 node) { UINT8 i; - doomdata_t *netbuffer; // Only accept PT_PING from the server. if (!FromServer(node, "PT_PING")) @@ -5736,7 +5716,7 @@ static void PT_Ping(SINT8 node) if (!client) return; - netbuffer = DOOMCOM_DATA(doomcom); + doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); // Update client ping table from the server. for (i = 0; i < MAXPLAYERS; i++) @@ -5883,6 +5863,7 @@ static void GetPackets(void) } continue; } + if (node == servernode && client && cl_mode != CL_SEARCHING) { if (netbuffer->packettype == PT_SERVERSHUTDOWN) @@ -6404,7 +6385,7 @@ static void Local_Maketic(INT32 realtics) { INT32 i; - I_OsPolling(); // I_Getevent + I_OsPolling(); // I_Getevent D_ProcessEvents(); // menu responder, cons responder, // game responder calls HU_Responder, AM_Responder, F_Responder, // and G_MapEventsToControls @@ -7012,7 +6993,7 @@ void NetUpdate(void) SV_Maketic(); // Create missed tics and increment maketic for (; tictoclear < firstticstosend; tictoclear++) // Clear only when acknowledged - D_Clearticcmd(tictoclear); // Clear the maketic the new tic + D_Clearticcmd(tictoclear); // Clear the maketic the new tic SV_SendTics(); @@ -7022,6 +7003,7 @@ void NetUpdate(void) hu_resynching = true; } } + Net_AckTicker(); HandleNodeTimeouts(); -- 2.54.0