From 7c2fe20cd5aa9badc4d7d7fed9561e8bf966997b Mon Sep 17 00:00:00 2001 From: LJ Sonic Date: Thu, 5 Jan 2023 22:51:17 +0100 Subject: [PATCH] Move tic and net command handling to new files --- src/blua/liolib.c | 1 + src/command.c | 1 + src/g_game.c | 1 + src/hu_stuff.c | 1 + src/lua_consolelib.c | 1 + src/netcode/Sourcefile | 2 + src/netcode/d_clisrv.c | 878 +------------------------------- src/netcode/d_clisrv.h | 12 +- src/netcode/d_net.c | 1 + src/netcode/d_netcmd.c | 1 + src/netcode/d_netfil.c | 1 + src/netcode/net_command.c | 315 ++++++++++++ src/netcode/net_command.h | 62 +++ src/netcode/server_connection.c | 1 + src/netcode/tic_command.c | 504 ++++++++++++++++++ src/netcode/tic_command.h | 44 ++ src/p_inter.c | 1 + src/p_mobj.c | 1 + src/p_setup.c | 2 + src/p_tick.c | 1 + src/p_user.c | 1 + 21 files changed, 955 insertions(+), 877 deletions(-) create mode 100644 src/netcode/net_command.c create mode 100644 src/netcode/net_command.h create mode 100644 src/netcode/tic_command.c create mode 100644 src/netcode/tic_command.h diff --git a/src/blua/liolib.c b/src/blua/liolib.c index 8a6354121..bce8e87cc 100644 --- a/src/blua/liolib.c +++ b/src/blua/liolib.c @@ -20,6 +20,7 @@ #include "../i_system.h" #include "../g_game.h" #include "../netcode/d_netfil.h" +#include "../netcode/net_command.h" #include "../lua_libs.h" #include "../byteptr.h" #include "../lua_script.h" diff --git a/src/command.c b/src/command.c index 4e8989fd3..a87a04dcc 100644 --- a/src/command.c +++ b/src/command.c @@ -29,6 +29,7 @@ #include "p_saveg.h" #include "g_game.h" // for player_names #include "netcode/d_netcmd.h" +#include "netcode/net_command.h" #include "hu_stuff.h" #include "p_setup.h" #include "lua_script.h" diff --git a/src/g_game.c b/src/g_game.c index 93b8eb936..17dbff7d3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -16,6 +16,7 @@ #include "d_main.h" #include "d_player.h" #include "netcode/d_clisrv.h" +#include "netcode/net_command.h" #include "f_finale.h" #include "p_setup.h" #include "p_saveg.h" diff --git a/src/hu_stuff.c b/src/hu_stuff.c index e5cf5aeb1..e08351a8a 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -20,6 +20,7 @@ #include "m_misc.h" // word jumping #include "netcode/d_clisrv.h" +#include "netcode/net_command.h" #include "g_game.h" #include "g_input.h" diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 816051199..a1bdf380d 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -16,6 +16,7 @@ #include "g_game.h" #include "byteptr.h" #include "z_zone.h" +#include "netcode/net_command.h" #include "lua_script.h" #include "lua_libs.h" diff --git a/src/netcode/Sourcefile b/src/netcode/Sourcefile index 4177166a4..1039b218a 100644 --- a/src/netcode/Sourcefile +++ b/src/netcode/Sourcefile @@ -1,6 +1,8 @@ d_clisrv.c server_connection.c client_connection.c +tic_command.c +net_command.c d_net.c d_netcmd.c d_netfil.c diff --git a/src/netcode/d_clisrv.c b/src/netcode/d_clisrv.c index c1264768e..06e6da751 100644 --- a/src/netcode/d_clisrv.c +++ b/src/netcode/d_clisrv.c @@ -51,6 +51,8 @@ #include "../m_perfstats.h" #include "server_connection.h" #include "client_connection.h" +#include "tic_command.h" +#include "net_command.h" // // NETWORKING @@ -86,11 +88,9 @@ UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. tic_t servermaxping = 800; // server's max ping. Defaults to 800 -static tic_t firstticstosend; // min of the nettics -static tic_t tictoclear = 0; // optimize d_clearticcmd tic_t maketic; -static INT16 consistancy[BACKUPTICS]; +INT16 consistancy[BACKUPTICS]; UINT8 hu_redownloadinggamestate = 0; @@ -101,14 +101,9 @@ UINT8 adminpassmd5[16]; boolean adminpasswordset = false; // Client specific -static ticcmd_t localcmds; -static ticcmd_t localcmds2; -static boolean cl_packetmissed; // here it is for the secondary local player (splitscreen) static boolean cl_redownloadinggamestate = false; -static UINT8 localtextcmd[MAXTEXTCMD]; -static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen tic_t neededtic; SINT8 servernode = 0; // the number of the server node @@ -116,385 +111,19 @@ SINT8 servernode = 0; // the number of the server node /// \todo WORK! boolean acceptnewnode = true; -// engine - -// Must be a power of two -#define TEXTCMD_HASH_SIZE 4 - -typedef struct textcmdplayer_s -{ - INT32 playernum; - UINT8 cmd[MAXTEXTCMD]; - struct textcmdplayer_s *next; -} textcmdplayer_t; - -typedef struct textcmdtic_s -{ - tic_t tic; - textcmdplayer_t *playercmds[TEXTCMD_HASH_SIZE]; - struct textcmdtic_s *next; -} textcmdtic_t; - -ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; -static textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL}; - - consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}}; consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL); -static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n) -{ - const size_t d = n / sizeof(ticcmd_t); - const size_t r = n % sizeof(ticcmd_t); - UINT8 *ret = dest; - - if (r) - M_Memcpy(dest, src, n); - else if (d) - G_MoveTiccmd(dest, src, d); - return ret+n; -} - -static inline void *G_ScpyTiccmd(ticcmd_t* dest, void* src, const size_t n) -{ - const size_t d = n / sizeof(ticcmd_t); - const size_t r = n % sizeof(ticcmd_t); - UINT8 *ret = src; - - if (r) - M_Memcpy(dest, src, n); - else if (d) - G_MoveTiccmd(dest, src, d); - return ret+n; -} - - - // Some software don't support largest packet // (original sersetup, not exactely, but the probability of sending a packet // of 512 bytes is like 0.1) UINT16 software_MAXPACKETLENGTH; -/** Guesses the full value of a tic from its lowest byte, for a specific node - * - * \param low The lowest byte of the tic value - * \param node The node to deduce the tic for - * \return The full tic value - * - */ -tic_t ExpandTics(INT32 low, INT32 node) -{ - INT32 delta; - - delta = low - (netnodes[node].tic & UINT8_MAX); - - if (delta >= -64 && delta <= 64) - return (netnodes[node].tic & ~UINT8_MAX) + low; - else if (delta > 64) - return (netnodes[node].tic & ~UINT8_MAX) - 256 + low; - else //if (delta < -64) - return (netnodes[node].tic & ~UINT8_MAX) + 256 + low; -} - -// ----------------------------------------------------------------- -// Some extra data function for handle textcmd buffer -// ----------------------------------------------------------------- - -static void (*listnetxcmd[MAXNETXCMD])(UINT8 **p, INT32 playernum); - -void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)) -{ -#ifdef PARANOIA - if (id >= MAXNETXCMD) - I_Error("Command id %d too big", id); - if (listnetxcmd[id] != 0) - I_Error("Command id %d already used", id); -#endif - listnetxcmd[id] = cmd_f; -} - -void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam) -{ - if (localtextcmd[0]+2+nparam > MAXTEXTCMD) - { - // for future reference: if (cv_debug) != debug disabled. - CONS_Alert(CONS_ERROR, M_GetText("NetXCmd buffer full, cannot add netcmd %d! (size: %d, needed: %s)\n"), id, localtextcmd[0], sizeu1(nparam)); - return; - } - localtextcmd[0]++; - localtextcmd[localtextcmd[0]] = (UINT8)id; - if (param && nparam) - { - M_Memcpy(&localtextcmd[localtextcmd[0]+1], param, nparam); - localtextcmd[0] = (UINT8)(localtextcmd[0] + (UINT8)nparam); - } -} - -// splitscreen player -void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam) -{ - if (localtextcmd2[0]+2+nparam > MAXTEXTCMD) - { - I_Error("No more place in the buffer for netcmd %d\n",id); - return; - } - localtextcmd2[0]++; - localtextcmd2[localtextcmd2[0]] = (UINT8)id; - if (param && nparam) - { - M_Memcpy(&localtextcmd2[localtextcmd2[0]+1], param, nparam); - localtextcmd2[0] = (UINT8)(localtextcmd2[0] + (UINT8)nparam); - } -} - -UINT8 GetFreeXCmdSize(void) -{ - // -1 for the size and another -1 for the ID. - return (UINT8)(localtextcmd[0] - 2); -} - -// Frees all textcmd memory for the specified tic -static void D_FreeTextcmd(tic_t tic) -{ - textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - textcmdtic_t *textcmdtic = *tctprev; - - while (textcmdtic && textcmdtic->tic != tic) - { - tctprev = &textcmdtic->next; - textcmdtic = textcmdtic->next; - } - - if (textcmdtic) - { - INT32 i; - - // Remove this tic from the list. - *tctprev = textcmdtic->next; - - // Free all players. - for (i = 0; i < TEXTCMD_HASH_SIZE; i++) - { - textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[i]; - - while (textcmdplayer) - { - textcmdplayer_t *tcpnext = textcmdplayer->next; - Z_Free(textcmdplayer); - textcmdplayer = tcpnext; - } - } - - // Free this tic's own memory. - Z_Free(textcmdtic); - } -} - -// Gets the buffer for the specified ticcmd, or NULL if there isn't one -static UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum) -{ - textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - while (textcmdtic && textcmdtic->tic != tic) textcmdtic = textcmdtic->next; - - // Do we have an entry for the tic? If so, look for player. - if (textcmdtic) - { - textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; - while (textcmdplayer && textcmdplayer->playernum != playernum) textcmdplayer = textcmdplayer->next; - - if (textcmdplayer) return textcmdplayer->cmd; - } - - return NULL; -} - -// Gets the buffer for the specified ticcmd, creating one if necessary -static UINT8* D_GetTextcmd(tic_t tic, INT32 playernum) -{ - textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; - textcmdplayer_t *textcmdplayer, **tcpprev; - - // Look for the tic. - while (textcmdtic && textcmdtic->tic != tic) - { - tctprev = &textcmdtic->next; - textcmdtic = textcmdtic->next; - } - - // If we don't have an entry for the tic, make it. - if (!textcmdtic) - { - textcmdtic = *tctprev = Z_Calloc(sizeof (textcmdtic_t), PU_STATIC, NULL); - textcmdtic->tic = tic; - } - - tcpprev = &textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; - textcmdplayer = *tcpprev; - - // Look for the player. - while (textcmdplayer && textcmdplayer->playernum != playernum) - { - tcpprev = &textcmdplayer->next; - textcmdplayer = textcmdplayer->next; - } - - // If we don't have an entry for the player, make it. - if (!textcmdplayer) - { - textcmdplayer = *tcpprev = Z_Calloc(sizeof (textcmdplayer_t), PU_STATIC, NULL); - textcmdplayer->playernum = playernum; - } - - return textcmdplayer->cmd; -} - -static void ExtraDataTicker(void) -{ - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] || i == 0) - { - UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i); - - if (bufferstart) - { - UINT8 *curpos = bufferstart; - UINT8 *bufferend = &curpos[curpos[0]+1]; - - curpos++; - while (curpos < bufferend) - { - if (*curpos < MAXNETXCMD && listnetxcmd[*curpos]) - { - const UINT8 id = *curpos; - curpos++; - DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i)); - (listnetxcmd[id])(&curpos, i); - DEBFILE("done\n"); - } - else - { - if (server) - { - SendKick(i, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic)); - } - CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]); - break; - } - } - } - } - - // If you are a client, you can safely forget the net commands for this tic - // If you are the server, you need to remember them until every client has been acknowledged, - // because if you need to resend a PT_SERVERTICS packet, you will need to put the commands in it - if (client) - D_FreeTextcmd(gametic); -} - -static void D_Clearticcmd(tic_t tic) -{ - INT32 i; - - D_FreeTextcmd(tic); - - for (i = 0; i < MAXPLAYERS; i++) - netcmds[tic%BACKUPTICS][i].angleturn = 0; - - DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS)); -} - -void D_ResetTiccmds(void) -{ - INT32 i; - - memset(&localcmds, 0, sizeof(ticcmd_t)); - memset(&localcmds2, 0, sizeof(ticcmd_t)); - - // Reset the net command list - for (i = 0; i < TEXTCMD_HASH_SIZE; i++) - while (textcmds[i]) - D_Clearticcmd(textcmds[i]->tic); -} - -void SendKick(UINT8 playernum, UINT8 msg) -{ - UINT8 buf[2]; - - if (!(server && cv_rejointimeout.value)) - msg &= ~KICK_MSG_KEEP_BODY; - - buf[0] = playernum; - buf[1] = msg; - SendNetXCmd(XD_KICK, &buf, 2); -} - -// ----------------------------------------------------------------- -// 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 -// ----------------------------------------------------------------- - -static INT16 Consistancy(void); - #define SAVEGAMESIZE (768*1024) -static boolean SV_ResendingSavegameToAnyone(void) +boolean SV_ResendingSavegameToAnyone(void) { INT32 i; @@ -2005,22 +1634,6 @@ void SV_StartSinglePlayerServer(void) multiplayer = true; } -// used at txtcmds received to check packetsize bound -static size_t TotalTextCmdPerTic(tic_t tic) -{ - INT32 i; - size_t total = 1; // num of textcmds in the tic (ntextcmd byte) - - for (i = 0; i < MAXPLAYERS; i++) - { - UINT8 *textcmd = D_GetExistingTextcmd(tic, i); - if ((!i || playeringame[i]) && textcmd) - total += 2 + textcmd[0]; // "+2" for size and playernum - } - - return total; -} - /** Called when a PT_SERVERSHUTDOWN packet is received * * \param node The packet sender (should be the server) @@ -2051,168 +1664,6 @@ static void HandleTimeout(SINT8 node) M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING); } -static void PT_ClientCmd(SINT8 node, INT32 netconsole) -{ - tic_t realend, realstart; - - if (client) - return; - - // 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, node); - realend = ExpandTics(netbuffer->u.clientpak.resendfrom, node); - - if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS - || netbuffer->packettype == PT_NODEKEEPALIVEMIS - || netnodes[node].supposedtic < realend) - { - netnodes[node].supposedtic = realend; - } - // Discard out of order packet - if (netnodes[node].tic > realend) - { - DEBFILE(va("out of order ticcmd discarded nettics = %u\n", netnodes[node].tic)); - return; - } - - // Update the nettics - netnodes[node].tic = realend; - - // Don't do anything for packets of type NODEKEEPALIVE? - if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE - || netbuffer->packettype == PT_NODEKEEPALIVEMIS) - return; - - // 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? - netnodes[node].freezetimeout = I_GetTime() + connectiontimeout; - - // Copy ticcmd - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); - - // Check ticcmd for "speed hacks" - if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE - || netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE) - { - CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole); - //D_Clearticcmd(k); - - SendKick(netconsole, KICK_MSG_CON_FAIL); - return; - } - - // Splitscreen cmd - if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) - && netnodes[node].player2 >= 0) - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)netnodes[node].player2], - &netbuffer->u.client2pak.cmd2, 1); - - // Check player consistancy during the level - if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL - && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) - && !SV_ResendingSavegameToAnyone() - && !netnodes[node].resendingsavegame && netnodes[node].savegameresendcooldown <= I_GetTime()) - { - if (cv_resynchattempts.value) - { - // Tell the client we are about to resend them the gamestate - netbuffer->packettype = PT_WILLRESENDGAMESTATE; - HSendPacket(node, true, 0, 0); - - netnodes[node].resendingsavegame = true; - - 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 | KICK_MSG_KEEP_BODY); - DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", - netconsole, realstart, consistancy[realstart%BACKUPTICS], - SHORT(netbuffer->u.clientpak.consistancy))); - return; - } - } -} - -static void PT_TextCmd(SINT8 node, INT32 netconsole) -{ - if (client) - return; - - // splitscreen special - if (netbuffer->packettype == PT_TEXTCMD2) - netconsole = netnodes[node].player2; - - 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_Login(SINT8 node, INT32 netconsole) { (void)node; @@ -2314,81 +1765,6 @@ static void PT_ReceivedGamestate(SINT8 node) netnodes[node].savegameresendcooldown = I_GetTime() + 5 * TICRATE; } -static void PT_ServerTics(SINT8 node, INT32 netconsole) -{ - UINT8 *pak, *txtpak, numtxtpak; - tic_t realend, realstart; - - if (!netnodes[node].ingame) - { - // Do not remove my own server (we have just get a out of order packet) - if (node != servernode) - { - DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype)); - Net_CloseConnection(node); - } - return; - } - - // 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(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - return; - } - - realstart = netbuffer->u.serverpak.starttic; - realend = realstart + 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) - { - 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 k = *txtpak++; // playernum - const size_t txtsize = txtpak[0]+1; - - if (i >= gametic) // Don't copy old net commands - M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize); - txtpak += txtsize; - } - } - - neededtic = realend; - } - else - { - DEBFILE(va("frame not in bound: %u\n", neededtic)); - /*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_Ping(SINT8 node, INT32 netconsole) { // Only accept PT_PING from the server. @@ -2602,7 +1978,7 @@ void GetPackets(void) // no more use random generator, because at very first tic isn't yet synchronized // Note: It is called consistAncy on purpose. // -static INT16 Consistancy(void) +INT16 Consistancy(void) { INT32 i; UINT32 ret = 0; @@ -2708,239 +2084,11 @@ static INT16 Consistancy(void) return (INT16)(ret & 0xFFFF); } -// send the client packet to the server -static void CL_SendClientCmd(void) -{ - size_t packetsize = 0; - - netbuffer->packettype = PT_CLIENTCMD; - - if (cl_packetmissed) - netbuffer->packettype++; - netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX); - netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX); - - if (gamestate == GS_WAITINGPLAYERS) - { - // Send PT_NODEKEEPALIVE packet - netbuffer->packettype += 4; - packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16); - HSendPacket(servernode, false, 0, packetsize); - } - else if (gamestate != GS_NULL && (addedtogame || dedicated)) - { - G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1); - netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]); - - // Send a special packet with 2 cmd for splitscreen - if (splitscreen || botingame) - { - netbuffer->packettype += 2; - G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1); - packetsize = sizeof (client2cmd_pak); - } - else - packetsize = sizeof (clientcmd_pak); - - HSendPacket(servernode, false, 0, packetsize); - } - - if (cl_mode == CL_CONNECTED || dedicated) - { - // Send extra data if needed - if (localtextcmd[0]) - { - netbuffer->packettype = PT_TEXTCMD; - M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1); - // All extra data have been sent - if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail... - localtextcmd[0] = 0; - } - - // Send extra data if needed for player 2 (splitscreen) - if (localtextcmd2[0]) - { - netbuffer->packettype = PT_TEXTCMD2; - M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1); - // All extra data have been sent - if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail... - localtextcmd2[0] = 0; - } - } -} - -// send the server packet -// send tic from firstticstosend to maketic-1 -static void SV_SendTics(void) -{ - tic_t realfirsttic, lasttictosend, i; - UINT32 n; - INT32 j; - size_t packsize; - UINT8 *bufpos; - UINT8 *ntextcmd; - - // send to all client but not to me - // for each node create a packet with x tics and send it - // x is computed using netnodes[n].supposedtic, max packet size and maketic - for (n = 1; n < MAXNETNODES; n++) - if (netnodes[n].ingame) - { - // assert netnodes[n].supposedtic>=netnodes[n].tic - realfirsttic = netnodes[n].supposedtic; - lasttictosend = min(maketic, netnodes[n].tic + 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, maketic, netnodes[n].supposedtic, netnodes[n].tic)); - realfirsttic = netnodes[n].tic; - if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) - // all tic are ok - continue; - DEBFILE(va("Sent %d anyway\n", realfirsttic)); - } - if (realfirsttic < firstticstosend) - realfirsttic = firstticstosend; - - // 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; - packsize += TotalTextCmdPerTic(i); - - if (packsize > software_MAXPACKETLENGTH) - { - DEBFILE(va("packet too large (%s) at tic %d (should be from %d to %d)\n", - sizeu1(packsize), i, realfirsttic, lasttictosend)); - lasttictosend = i; - - // too bad: too much player have send extradata and there is too - // much data in one tic. - // To avoid it put the data on the next tic. (see getpacket - // textcmd case) but when numplayer changes the computation can be different - if (lasttictosend == realfirsttic) - { - if (packsize > MAXPACKETLENGTH) - I_Error("Too many players: can't send %s data for %d players to node %d\n" - "Well sorry nobody is perfect....\n", - sizeu1(packsize), doomcom->numslots, n); - else - { - lasttictosend++; // send it anyway! - DEBFILE("sending it anyway\n"); - } - } - break; - } - } - - // Send the tics - netbuffer->packettype = PT_SERVERTICS; - netbuffer->u.serverpak.starttic = realfirsttic; - netbuffer->u.serverpak.numtics = (UINT8)(lasttictosend - realfirsttic); - netbuffer->u.serverpak.numslots = (UINT8)SHORT(doomcom->numslots); - bufpos = (UINT8 *)&netbuffer->u.serverpak.cmds; - - for (i = realfirsttic; i < lasttictosend; i++) - { - bufpos = G_DcpyTiccmd(bufpos, netcmds[i%BACKUPTICS], doomcom->numslots * sizeof (ticcmd_t)); - } - - // add textcmds - for (i = realfirsttic; i < lasttictosend; i++) - { - ntextcmd = bufpos++; - *ntextcmd = 0; - for (j = 0; j < MAXPLAYERS; j++) - { - UINT8 *textcmd = D_GetExistingTextcmd(i, j); - INT32 size = textcmd ? textcmd[0] : 0; - - if ((!j || playeringame[j]) && size) - { - (*ntextcmd)++; - WRITEUINT8(bufpos, j); - M_Memcpy(bufpos, textcmd, size + 1); - bufpos += size + 1; - } - } - } - 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) - netnodes[n].supposedtic = lasttictosend-doomcom->extratics; - else - netnodes[n].supposedtic = lasttictosend; - if (netnodes[n].supposedtic < netnodes[n].tic) netnodes[n].supposedtic = netnodes[n].tic; - } - // node 0 is me! - netnodes[0].supposedtic = maketic; -} - -// -// TryRunTics -// -static void Local_Maketic(INT32 realtics) -{ - I_OsPolling(); // I_Getevent - D_ProcessEvents(); // menu responder, cons responder, - // game responder calls HU_Responder, AM_Responder, - // and G_MapEventsToControls - if (!dedicated) rendergametic = gametic; - // translate inputs (keyboard/mouse/gamepad) into game controls - G_BuildTiccmd(&localcmds, realtics, 1); - if (splitscreen || botingame) - G_BuildTiccmd(&localcmds2, realtics, 2); - - localcmds.angleturn |= TICCMD_RECEIVED; - localcmds2.angleturn |= TICCMD_RECEIVED; -} - -// create missed tic -static void SV_Maketic(void) -{ - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - // We didn't receive this tic - if ((netcmds[maketic % BACKUPTICS][i].angleturn & TICCMD_RECEIVED) == 0) - { - ticcmd_t * ticcmd = &netcmds[(maketic ) % BACKUPTICS][i]; - ticcmd_t *prevticcmd = &netcmds[(maketic - 1) % BACKUPTICS][i]; - - if (players[i].quittime) - { - // Copy the angle/aiming from the previous tic - // and empty the other inputs - memset(ticcmd, 0, sizeof(netcmds[0][0])); - ticcmd->angleturn = prevticcmd->angleturn | TICCMD_RECEIVED; - ticcmd->aiming = prevticcmd->aiming; - } - else - { - DEBFILE(va("MISS tic%4d for player %d\n", maketic, i)); - // Copy the input from the previous tic - *ticcmd = *prevticcmd; - ticcmd->angleturn &= ~TICCMD_RECEIVED; - } - } - } - - // all tic are now proceed make the next - maketic++; -} +/* +Ping Update except better: +We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out. +If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave. +*/ boolean TryRunTics(tic_t realtics) { @@ -3049,12 +2197,6 @@ boolean TryRunTics(tic_t realtics) return ticking; } -/* -Ping Update except better: -We call this once per second and check for people's pings. If their ping happens to be too high, we increment some timer and kick them out. -If they're not lagging, decrement the timer by 1. Of course, reset all of this if they leave. -*/ - static INT32 pingtimeout[MAXPLAYERS]; static inline void PingUpdate(void) diff --git a/src/netcode/d_clisrv.h b/src/netcode/d_clisrv.h index b8da645ba..8b73170da 100644 --- a/src/netcode/d_clisrv.h +++ b/src/netcode/d_clisrv.h @@ -378,6 +378,7 @@ extern boolean acceptnewnode; extern SINT8 servernode; extern tic_t maketic; extern tic_t neededtic; +extern INT16 consistancy[BACKUPTICS]; void Command_Ping_f(void); extern tic_t connectiontimeout; @@ -391,20 +392,15 @@ extern consvar_t cv_resynchattempts, cv_blamecfail; extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed; // Used in d_net, the only dependence -tic_t ExpandTics(INT32 low, INT32 node); void D_ClientServerInit(void); -// Initialise the other field -void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)); -void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam); -void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player -void SendKick(UINT8 playernum, UINT8 msg); - // Create any new ticcmds and broadcast to other players. void NetUpdate(void); void GetPackets(void); void ResetNode(INT32 node); +INT16 Consistancy(void); +boolean SV_ResendingSavegameToAnyone(void); void SV_StartSinglePlayerServer(void); void SV_SpawnServer(void); @@ -440,10 +436,8 @@ extern char motd[254], server_context[8]; extern UINT8 playernode[MAXPLAYERS]; INT32 D_NumPlayers(void); -void D_ResetTiccmds(void); tic_t GetLag(INT32 node); -UINT8 GetFreeXCmdSize(void); void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest); diff --git a/src/netcode/d_net.c b/src/netcode/d_net.c index ae0605001..972342282 100644 --- a/src/netcode/d_net.c +++ b/src/netcode/d_net.c @@ -26,6 +26,7 @@ #include "../w_wad.h" #include "d_netfil.h" #include "d_clisrv.h" +#include "tic_command.h" #include "../z_zone.h" #include "i_tcp.h" #include "../d_main.h" // srb2home diff --git a/src/netcode/d_netcmd.c b/src/netcode/d_netcmd.c index fe4cf22bd..0d1785510 100644 --- a/src/netcode/d_netcmd.c +++ b/src/netcode/d_netcmd.c @@ -37,6 +37,7 @@ #include "../m_cheat.h" #include "d_clisrv.h" #include "server_connection.h" +#include "net_command.h" #include "d_net.h" #include "../v_video.h" #include "../d_main.h" diff --git a/src/netcode/d_netfil.c b/src/netcode/d_netfil.c index 80fa06852..e581be2ac 100644 --- a/src/netcode/d_netfil.c +++ b/src/netcode/d_netfil.c @@ -42,6 +42,7 @@ #include "d_net.h" #include "../w_wad.h" #include "d_netfil.h" +#include "net_command.h" #include "../z_zone.h" #include "../byteptr.h" #include "../p_setup.h" diff --git a/src/netcode/net_command.c b/src/netcode/net_command.c new file mode 100644 index 000000000..eeb479d21 --- /dev/null +++ b/src/netcode/net_command.c @@ -0,0 +1,315 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file net_command.c +/// \brief Net command handling + +#include "net_command.h" +#include "tic_command.h" +#include "d_clisrv.h" +#include "i_net.h" +#include "../g_game.h" +#include "../z_zone.h" +#include "../doomtype.h" + +textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL}; +UINT8 localtextcmd[MAXTEXTCMD]; +UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen +static void (*listnetxcmd[MAXNETXCMD])(UINT8 **p, INT32 playernum); + +void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)) +{ +#ifdef PARANOIA + if (id >= MAXNETXCMD) + I_Error("Command id %d too big", id); + if (listnetxcmd[id] != 0) + I_Error("Command id %d already used", id); +#endif + listnetxcmd[id] = cmd_f; +} + +void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam) +{ + if (localtextcmd[0]+2+nparam > MAXTEXTCMD) + { + // for future reference: if (cv_debug) != debug disabled. + CONS_Alert(CONS_ERROR, M_GetText("NetXCmd buffer full, cannot add netcmd %d! (size: %d, needed: %s)\n"), id, localtextcmd[0], sizeu1(nparam)); + return; + } + localtextcmd[0]++; + localtextcmd[localtextcmd[0]] = (UINT8)id; + if (param && nparam) + { + M_Memcpy(&localtextcmd[localtextcmd[0]+1], param, nparam); + localtextcmd[0] = (UINT8)(localtextcmd[0] + (UINT8)nparam); + } +} + +// splitscreen player +void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam) +{ + if (localtextcmd2[0]+2+nparam > MAXTEXTCMD) + { + I_Error("No more place in the buffer for netcmd %d\n",id); + return; + } + localtextcmd2[0]++; + localtextcmd2[localtextcmd2[0]] = (UINT8)id; + if (param && nparam) + { + M_Memcpy(&localtextcmd2[localtextcmd2[0]+1], param, nparam); + localtextcmd2[0] = (UINT8)(localtextcmd2[0] + (UINT8)nparam); + } +} + +UINT8 GetFreeXCmdSize(void) +{ + // -1 for the size and another -1 for the ID. + return (UINT8)(localtextcmd[0] - 2); +} + +// Frees all textcmd memory for the specified tic +void D_FreeTextcmd(tic_t tic) +{ + textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; + textcmdtic_t *textcmdtic = *tctprev; + + while (textcmdtic && textcmdtic->tic != tic) + { + tctprev = &textcmdtic->next; + textcmdtic = textcmdtic->next; + } + + if (textcmdtic) + { + INT32 i; + + // Remove this tic from the list. + *tctprev = textcmdtic->next; + + // Free all players. + for (i = 0; i < TEXTCMD_HASH_SIZE; i++) + { + textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[i]; + + while (textcmdplayer) + { + textcmdplayer_t *tcpnext = textcmdplayer->next; + Z_Free(textcmdplayer); + textcmdplayer = tcpnext; + } + } + + // Free this tic's own memory. + Z_Free(textcmdtic); + } +} + +// Gets the buffer for the specified ticcmd, or NULL if there isn't one +UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum) +{ + textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; + while (textcmdtic && textcmdtic->tic != tic) textcmdtic = textcmdtic->next; + + // Do we have an entry for the tic? If so, look for player. + if (textcmdtic) + { + textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; + while (textcmdplayer && textcmdplayer->playernum != playernum) textcmdplayer = textcmdplayer->next; + + if (textcmdplayer) return textcmdplayer->cmd; + } + + return NULL; +} + +// Gets the buffer for the specified ticcmd, creating one if necessary +UINT8* D_GetTextcmd(tic_t tic, INT32 playernum) +{ + textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; + textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)]; + textcmdplayer_t *textcmdplayer, **tcpprev; + + // Look for the tic. + while (textcmdtic && textcmdtic->tic != tic) + { + tctprev = &textcmdtic->next; + textcmdtic = textcmdtic->next; + } + + // If we don't have an entry for the tic, make it. + if (!textcmdtic) + { + textcmdtic = *tctprev = Z_Calloc(sizeof (textcmdtic_t), PU_STATIC, NULL); + textcmdtic->tic = tic; + } + + tcpprev = &textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)]; + textcmdplayer = *tcpprev; + + // Look for the player. + while (textcmdplayer && textcmdplayer->playernum != playernum) + { + tcpprev = &textcmdplayer->next; + textcmdplayer = textcmdplayer->next; + } + + // If we don't have an entry for the player, make it. + if (!textcmdplayer) + { + textcmdplayer = *tcpprev = Z_Calloc(sizeof (textcmdplayer_t), PU_STATIC, NULL); + textcmdplayer->playernum = playernum; + } + + return textcmdplayer->cmd; +} + +void ExtraDataTicker(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] || i == 0) + { + UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i); + + if (bufferstart) + { + UINT8 *curpos = bufferstart; + UINT8 *bufferend = &curpos[curpos[0]+1]; + + curpos++; + while (curpos < bufferend) + { + if (*curpos < MAXNETXCMD && listnetxcmd[*curpos]) + { + const UINT8 id = *curpos; + curpos++; + DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i)); + (listnetxcmd[id])(&curpos, i); + DEBFILE("done\n"); + } + else + { + if (server) + { + SendKick(i, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic)); + } + CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]); + break; + } + } + } + } + + // If you are a client, you can safely forget the net commands for this tic + // If you are the server, you need to remember them until every client has been acknowledged, + // because if you need to resend a PT_SERVERTICS packet, you will need to put the commands in it + if (client) + D_FreeTextcmd(gametic); +} + +// used at txtcmds received to check packetsize bound +size_t TotalTextCmdPerTic(tic_t tic) +{ + INT32 i; + size_t total = 1; // num of textcmds in the tic (ntextcmd byte) + + for (i = 0; i < MAXPLAYERS; i++) + { + UINT8 *textcmd = D_GetExistingTextcmd(tic, i); + if ((!i || playeringame[i]) && textcmd) + total += 2 + textcmd[0]; // "+2" for size and playernum + } + + return total; +} + +void PT_TextCmd(SINT8 node, INT32 netconsole) +{ + if (client) + return; + + // splitscreen special + if (netbuffer->packettype == PT_TEXTCMD2) + netconsole = netnodes[node].player2; + + 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]; + } +} + +void SendKick(UINT8 playernum, UINT8 msg) +{ + UINT8 buf[2]; + + if (!(server && cv_rejointimeout.value)) + msg &= ~KICK_MSG_KEEP_BODY; + + buf[0] = playernum; + buf[1] = msg; + SendNetXCmd(XD_KICK, &buf, 2); +} diff --git a/src/netcode/net_command.h b/src/netcode/net_command.h new file mode 100644 index 000000000..1fc5035c8 --- /dev/null +++ b/src/netcode/net_command.h @@ -0,0 +1,62 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file net_command.h +/// \brief Net command handling + +#ifndef __D_NET_COMMAND__ +#define __D_NET_COMMAND__ + +#include "d_clisrv.h" +#include "../doomtype.h" + +// Must be a power of two +#define TEXTCMD_HASH_SIZE 4 + +typedef struct textcmdplayer_s +{ + INT32 playernum; + UINT8 cmd[MAXTEXTCMD]; + struct textcmdplayer_s *next; +} textcmdplayer_t; + +typedef struct textcmdtic_s +{ + tic_t tic; + textcmdplayer_t *playercmds[TEXTCMD_HASH_SIZE]; + struct textcmdtic_s *next; +} textcmdtic_t; + +extern textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE]; + +extern UINT8 localtextcmd[MAXTEXTCMD]; +extern UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen + +void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum)); +void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam); +void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player + +UINT8 GetFreeXCmdSize(void); +void D_FreeTextcmd(tic_t tic); + +// Gets the buffer for the specified ticcmd, or NULL if there isn't one +UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum); + +// Gets the buffer for the specified ticcmd, creating one if necessary +UINT8* D_GetTextcmd(tic_t tic, INT32 playernum); + +void ExtraDataTicker(void); + +// used at txtcmds received to check packetsize bound +size_t TotalTextCmdPerTic(tic_t tic); + +void PT_TextCmd(SINT8 node, INT32 netconsole); +void SendKick(UINT8 playernum, UINT8 msg); + +#endif diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c index 9e397b0f3..b776db422 100644 --- a/src/netcode/server_connection.c +++ b/src/netcode/server_connection.c @@ -15,6 +15,7 @@ #include "d_clisrv.h" #include "d_netfil.h" #include "mserv.h" +#include "net_command.h" #include "../byteptr.h" #include "../g_game.h" #include "../g_state.h" diff --git a/src/netcode/tic_command.c b/src/netcode/tic_command.c new file mode 100644 index 000000000..e7df895ff --- /dev/null +++ b/src/netcode/tic_command.c @@ -0,0 +1,504 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file tic_command.c +/// \brief Tic command handling + +#include "tic_command.h" +#include "d_clisrv.h" +#include "net_command.h" +#include "client_connection.h" +#include "i_net.h" +#include "../d_main.h" +#include "../g_game.h" +#include "../i_system.h" +#include "../i_time.h" +#include "../byteptr.h" +#include "../doomstat.h" +#include "../doomtype.h" + +tic_t firstticstosend; // min of the nettics +tic_t tictoclear = 0; // optimize d_clearticcmd +ticcmd_t localcmds; +ticcmd_t localcmds2; +boolean cl_packetmissed; +ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; + +static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n) +{ + const size_t d = n / sizeof(ticcmd_t); + const size_t r = n % sizeof(ticcmd_t); + UINT8 *ret = dest; + + if (r) + M_Memcpy(dest, src, n); + else if (d) + G_MoveTiccmd(dest, src, d); + return ret+n; +} + +static inline void *G_ScpyTiccmd(ticcmd_t* dest, void* src, const size_t n) +{ + const size_t d = n / sizeof(ticcmd_t); + const size_t r = n % sizeof(ticcmd_t); + UINT8 *ret = src; + + if (r) + M_Memcpy(dest, src, n); + else if (d) + G_MoveTiccmd(dest, src, d); + return ret+n; +} + +/** Guesses the full value of a tic from its lowest byte, for a specific node + * + * \param low The lowest byte of the tic value + * \param node The node to deduce the tic for + * \return The full tic value + * + */ +tic_t ExpandTics(INT32 low, INT32 node) +{ + INT32 delta; + + delta = low - (netnodes[node].tic & UINT8_MAX); + + if (delta >= -64 && delta <= 64) + return (netnodes[node].tic & ~UINT8_MAX) + low; + else if (delta > 64) + return (netnodes[node].tic & ~UINT8_MAX) - 256 + low; + else //if (delta < -64) + return (netnodes[node].tic & ~UINT8_MAX) + 256 + low; +} + +void D_Clearticcmd(tic_t tic) +{ + INT32 i; + + D_FreeTextcmd(tic); + + for (i = 0; i < MAXPLAYERS; i++) + netcmds[tic%BACKUPTICS][i].angleturn = 0; + + DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS)); +} + +void D_ResetTiccmds(void) +{ + INT32 i; + + memset(&localcmds, 0, sizeof(ticcmd_t)); + memset(&localcmds2, 0, sizeof(ticcmd_t)); + + // Reset the net command list + for (i = 0; i < TEXTCMD_HASH_SIZE; i++) + while (textcmds[i]) + D_Clearticcmd(textcmds[i]->tic); +} + +void PT_ClientCmd(SINT8 node, INT32 netconsole) +{ + tic_t realend, realstart; + + if (client) + return; + + // 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, node); + realend = ExpandTics(netbuffer->u.clientpak.resendfrom, node); + + if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS + || netbuffer->packettype == PT_NODEKEEPALIVEMIS + || netnodes[node].supposedtic < realend) + { + netnodes[node].supposedtic = realend; + } + // Discard out of order packet + if (netnodes[node].tic > realend) + { + DEBFILE(va("out of order ticcmd discarded nettics = %u\n", netnodes[node].tic)); + return; + } + + // Update the nettics + netnodes[node].tic = realend; + + // Don't do anything for packets of type NODEKEEPALIVE? + if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE + || netbuffer->packettype == PT_NODEKEEPALIVEMIS) + return; + + // 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? + netnodes[node].freezetimeout = I_GetTime() + connectiontimeout; + + // Copy ticcmd + G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); + + // Check ticcmd for "speed hacks" + if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE + || netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole); + //D_Clearticcmd(k); + + SendKick(netconsole, KICK_MSG_CON_FAIL); + return; + } + + // Splitscreen cmd + if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) + && netnodes[node].player2 >= 0) + G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)netnodes[node].player2], + &netbuffer->u.client2pak.cmd2, 1); + + // Check player consistancy during the level + if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL + && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) + && !SV_ResendingSavegameToAnyone() + && !netnodes[node].resendingsavegame && netnodes[node].savegameresendcooldown <= I_GetTime()) + { + if (cv_resynchattempts.value) + { + // Tell the client we are about to resend them the gamestate + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + HSendPacket(node, true, 0, 0); + + netnodes[node].resendingsavegame = true; + + 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 | KICK_MSG_KEEP_BODY); + DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", + netconsole, realstart, consistancy[realstart%BACKUPTICS], + SHORT(netbuffer->u.clientpak.consistancy))); + return; + } + } +} + +void PT_ServerTics(SINT8 node, INT32 netconsole) +{ + UINT8 *pak, *txtpak, numtxtpak; + tic_t realend, realstart; + + if (!netnodes[node].ingame) + { + // Do not remove my own server (we have just get a out of order packet) + if (node != servernode) + { + DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype)); + Net_CloseConnection(node); + } + return; + } + + // 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(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + return; + } + + realstart = netbuffer->u.serverpak.starttic; + realend = realstart + 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) + { + 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 k = *txtpak++; // playernum + const size_t txtsize = txtpak[0]+1; + + if (i >= gametic) // Don't copy old net commands + M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize); + txtpak += txtsize; + } + } + + neededtic = realend; + } + else + { + DEBFILE(va("frame not in bound: %u\n", neededtic)); + /*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);*/ + } +} + +// send the client packet to the server +void CL_SendClientCmd(void) +{ + size_t packetsize = 0; + + netbuffer->packettype = PT_CLIENTCMD; + + if (cl_packetmissed) + netbuffer->packettype++; + netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX); + netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX); + + if (gamestate == GS_WAITINGPLAYERS) + { + // Send PT_NODEKEEPALIVE packet + netbuffer->packettype += 4; + packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16); + HSendPacket(servernode, false, 0, packetsize); + } + else if (gamestate != GS_NULL && (addedtogame || dedicated)) + { + G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1); + netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]); + + // Send a special packet with 2 cmd for splitscreen + if (splitscreen || botingame) + { + netbuffer->packettype += 2; + G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1); + packetsize = sizeof (client2cmd_pak); + } + else + packetsize = sizeof (clientcmd_pak); + + HSendPacket(servernode, false, 0, packetsize); + } + + if (cl_mode == CL_CONNECTED || dedicated) + { + // Send extra data if needed + if (localtextcmd[0]) + { + netbuffer->packettype = PT_TEXTCMD; + M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1); + // All extra data have been sent + if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail... + localtextcmd[0] = 0; + } + + // Send extra data if needed for player 2 (splitscreen) + if (localtextcmd2[0]) + { + netbuffer->packettype = PT_TEXTCMD2; + M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1); + // All extra data have been sent + if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail... + localtextcmd2[0] = 0; + } + } +} + +// send the server packet +// send tic from firstticstosend to maketic-1 +void SV_SendTics(void) +{ + tic_t realfirsttic, lasttictosend, i; + UINT32 n; + INT32 j; + size_t packsize; + UINT8 *bufpos; + UINT8 *ntextcmd; + + // send to all client but not to me + // for each node create a packet with x tics and send it + // x is computed using netnodes[n].supposedtic, max packet size and maketic + for (n = 1; n < MAXNETNODES; n++) + if (netnodes[n].ingame) + { + // assert netnodes[n].supposedtic>=netnodes[n].tic + realfirsttic = netnodes[n].supposedtic; + lasttictosend = min(maketic, netnodes[n].tic + 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, maketic, netnodes[n].supposedtic, netnodes[n].tic)); + realfirsttic = netnodes[n].tic; + if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3) + // all tic are ok + continue; + DEBFILE(va("Sent %d anyway\n", realfirsttic)); + } + if (realfirsttic < firstticstosend) + realfirsttic = firstticstosend; + + // 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; + packsize += TotalTextCmdPerTic(i); + + if (packsize > software_MAXPACKETLENGTH) + { + DEBFILE(va("packet too large (%s) at tic %d (should be from %d to %d)\n", + sizeu1(packsize), i, realfirsttic, lasttictosend)); + lasttictosend = i; + + // too bad: too much player have send extradata and there is too + // much data in one tic. + // To avoid it put the data on the next tic. (see getpacket + // textcmd case) but when numplayer changes the computation can be different + if (lasttictosend == realfirsttic) + { + if (packsize > MAXPACKETLENGTH) + I_Error("Too many players: can't send %s data for %d players to node %d\n" + "Well sorry nobody is perfect....\n", + sizeu1(packsize), doomcom->numslots, n); + else + { + lasttictosend++; // send it anyway! + DEBFILE("sending it anyway\n"); + } + } + break; + } + } + + // Send the tics + netbuffer->packettype = PT_SERVERTICS; + netbuffer->u.serverpak.starttic = realfirsttic; + netbuffer->u.serverpak.numtics = (UINT8)(lasttictosend - realfirsttic); + netbuffer->u.serverpak.numslots = (UINT8)SHORT(doomcom->numslots); + bufpos = (UINT8 *)&netbuffer->u.serverpak.cmds; + + for (i = realfirsttic; i < lasttictosend; i++) + { + bufpos = G_DcpyTiccmd(bufpos, netcmds[i%BACKUPTICS], doomcom->numslots * sizeof (ticcmd_t)); + } + + // add textcmds + for (i = realfirsttic; i < lasttictosend; i++) + { + ntextcmd = bufpos++; + *ntextcmd = 0; + for (j = 0; j < MAXPLAYERS; j++) + { + UINT8 *textcmd = D_GetExistingTextcmd(i, j); + INT32 size = textcmd ? textcmd[0] : 0; + + if ((!j || playeringame[j]) && size) + { + (*ntextcmd)++; + WRITEUINT8(bufpos, j); + M_Memcpy(bufpos, textcmd, size + 1); + bufpos += size + 1; + } + } + } + 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) + netnodes[n].supposedtic = lasttictosend-doomcom->extratics; + else + netnodes[n].supposedtic = lasttictosend; + if (netnodes[n].supposedtic < netnodes[n].tic) netnodes[n].supposedtic = netnodes[n].tic; + } + // node 0 is me! + netnodes[0].supposedtic = maketic; +} + +// +// TryRunTics +// +void Local_Maketic(INT32 realtics) +{ + I_OsPolling(); // I_Getevent + D_ProcessEvents(); // menu responder, cons responder, + // game responder calls HU_Responder, AM_Responder, + // and G_MapEventsToControls + if (!dedicated) rendergametic = gametic; + // translate inputs (keyboard/mouse/gamepad) into game controls + G_BuildTiccmd(&localcmds, realtics, 1); + if (splitscreen || botingame) + G_BuildTiccmd(&localcmds2, realtics, 2); + + localcmds.angleturn |= TICCMD_RECEIVED; + localcmds2.angleturn |= TICCMD_RECEIVED; +} + +// create missed tic +void SV_Maketic(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + // We didn't receive this tic + if ((netcmds[maketic % BACKUPTICS][i].angleturn & TICCMD_RECEIVED) == 0) + { + ticcmd_t * ticcmd = &netcmds[(maketic ) % BACKUPTICS][i]; + ticcmd_t *prevticcmd = &netcmds[(maketic - 1) % BACKUPTICS][i]; + + if (players[i].quittime) + { + // Copy the angle/aiming from the previous tic + // and empty the other inputs + memset(ticcmd, 0, sizeof(netcmds[0][0])); + ticcmd->angleturn = prevticcmd->angleturn | TICCMD_RECEIVED; + ticcmd->aiming = prevticcmd->aiming; + } + else + { + DEBFILE(va("MISS tic%4d for player %d\n", maketic, i)); + // Copy the input from the previous tic + *ticcmd = *prevticcmd; + ticcmd->angleturn &= ~TICCMD_RECEIVED; + } + } + } + + // all tic are now proceed make the next + maketic++; +} diff --git a/src/netcode/tic_command.h b/src/netcode/tic_command.h new file mode 100644 index 000000000..d19f4c1aa --- /dev/null +++ b/src/netcode/tic_command.h @@ -0,0 +1,44 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file tic_command.h +/// \brief Tic command handling + +#ifndef __D_TIC_COMMAND__ +#define __D_TIC_COMMAND__ + +#include "d_clisrv.h" +#include "../d_ticcmd.h" +#include "../doomdef.h" +#include "../doomtype.h" + +extern tic_t firstticstosend; // min of the nettics +extern tic_t tictoclear; // optimize d_clearticcmd + +extern ticcmd_t localcmds; +extern ticcmd_t localcmds2; +extern boolean cl_packetmissed; + +extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; + +tic_t ExpandTics(INT32 low, INT32 node); +void D_Clearticcmd(tic_t tic); +void D_ResetTiccmds(void); + +void PT_ClientCmd(SINT8 node, INT32 netconsole); +void PT_ServerTics(SINT8 node, INT32 netconsole); + +// send the client packet to the server +void CL_SendClientCmd(void); + +void SV_SendTics(void); +void Local_Maketic(INT32 realtics); +void SV_Maketic(void); + +#endif diff --git a/src/p_inter.c b/src/p_inter.c index f3c13e315..f33494d1f 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -30,6 +30,7 @@ #include "m_misc.h" #include "v_video.h" // video flags for CEchos #include "f_finale.h" +#include "netcode/net_command.h" // CTF player names #define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : "" diff --git a/src/p_mobj.c b/src/p_mobj.c index 49c438b3f..e60e81ace 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -36,6 +36,7 @@ #include "p_slopes.h" #include "f_finale.h" #include "m_cond.h" +#include "netcode/net_command.h" static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}}; consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL); diff --git a/src/p_setup.c b/src/p_setup.c index cd9185484..22d48dd0b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -87,6 +87,8 @@ #include "taglist.h" +#include "netcode/net_command.h" + // // Map MD5, calculated on level load. // Sent to clients in PT_SERVERINFO. diff --git a/src/p_tick.c b/src/p_tick.c index fe6a4d33f..8fb99d737 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -26,6 +26,7 @@ #include "r_main.h" #include "r_fps.h" #include "i_video.h" // rendermode +#include "netcode/net_command.h" // Object place #include "m_cheat.h" diff --git a/src/p_user.c b/src/p_user.c index 1e8dee885..a06bf894f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -19,6 +19,7 @@ #include "i_system.h" #include "d_event.h" #include "netcode/d_net.h" +#include "netcode/net_command.h" #include "g_game.h" #include "p_local.h" #include "r_fps.h"