mirror of
https://git.do.srb2.org/KartKrew/Kart-Public.git
synced 2024-12-26 12:21:19 +00:00
-Added a timeout for game state downloading to prevent definitive join freezes in some cases. The timeout has a minimum value of "jointimeout" and gets higher as the game state grows in size
-If the server tries to kick a joiner who is downloading the game state, they will get a timeout instead, because a regular kick would only happen once the game state has been downloaded -Added a timeout for player ticcmd packets, again to prevent freezes to happen in some cases -File/game state downloading is now faster, the speed is controlled by the "downloadspeed" cvar, in packets per tic -The reason is now properly shown when the server refuses connection -Changed the default values of "nettimeout" to 10 seconds (previously 15) and "maxsend" to 4 MB (previously 1) -Added a "noticedownload" cvar that displays a message in the server console when someone is downloading a file
This commit is contained in:
parent
04747ff79e
commit
e9cb6d0331
11 changed files with 446 additions and 153 deletions
201
src/d_clisrv.c
201
src/d_clisrv.c
|
@ -72,14 +72,21 @@
|
||||||
#define MAX_REASONLENGTH 30
|
#define MAX_REASONLENGTH 30
|
||||||
|
|
||||||
boolean server = true; // true or false but !server == client
|
boolean server = true; // true or false but !server == client
|
||||||
|
#define client (!server)
|
||||||
boolean nodownload = false;
|
boolean nodownload = false;
|
||||||
static boolean serverrunning = false;
|
static boolean serverrunning = false;
|
||||||
INT32 serverplayer = 0;
|
INT32 serverplayer = 0;
|
||||||
char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support)
|
char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support)
|
||||||
|
|
||||||
// server specific vars
|
// Server specific vars
|
||||||
UINT8 playernode[MAXPLAYERS];
|
UINT8 playernode[MAXPLAYERS];
|
||||||
|
|
||||||
|
// Minimum timeout for sending the savegame
|
||||||
|
// The actual timeout will be longer depending on the savegame length
|
||||||
|
tic_t jointimeout = (10*TICRATE);
|
||||||
|
static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame?
|
||||||
|
static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout?
|
||||||
|
|
||||||
#ifdef NEWPING
|
#ifdef NEWPING
|
||||||
UINT16 pingmeasurecount = 1;
|
UINT16 pingmeasurecount = 1;
|
||||||
UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone.
|
UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone.
|
||||||
|
@ -108,7 +115,7 @@ static UINT8 resynch_local_inprogress = false; // WE are desynched and getting p
|
||||||
static UINT8 player_joining = false;
|
static UINT8 player_joining = false;
|
||||||
UINT8 hu_resynching = 0;
|
UINT8 hu_resynching = 0;
|
||||||
|
|
||||||
// client specific
|
// Client specific
|
||||||
static ticcmd_t localcmds;
|
static ticcmd_t localcmds;
|
||||||
static ticcmd_t localcmds2;
|
static ticcmd_t localcmds2;
|
||||||
static boolean cl_packetmissed;
|
static boolean cl_packetmissed;
|
||||||
|
@ -404,7 +411,7 @@ static void ExtraDataTicker(void)
|
||||||
// If you are a client, you can safely forget the net commands for this tic
|
// 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 aknowledged,
|
// If you are the server, you need to remember them until every client has been aknowledged,
|
||||||
// because if you need to resend a PT_SERVERTICS packet, you need to put the commands in it
|
// because if you need to resend a PT_SERVERTICS packet, you need to put the commands in it
|
||||||
if (!server)
|
if (client)
|
||||||
D_FreeTextcmd(gametic);
|
D_FreeTextcmd(gametic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1038,6 +1045,9 @@ static void SV_AcknowledgeResynchAck(INT32 node, UINT8 rsg)
|
||||||
resynch_status[node] &= ~(1<<rsg);
|
resynch_status[node] &= ~(1<<rsg);
|
||||||
--resynch_score[node]; // unpenalize
|
--resynch_score[node]; // unpenalize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't let resynch cause a timeout
|
||||||
|
freezetimeout[node] = I_GetTime() + connectiontimeout;
|
||||||
}
|
}
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
// end resynch
|
// end resynch
|
||||||
|
@ -1131,12 +1141,17 @@ static inline void CL_DrawConnectionStatus(void)
|
||||||
{
|
{
|
||||||
#ifdef JOININGAME
|
#ifdef JOININGAME
|
||||||
case CL_DOWNLOADSAVEGAME:
|
case CL_DOWNLOADSAVEGAME:
|
||||||
cltext = M_GetText("Downloading game state...");
|
if (lastfilenum != -1)
|
||||||
Net_GetNetStat();
|
{
|
||||||
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
|
cltext = M_GetText("Downloading game state...");
|
||||||
va(" %4uK",fileneeded[lastfilenum].currentsize>>10));
|
Net_GetNetStat();
|
||||||
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
|
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
|
||||||
va("%3.1fK/s ", ((double)getbps)/1024));
|
va(" %4uK",fileneeded[lastfilenum].currentsize>>10));
|
||||||
|
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
|
||||||
|
va("%3.1fK/s ", ((double)getbps)/1024));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cltext = M_GetText("Waiting to download game state...");
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case CL_ASKJOIN:
|
case CL_ASKJOIN:
|
||||||
|
@ -1151,25 +1166,31 @@ static inline void CL_DrawConnectionStatus(void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
INT32 dldlength;
|
if (lastfilenum != -1)
|
||||||
static char tempname[32];
|
{
|
||||||
|
INT32 dldlength;
|
||||||
|
static char tempname[32];
|
||||||
|
|
||||||
Net_GetNetStat();
|
Net_GetNetStat();
|
||||||
dldlength = (INT32)((fileneeded[lastfilenum].currentsize/(double)fileneeded[lastfilenum].totalsize) * 256);
|
dldlength = (INT32)((fileneeded[lastfilenum].currentsize/(double)fileneeded[lastfilenum].totalsize) * 256);
|
||||||
if (dldlength > 256)
|
if (dldlength > 256)
|
||||||
dldlength = 256;
|
dldlength = 256;
|
||||||
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175);
|
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175);
|
||||||
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 160);
|
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 160);
|
||||||
|
|
||||||
memset(tempname, 0, sizeof(tempname));
|
memset(tempname, 0, sizeof(tempname));
|
||||||
nameonly(strncpy(tempname, fileneeded[lastfilenum].filename, 31));
|
nameonly(strncpy(tempname, fileneeded[lastfilenum].filename, 31));
|
||||||
|
|
||||||
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
|
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
|
||||||
va(M_GetText("Downloading \"%s\""), tempname));
|
va(M_GetText("Downloading \"%s\""), tempname));
|
||||||
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
|
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
|
||||||
va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,fileneeded[lastfilenum].totalsize>>10));
|
va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,fileneeded[lastfilenum].totalsize>>10));
|
||||||
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
|
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
|
||||||
va("%3.1fK/s ", ((double)getbps)/1024));
|
va("%3.1fK/s ", ((double)getbps)/1024));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
|
||||||
|
M_GetText("Waiting to download files..."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1458,6 +1479,10 @@ static void SV_SendSaveGame(INT32 node)
|
||||||
|
|
||||||
SV_SendRam(node, buffertosend, length, SF_RAM, 0);
|
SV_SendRam(node, buffertosend, length, SF_RAM, 0);
|
||||||
save_p = NULL;
|
save_p = NULL;
|
||||||
|
|
||||||
|
// Remember when we started sending the savegame so we can handle timeouts
|
||||||
|
sendingsavegame[node] = true;
|
||||||
|
freezetimeout[node] = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DUMPCONSISTENCY
|
#ifdef DUMPCONSISTENCY
|
||||||
|
@ -1750,7 +1775,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!server)
|
if (client)
|
||||||
{
|
{
|
||||||
D_ParseFileneeded(serverlist[i].info.fileneedednum,
|
D_ParseFileneeded(serverlist[i].info.fileneedednum,
|
||||||
serverlist[i].info.fileneeded);
|
serverlist[i].info.fileneeded);
|
||||||
|
@ -1924,7 +1949,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic
|
||||||
*oldtic = I_GetTime();
|
*oldtic = I_GetTime();
|
||||||
|
|
||||||
#ifdef CLIENT_LOADINGSCREEN
|
#ifdef CLIENT_LOADINGSCREEN
|
||||||
if (!server && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED)
|
if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED)
|
||||||
{
|
{
|
||||||
F_TitleScreenTicker(true);
|
F_TitleScreenTicker(true);
|
||||||
F_TitleScreenDrawer();
|
F_TitleScreenDrawer();
|
||||||
|
@ -1966,7 +1991,7 @@ static void CL_ConnectToServer(boolean viams)
|
||||||
cl_mode = CL_SEARCHING;
|
cl_mode = CL_SEARCHING;
|
||||||
|
|
||||||
#ifdef CLIENT_LOADINGSCREEN
|
#ifdef CLIENT_LOADINGSCREEN
|
||||||
lastfilenum = 0;
|
lastfilenum = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JOININGAME
|
#ifdef JOININGAME
|
||||||
|
@ -2037,7 +2062,7 @@ static void CL_ConnectToServer(boolean viams)
|
||||||
pnumnodes++;
|
pnumnodes++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (!(cl_mode == CL_CONNECTED && (!server || (server && nodewaited <= pnumnodes))));
|
while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes))));
|
||||||
|
|
||||||
DEBFILE(va("Synchronisation Finished\n"));
|
DEBFILE(va("Synchronisation Finished\n"));
|
||||||
|
|
||||||
|
@ -2574,6 +2599,14 @@ static void Command_Kick(void)
|
||||||
WRITESINT8(p, pn);
|
WRITESINT8(p, pn);
|
||||||
if (pn == -1 || pn == 0)
|
if (pn == -1 || pn == 0)
|
||||||
return;
|
return;
|
||||||
|
// Special case if we are trying to kick a player who is downloading the game state:
|
||||||
|
// trigger a timeout instead of kicking them, because a kick would only
|
||||||
|
// take effect after they have finished downloading
|
||||||
|
if (sendingsavegame[playernode[pn]])
|
||||||
|
{
|
||||||
|
Net_ConnectionTimeout(playernode[pn]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (COM_Argc() == 2)
|
if (COM_Argc() == 2)
|
||||||
{
|
{
|
||||||
WRITEUINT8(p, KICK_MSG_GO_AWAY);
|
WRITEUINT8(p, KICK_MSG_GO_AWAY);
|
||||||
|
@ -2786,7 +2819,12 @@ consvar_t cv_blamecfail = {"blamecfail", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL
|
||||||
|
|
||||||
// max file size to send to a player (in kilobytes)
|
// max file size to send to a player (in kilobytes)
|
||||||
static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}};
|
static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}};
|
||||||
consvar_t cv_maxsend = {"maxsend", "1024", CV_SAVE, maxsend_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
consvar_t cv_maxsend = {"maxsend", "4096", CV_SAVE, maxsend_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||||
|
consvar_t cv_noticedownload = {"noticedownload", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||||
|
|
||||||
|
// Speed of file downloading (in packets per tic)
|
||||||
|
static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, NULL}};
|
||||||
|
consvar_t cv_downloadspeed = {"downloadspeed", "16", CV_SAVE, downloadspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||||
|
|
||||||
static void Got_AddPlayer(UINT8 **p, INT32 playernum);
|
static void Got_AddPlayer(UINT8 **p, INT32 playernum);
|
||||||
|
|
||||||
|
@ -2809,6 +2847,9 @@ void D_ClientServerInit(void)
|
||||||
COM_AddCommand("drop", Command_Drop);
|
COM_AddCommand("drop", Command_Drop);
|
||||||
COM_AddCommand("droprate", Command_Droprate);
|
COM_AddCommand("droprate", Command_Droprate);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef DEBUGMODE
|
||||||
|
COM_AddCommand("numnodes", Command_Numnodes);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
RegisterNetXCmd(XD_KICK, Got_KickCmd);
|
RegisterNetXCmd(XD_KICK, Got_KickCmd);
|
||||||
|
@ -2844,6 +2885,7 @@ static void ResetNode(INT32 node)
|
||||||
supposedtics[node] = gametic;
|
supposedtics[node] = gametic;
|
||||||
nodewaiting[node] = 0;
|
nodewaiting[node] = 0;
|
||||||
playerpernode[node] = 0;
|
playerpernode[node] = 0;
|
||||||
|
sendingsavegame[node] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SV_ResetServer(void)
|
void SV_ResetServer(void)
|
||||||
|
@ -3136,7 +3178,7 @@ void CL_RemoveSplitscreenPlayer(void)
|
||||||
// is there a game running
|
// is there a game running
|
||||||
boolean Playing(void)
|
boolean Playing(void)
|
||||||
{
|
{
|
||||||
return (server && serverrunning) || (!server && cl_mode == CL_CONNECTED);
|
return (server && serverrunning) || (client && cl_mode == CL_CONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean SV_SpawnServer(void)
|
boolean SV_SpawnServer(void)
|
||||||
|
@ -3399,12 +3441,19 @@ static void HandlePacketFromAwayNode(SINT8 node)
|
||||||
}
|
}
|
||||||
if (cl_mode == CL_WAITJOINRESPONSE)
|
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");
|
||||||
|
|
||||||
D_QuitNetGame();
|
D_QuitNetGame();
|
||||||
CL_Reset();
|
CL_Reset();
|
||||||
D_StartTitle();
|
D_StartTitle();
|
||||||
|
|
||||||
M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
|
M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
|
||||||
netbuffer->u.serverrefuse.reason), NULL, MM_NOTHING);
|
reason), NULL, MM_NOTHING);
|
||||||
|
|
||||||
|
free(reason);
|
||||||
|
|
||||||
// Will be reset by caller. Signals refusal.
|
// Will be reset by caller. Signals refusal.
|
||||||
cl_mode = CL_ABORTED;
|
cl_mode = CL_ABORTED;
|
||||||
|
@ -3425,7 +3474,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
|
||||||
if (cl_mode != CL_WAITJOINRESPONSE)
|
if (cl_mode != CL_WAITJOINRESPONSE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!server)
|
if (client)
|
||||||
{
|
{
|
||||||
maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
|
maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
|
||||||
gametype = netbuffer->u.servercfg.gametype;
|
gametype = netbuffer->u.servercfg.gametype;
|
||||||
|
@ -3553,7 +3602,7 @@ FILESTAMP
|
||||||
case PT_CLIENT2MIS:
|
case PT_CLIENT2MIS:
|
||||||
case PT_NODEKEEPALIVE:
|
case PT_NODEKEEPALIVE:
|
||||||
case PT_NODEKEEPALIVEMIS:
|
case PT_NODEKEEPALIVEMIS:
|
||||||
if (!server)
|
if (client)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Ignore tics from those not synched
|
// Ignore tics from those not synched
|
||||||
|
@ -3586,6 +3635,13 @@ FILESTAMP
|
||||||
|| netbuffer->packettype == PT_NODEKEEPALIVEMIS)
|
|| netbuffer->packettype == PT_NODEKEEPALIVEMIS)
|
||||||
break;
|
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;
|
||||||
|
|
||||||
// Copy ticcmd
|
// Copy ticcmd
|
||||||
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
|
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
|
||||||
|
|
||||||
|
@ -3652,7 +3708,7 @@ FILESTAMP
|
||||||
case PT_TEXTCMD2: // splitscreen special
|
case PT_TEXTCMD2: // splitscreen special
|
||||||
netconsole = nodetoplayer2[node];
|
netconsole = nodetoplayer2[node];
|
||||||
case PT_TEXTCMD:
|
case PT_TEXTCMD:
|
||||||
if (!server)
|
if (client)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (netconsole < 0 || netconsole >= MAXPLAYERS)
|
if (netconsole < 0 || netconsole >= MAXPLAYERS)
|
||||||
|
@ -3696,7 +3752,7 @@ FILESTAMP
|
||||||
break;
|
break;
|
||||||
case PT_NODETIMEOUT:
|
case PT_NODETIMEOUT:
|
||||||
case PT_CLIENTQUIT:
|
case PT_CLIENTQUIT:
|
||||||
if (!server)
|
if (client)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// nodeingame will be put false in the execution of kick command
|
// nodeingame will be put false in the execution of kick command
|
||||||
|
@ -3728,7 +3784,7 @@ FILESTAMP
|
||||||
// Only accept PT_RESYNCHEND from the server.
|
// Only accept PT_RESYNCHEND from the server.
|
||||||
if (node != servernode)
|
if (node != servernode)
|
||||||
{
|
{
|
||||||
CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_RESYNCHEND", node);
|
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHEND", node);
|
||||||
|
|
||||||
if (server)
|
if (server)
|
||||||
{
|
{
|
||||||
|
@ -3806,13 +3862,20 @@ FILESTAMP
|
||||||
neededtic = realend;
|
neededtic = realend;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
DEBFILE(va("frame not in bound: %u\n", neededtic));
|
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);*/
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PT_RESYNCHING:
|
case PT_RESYNCHING:
|
||||||
// Only accept PT_RESYNCHING from the server.
|
// Only accept PT_RESYNCHING from the server.
|
||||||
if (node != servernode)
|
if (node != servernode)
|
||||||
{
|
{
|
||||||
CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_RESYNCHING", node);
|
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHING", node);
|
||||||
|
|
||||||
if (server)
|
if (server)
|
||||||
{
|
{
|
||||||
|
@ -3832,7 +3895,7 @@ FILESTAMP
|
||||||
// Only accept PT_PING from the server.
|
// Only accept PT_PING from the server.
|
||||||
if (node != servernode)
|
if (node != servernode)
|
||||||
{
|
{
|
||||||
CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_PING", node);
|
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node);
|
||||||
|
|
||||||
if (server)
|
if (server)
|
||||||
{
|
{
|
||||||
|
@ -3846,7 +3909,7 @@ FILESTAMP
|
||||||
}
|
}
|
||||||
|
|
||||||
//Update client ping table from the server.
|
//Update client ping table from the server.
|
||||||
if (!server)
|
if (client)
|
||||||
{
|
{
|
||||||
INT32 i;
|
INT32 i;
|
||||||
for (i = 0; i < MAXNETNODES; i++)
|
for (i = 0; i < MAXNETNODES; i++)
|
||||||
|
@ -3859,7 +3922,7 @@ FILESTAMP
|
||||||
case PT_SERVERCFG:
|
case PT_SERVERCFG:
|
||||||
break;
|
break;
|
||||||
case PT_FILEFRAGMENT:
|
case PT_FILEFRAGMENT:
|
||||||
if (!server)
|
if (client)
|
||||||
Got_Filetxpak();
|
Got_Filetxpak();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -3889,17 +3952,18 @@ FILESTAMP
|
||||||
HandleConnect(node);
|
HandleConnect(node);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (netbuffer->packettype == PT_SERVERSHUTDOWN && node == servernode
|
if (node == servernode && client && cl_mode != CL_SEARCHING)
|
||||||
&& !server && cl_mode != CL_SEARCHING)
|
|
||||||
{
|
{
|
||||||
HandleShutdown(node);
|
if (netbuffer->packettype == PT_SERVERSHUTDOWN)
|
||||||
continue;
|
{
|
||||||
}
|
HandleShutdown(node);
|
||||||
if (netbuffer->packettype == PT_NODETIMEOUT && node == servernode
|
continue;
|
||||||
&& !server && cl_mode != CL_SEARCHING)
|
}
|
||||||
{
|
if (netbuffer->packettype == PT_NODETIMEOUT)
|
||||||
HandleTimeout(node);
|
{
|
||||||
continue;
|
HandleTimeout(node);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NONET
|
#ifndef NONET
|
||||||
|
@ -3916,7 +3980,7 @@ FILESTAMP
|
||||||
// Packet received from someone already playing
|
// Packet received from someone already playing
|
||||||
if (nodeingame[node])
|
if (nodeingame[node])
|
||||||
HandlePacketFromPlayer(node);
|
HandlePacketFromPlayer(node);
|
||||||
// Packet received from someone trying to join
|
// Packet received from someone not playing
|
||||||
else
|
else
|
||||||
HandlePacketFromAwayNode(node);
|
HandlePacketFromAwayNode(node);
|
||||||
}
|
}
|
||||||
|
@ -4047,7 +4111,7 @@ static void CL_SendClientCmd(void)
|
||||||
|
|
||||||
if (gamestate == GS_WAITINGPLAYERS)
|
if (gamestate == GS_WAITINGPLAYERS)
|
||||||
{
|
{
|
||||||
// send NODEKEEPALIVE packet
|
// Send PT_NODEKEEPALIVE packet
|
||||||
netbuffer->packettype += 4;
|
netbuffer->packettype += 4;
|
||||||
packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16);
|
packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16);
|
||||||
HSendPacket(servernode, false, 0, packetsize);
|
HSendPacket(servernode, false, 0, packetsize);
|
||||||
|
@ -4057,7 +4121,7 @@ static void CL_SendClientCmd(void)
|
||||||
G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1);
|
G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1);
|
||||||
netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]);
|
netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]);
|
||||||
|
|
||||||
// send a special packet with 2 cmd for splitscreen
|
// Send a special packet with 2 cmd for splitscreen
|
||||||
if (splitscreen || botingame)
|
if (splitscreen || botingame)
|
||||||
{
|
{
|
||||||
netbuffer->packettype += 2;
|
netbuffer->packettype += 2;
|
||||||
|
@ -4072,23 +4136,23 @@ static void CL_SendClientCmd(void)
|
||||||
|
|
||||||
if (cl_mode == CL_CONNECTED || dedicated)
|
if (cl_mode == CL_CONNECTED || dedicated)
|
||||||
{
|
{
|
||||||
// send extra data if needed
|
// Send extra data if needed
|
||||||
if (localtextcmd[0])
|
if (localtextcmd[0])
|
||||||
{
|
{
|
||||||
netbuffer->packettype = PT_TEXTCMD;
|
netbuffer->packettype = PT_TEXTCMD;
|
||||||
M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1);
|
M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1);
|
||||||
// all extra data have been sended
|
// All extra data have been sent
|
||||||
if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // send can fail...
|
if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail...
|
||||||
localtextcmd[0] = 0;
|
localtextcmd[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send extra data if needed for player 2 (splitscreen)
|
// Send extra data if needed for player 2 (splitscreen)
|
||||||
if (localtextcmd2[0])
|
if (localtextcmd2[0])
|
||||||
{
|
{
|
||||||
netbuffer->packettype = PT_TEXTCMD2;
|
netbuffer->packettype = PT_TEXTCMD2;
|
||||||
M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1);
|
M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1);
|
||||||
// all extra data have been sended
|
// All extra data have been sent
|
||||||
if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // send can fail...
|
if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail...
|
||||||
localtextcmd2[0] = 0;
|
localtextcmd2[0] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4352,7 +4416,7 @@ static inline void PingUpdate(void)
|
||||||
//check for ping limit breakage.
|
//check for ping limit breakage.
|
||||||
if (cv_maxping.value)
|
if (cv_maxping.value)
|
||||||
{
|
{
|
||||||
for (i = 1; i < MAXNETNODES; i++)
|
for (i = 1; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
if (playeringame[i] && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value))
|
if (playeringame[i] && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value))
|
||||||
{
|
{
|
||||||
|
@ -4366,7 +4430,7 @@ static inline void PingUpdate(void)
|
||||||
//in that case, it is probably the server's fault.
|
//in that case, it is probably the server's fault.
|
||||||
if (numlaggers < D_NumPlayers() - 1)
|
if (numlaggers < D_NumPlayers() - 1)
|
||||||
{
|
{
|
||||||
for (i = 1; i < MAXNETNODES; i++)
|
for (i = 1; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
if (playeringame[i] && laggers[i])
|
if (playeringame[i] && laggers[i])
|
||||||
{
|
{
|
||||||
|
@ -4381,7 +4445,7 @@ static inline void PingUpdate(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
//make the ping packet and clear server data for next one
|
//make the ping packet and clear server data for next one
|
||||||
for (i = 0; i < MAXNETNODES; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
{
|
{
|
||||||
netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount;
|
netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount;
|
||||||
//server takes a snapshot of the real ping for display.
|
//server takes a snapshot of the real ping for display.
|
||||||
|
@ -4391,7 +4455,7 @@ static inline void PingUpdate(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
//send out our ping packets
|
//send out our ping packets
|
||||||
for (i = 0; i < MAXNETNODES; i++)
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
if (playeringame[i])
|
if (playeringame[i])
|
||||||
HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS);
|
HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS);
|
||||||
|
|
||||||
|
@ -4440,7 +4504,7 @@ void NetUpdate(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!server)
|
if (client)
|
||||||
maketic = neededtic;
|
maketic = neededtic;
|
||||||
|
|
||||||
Local_Maketic(realtics); // make local tic, and call menu?
|
Local_Maketic(realtics); // make local tic, and call menu?
|
||||||
|
@ -4455,7 +4519,7 @@ FILESTAMP
|
||||||
|
|
||||||
MasterClient_Ticker(); // Acking the Master Server
|
MasterClient_Ticker(); // Acking the Master Server
|
||||||
|
|
||||||
if (!server)
|
if (client)
|
||||||
{
|
{
|
||||||
if (!resynch_local_inprogress)
|
if (!resynch_local_inprogress)
|
||||||
CL_SendClientCmd(); // Send tic cmd
|
CL_SendClientCmd(); // Send tic cmd
|
||||||
|
@ -4505,6 +4569,11 @@ FILESTAMP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Net_AckTicker();
|
Net_AckTicker();
|
||||||
|
// Handle timeouts to prevent definitive freezes from happenning
|
||||||
|
if (server)
|
||||||
|
for (i = 1; i < MAXNETNODES; i++)
|
||||||
|
if (nodeingame[i] && freezetimeout[i] < I_GetTime())
|
||||||
|
Net_ConnectionTimeout(i);
|
||||||
nowtime /= NEWTICRATERATIO;
|
nowtime /= NEWTICRATERATIO;
|
||||||
if (nowtime > resptime)
|
if (nowtime > resptime)
|
||||||
{
|
{
|
||||||
|
|
|
@ -80,6 +80,10 @@ typedef enum
|
||||||
void Command_Drop(void);
|
void Command_Drop(void);
|
||||||
void Command_Droprate(void);
|
void Command_Droprate(void);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef DEBUGMODE
|
||||||
|
void Command_Numnodes(void);
|
||||||
|
#endif
|
||||||
|
boolean NodeClosing(INT32 node);
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
@ -442,6 +446,7 @@ extern consvar_t cv_playbackspeed;
|
||||||
#define KICK_MSG_CUSTOM_BAN 8
|
#define KICK_MSG_CUSTOM_BAN 8
|
||||||
|
|
||||||
extern boolean server;
|
extern boolean server;
|
||||||
|
#define client (!server)
|
||||||
extern boolean dedicated; // For dedicated server
|
extern boolean dedicated; // For dedicated server
|
||||||
extern UINT16 software_MAXPACKETLENGTH;
|
extern UINT16 software_MAXPACKETLENGTH;
|
||||||
extern boolean acceptnewnode;
|
extern boolean acceptnewnode;
|
||||||
|
@ -449,13 +454,14 @@ extern SINT8 servernode;
|
||||||
|
|
||||||
void Command_Ping_f(void);
|
void Command_Ping_f(void);
|
||||||
extern tic_t connectiontimeout;
|
extern tic_t connectiontimeout;
|
||||||
|
extern tic_t jointimeout;
|
||||||
#ifdef NEWPING
|
#ifdef NEWPING
|
||||||
extern UINT16 pingmeasurecount;
|
extern UINT16 pingmeasurecount;
|
||||||
extern UINT32 realpingtable[MAXPLAYERS];
|
extern UINT32 realpingtable[MAXPLAYERS];
|
||||||
extern UINT32 playerpingtable[MAXPLAYERS];
|
extern UINT32 playerpingtable[MAXPLAYERS];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend;
|
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;
|
||||||
|
|
||||||
// Used in d_net, the only dependence
|
// Used in d_net, the only dependence
|
||||||
tic_t ExpandTics(INT32 low);
|
tic_t ExpandTics(INT32 low);
|
||||||
|
|
107
src/d_net.c
107
src/d_net.c
|
@ -42,7 +42,7 @@
|
||||||
// Normally maketic >= gametic > 0
|
// Normally maketic >= gametic > 0
|
||||||
|
|
||||||
#define FORCECLOSE 0x8000
|
#define FORCECLOSE 0x8000
|
||||||
tic_t connectiontimeout = (15*TICRATE);
|
tic_t connectiontimeout = (10*TICRATE);
|
||||||
|
|
||||||
/// \brief network packet
|
/// \brief network packet
|
||||||
doomcom_t *doomcom = NULL;
|
doomcom_t *doomcom = NULL;
|
||||||
|
@ -62,7 +62,7 @@ INT32 net_bandwidth;
|
||||||
/// \brief max length per packet
|
/// \brief max length per packet
|
||||||
INT16 hardware_MAXPACKETLENGTH;
|
INT16 hardware_MAXPACKETLENGTH;
|
||||||
|
|
||||||
void (*I_NetGet)(void) = NULL;
|
boolean (*I_NetGet)(void) = NULL;
|
||||||
void (*I_NetSend)(void) = NULL;
|
void (*I_NetSend)(void) = NULL;
|
||||||
boolean (*I_NetCanSend)(void) = NULL;
|
boolean (*I_NetCanSend)(void) = NULL;
|
||||||
boolean (*I_NetCanGet)(void) = NULL;
|
boolean (*I_NetCanGet)(void) = NULL;
|
||||||
|
@ -142,7 +142,7 @@ typedef struct
|
||||||
UINT8 destinationnode; // The node to send the ack to
|
UINT8 destinationnode; // The node to send the ack to
|
||||||
tic_t senttime; // The time when the ack was sent
|
tic_t senttime; // The time when the ack was sent
|
||||||
UINT16 length; // The packet size
|
UINT16 length; // The packet size
|
||||||
UINT16 resentnum; // The number of
|
UINT16 resentnum; // The number of times the ack has been resent
|
||||||
union {
|
union {
|
||||||
SINT8 raw[MAXPACKETLENGTH];
|
SINT8 raw[MAXPACKETLENGTH];
|
||||||
doomdata_t data;
|
doomdata_t data;
|
||||||
|
@ -152,11 +152,12 @@ typedef struct
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
CLOSE = 1, // flag is set when connection is closing
|
NF_CLOSE = 1, // Flag is set when connection is closing
|
||||||
|
NF_TIMEOUT = 2, // Flag is set when the node got a timeout
|
||||||
} node_flags_t;
|
} node_flags_t;
|
||||||
|
|
||||||
#ifndef NONET
|
#ifndef NONET
|
||||||
// table of packet that was not acknowleged can be resend (the sender window)
|
// Table of packets that were not acknowleged can be resent (the sender window)
|
||||||
static ackpak_t ackpak[MAXACKPACKETS];
|
static ackpak_t ackpak[MAXACKPACKETS];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -274,6 +275,38 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Counts how many acks are free
|
||||||
|
*
|
||||||
|
* \param urgent True if the type of the packet meant to
|
||||||
|
* use an ack is lower than PT_CANFAIL
|
||||||
|
* If for some reason you don't want use it
|
||||||
|
* for any packet type in particular,
|
||||||
|
* just set to false
|
||||||
|
* \return The number of free acks
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
INT32 Net_GetFreeAcks(boolean urgent)
|
||||||
|
{
|
||||||
|
INT32 i, numfreeslot = 0;
|
||||||
|
INT32 n = 0; // Number of free acks found
|
||||||
|
|
||||||
|
for (i = 0; i < MAXACKPACKETS; i++)
|
||||||
|
if (!ackpak[i].acknum)
|
||||||
|
{
|
||||||
|
// For low priority packets, make sure to let freeslots so urgent packets can be sent
|
||||||
|
if (!urgent)
|
||||||
|
{
|
||||||
|
numfreeslot++;
|
||||||
|
if (numfreeslot <= URGENTFREESLOTNUM)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
// Get a ack to send in the queue of this node
|
// Get a ack to send in the queue of this node
|
||||||
static UINT8 GetAcktosend(INT32 node)
|
static UINT8 GetAcktosend(INT32 node)
|
||||||
{
|
{
|
||||||
|
@ -298,7 +331,7 @@ static void RemoveAck(INT32 i)
|
||||||
DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
|
DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
|
||||||
#endif
|
#endif
|
||||||
ackpak[i].acknum = 0;
|
ackpak[i].acknum = 0;
|
||||||
if (nodes[node].flags & CLOSE)
|
if (nodes[node].flags & NF_CLOSE)
|
||||||
Net_CloseConnection(node);
|
Net_CloseConnection(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,8 +485,13 @@ static void GotAcks(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void Net_ConnectionTimeout(INT32 node)
|
void Net_ConnectionTimeout(INT32 node)
|
||||||
{
|
{
|
||||||
|
// Don't timeout several times
|
||||||
|
if (nodes[node].flags & NF_TIMEOUT)
|
||||||
|
return;
|
||||||
|
nodes[node].flags |= NF_TIMEOUT;
|
||||||
|
|
||||||
// Send a very special packet to self (hack the reboundstore queue)
|
// Send a very special packet to self (hack the reboundstore queue)
|
||||||
// Main code will handle it
|
// Main code will handle it
|
||||||
reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
|
reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
|
||||||
|
@ -484,7 +522,7 @@ void Net_AckTicker(void)
|
||||||
if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
|
if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (ackpak[i].resentnum > 10 && (node->flags & CLOSE))
|
if (ackpak[i].resentnum > 10 && (node->flags & NF_CLOSE))
|
||||||
{
|
{
|
||||||
DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n",
|
DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n",
|
||||||
i, nodei));
|
i, nodei));
|
||||||
|
@ -520,7 +558,7 @@ void Net_AckTicker(void)
|
||||||
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
|
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
|
||||||
Net_SendAcks(i);
|
Net_SendAcks(i);
|
||||||
|
|
||||||
if (!(nodes[i].flags & CLOSE)
|
if (!(nodes[i].flags & NF_CLOSE)
|
||||||
&& nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime())
|
&& nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime())
|
||||||
{
|
{
|
||||||
Net_ConnectionTimeout(i);
|
Net_ConnectionTimeout(i);
|
||||||
|
@ -678,7 +716,7 @@ void Net_CloseConnection(INT32 node)
|
||||||
if (!node)
|
if (!node)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nodes[node].flags |= CLOSE;
|
nodes[node].flags |= NF_CLOSE;
|
||||||
|
|
||||||
// try to Send ack back (two army problem)
|
// try to Send ack back (two army problem)
|
||||||
if (GetAcktosend(node))
|
if (GetAcktosend(node))
|
||||||
|
@ -813,18 +851,20 @@ static void DebugPrintpacket(const char *header)
|
||||||
case PT_SERVERTICS:
|
case PT_SERVERTICS:
|
||||||
{
|
{
|
||||||
servertics_pak *serverpak = &netbuffer->u.serverpak;
|
servertics_pak *serverpak = &netbuffer->u.serverpak;
|
||||||
ticcmd_t *cmd = &serverpak->cmds[serverpak->numslots * serverpak->numtics];
|
UINT8 *cmd = (UINT8 *)(&serverpak->cmds[serverpak->numslots * serverpak->numtics]);
|
||||||
size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)cmd;
|
size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - cmd;
|
||||||
|
|
||||||
fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ",
|
fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ",
|
||||||
(UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
|
(UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
|
||||||
fprintfstring((char *)cmd, 3);
|
/// \todo Display more readable information about net commands
|
||||||
|
fprintfstringnewline((char *)cmd, ntxtcmd);
|
||||||
|
/*fprintfstring((char *)cmd, 3);
|
||||||
if (ntxtcmd > 4)
|
if (ntxtcmd > 4)
|
||||||
{
|
{
|
||||||
fprintf(debugfile, "[%s]", netxcmdnames[*(((UINT8 *)cmd) + 3) - 1]);
|
fprintf(debugfile, "[%s]", netxcmdnames[*((cmd) + 3) - 1]);
|
||||||
fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
|
fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
|
||||||
}
|
}
|
||||||
fprintf(debugfile, "\n");
|
fprintf(debugfile, "\n");*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PT_CLIENTCMD:
|
case PT_CLIENTCMD:
|
||||||
|
@ -891,7 +931,7 @@ void Command_Drop(void)
|
||||||
if (COM_Argc() < 2)
|
if (COM_Argc() < 2)
|
||||||
{
|
{
|
||||||
CONS_Printf("drop <packettype> [quantity]: drop packets\n"
|
CONS_Printf("drop <packettype> [quantity]: drop packets\n"
|
||||||
"drop reset: cancel all packet drops");
|
"drop reset: cancel all packet drops\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -958,6 +998,11 @@ static boolean ShouldDropPacket(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
boolean NodeClosing(INT32 node)
|
||||||
|
{
|
||||||
|
return ((nodes[node].flags) & NF_CLOSE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// HSendPacket
|
// HSendPacket
|
||||||
//
|
//
|
||||||
|
@ -1067,6 +1112,8 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
||||||
//
|
//
|
||||||
boolean HGetPacket(void)
|
boolean HGetPacket(void)
|
||||||
{
|
{
|
||||||
|
//boolean nodejustjoined;
|
||||||
|
|
||||||
// Get a packet from self
|
// Get a packet from self
|
||||||
if (rebound_tail != rebound_head)
|
if (rebound_tail != rebound_head)
|
||||||
{
|
{
|
||||||
|
@ -1092,9 +1139,10 @@ boolean HGetPacket(void)
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
|
//nodejustjoined = I_NetGet();
|
||||||
I_NetGet();
|
I_NetGet();
|
||||||
|
|
||||||
if (doomcom->remotenode == -1)
|
if (doomcom->remotenode == -1) // No packet received
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
getbytes += packetheaderlength + doomcom->datalength; // For stat
|
getbytes += packetheaderlength + doomcom->datalength; // For stat
|
||||||
|
@ -1110,6 +1158,7 @@ boolean HGetPacket(void)
|
||||||
if (netbuffer->checksum != NetbufferChecksum())
|
if (netbuffer->checksum != NetbufferChecksum())
|
||||||
{
|
{
|
||||||
DEBFILE("Bad packet checksum\n");
|
DEBFILE("Bad packet checksum\n");
|
||||||
|
//Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode);
|
||||||
Net_CloseConnection(doomcom->remotenode);
|
Net_CloseConnection(doomcom->remotenode);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1119,11 +1168,26 @@ boolean HGetPacket(void)
|
||||||
DebugPrintpacket("GET");
|
DebugPrintpacket("GET");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// proceed the ack and ackreturn field
|
/*// If a new node sends an unexpected packet, just ignore it
|
||||||
|
if (nodejustjoined && server
|
||||||
|
&& !(netbuffer->packettype == PT_ASKINFO
|
||||||
|
|| netbuffer->packettype == PT_SERVERINFO
|
||||||
|
|| netbuffer->packettype == PT_PLAYERINFO
|
||||||
|
|| netbuffer->packettype == PT_REQUESTFILE
|
||||||
|
|| netbuffer->packettype == PT_ASKINFOVIAMS
|
||||||
|
|| netbuffer->packettype == PT_CLIENTJOIN))
|
||||||
|
{
|
||||||
|
DEBFILE(va("New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]));
|
||||||
|
//CONS_Alert(CONS_NOTICE, "New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]);
|
||||||
|
Net_CloseConnection(doomcom->remotenode | FORCECLOSE);
|
||||||
|
continue;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// Proceed the ack and ackreturn field
|
||||||
if (!Processackpak())
|
if (!Processackpak())
|
||||||
continue; // discarded (duplicated)
|
continue; // discarded (duplicated)
|
||||||
|
|
||||||
// a packet with just ackreturn
|
// A packet with just ackreturn
|
||||||
if (netbuffer->packettype == PT_NOTHING)
|
if (netbuffer->packettype == PT_NOTHING)
|
||||||
{
|
{
|
||||||
GotAcks();
|
GotAcks();
|
||||||
|
@ -1136,9 +1200,10 @@ boolean HGetPacket(void)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Internal_Get(void)
|
static boolean Internal_Get(void)
|
||||||
{
|
{
|
||||||
doomcom->remotenode = -1;
|
doomcom->remotenode = -1;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCNORETURN static ATTRNORETURN void Internal_Send(void)
|
FUNCNORETURN static ATTRNORETURN void Internal_Send(void)
|
||||||
|
@ -1223,7 +1288,7 @@ boolean D_CheckNetGame(void)
|
||||||
|
|
||||||
if (netgame)
|
if (netgame)
|
||||||
ret = true;
|
ret = true;
|
||||||
if (!server && netgame)
|
if (client && netgame)
|
||||||
netgame = false;
|
netgame = false;
|
||||||
server = true; // WTF? server always true???
|
server = true; // WTF? server always true???
|
||||||
// no! The deault mode is server. Client is set elsewhere
|
// no! The deault mode is server. Client is set elsewhere
|
||||||
|
|
|
@ -39,6 +39,7 @@ extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if a
|
||||||
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
|
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
|
||||||
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
|
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
|
||||||
|
|
||||||
|
INT32 Net_GetFreeAcks(boolean urgent);
|
||||||
void Net_AckTicker(void);
|
void Net_AckTicker(void);
|
||||||
|
|
||||||
// If reliable return true if packet sent, 0 else
|
// If reliable return true if packet sent, 0 else
|
||||||
|
@ -53,6 +54,7 @@ boolean D_CheckNetGame(void);
|
||||||
void D_CloseConnection(void);
|
void D_CloseConnection(void);
|
||||||
void Net_UnAcknowledgePacket(INT32 node);
|
void Net_UnAcknowledgePacket(INT32 node);
|
||||||
void Net_CloseConnection(INT32 node);
|
void Net_CloseConnection(INT32 node);
|
||||||
|
void Net_ConnectionTimeout(INT32 node);
|
||||||
void Net_AbortPacketType(UINT8 packettype);
|
void Net_AbortPacketType(UINT8 packettype);
|
||||||
void Net_SendAcks(INT32 node);
|
void Net_SendAcks(INT32 node);
|
||||||
void Net_WaitAllAckReceived(UINT32 timeout);
|
void Net_WaitAllAckReceived(UINT32 timeout);
|
||||||
|
|
|
@ -82,6 +82,7 @@ static void AutoBalance_OnChange(void);
|
||||||
static void TeamScramble_OnChange(void);
|
static void TeamScramble_OnChange(void);
|
||||||
|
|
||||||
static void NetTimeout_OnChange(void);
|
static void NetTimeout_OnChange(void);
|
||||||
|
static void JoinTimeout_OnChange(void);
|
||||||
|
|
||||||
static void Ringslinger_OnChange(void);
|
static void Ringslinger_OnChange(void);
|
||||||
static void Gravity_OnChange(void);
|
static void Gravity_OnChange(void);
|
||||||
|
@ -340,7 +341,9 @@ consvar_t cv_killingdead = {"killingdead", "Off", CV_NETVAR, CV_OnOff, NULL, 0,
|
||||||
|
|
||||||
consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics
|
consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics
|
||||||
static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
|
static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
|
||||||
consvar_t cv_nettimeout = {"nettimeout", "525", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
consvar_t cv_nettimeout = {"nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
||||||
|
static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
|
||||||
|
consvar_t cv_jointimeout = {"jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
||||||
#ifdef NEWPING
|
#ifdef NEWPING
|
||||||
consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
|
consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||||
#endif
|
#endif
|
||||||
|
@ -546,9 +549,12 @@ void D_RegisterServerCommands(void)
|
||||||
// d_clisrv
|
// d_clisrv
|
||||||
CV_RegisterVar(&cv_maxplayers);
|
CV_RegisterVar(&cv_maxplayers);
|
||||||
CV_RegisterVar(&cv_maxsend);
|
CV_RegisterVar(&cv_maxsend);
|
||||||
|
CV_RegisterVar(&cv_noticedownload);
|
||||||
|
CV_RegisterVar(&cv_downloadspeed);
|
||||||
|
|
||||||
COM_AddCommand("ping", Command_Ping_f);
|
COM_AddCommand("ping", Command_Ping_f);
|
||||||
CV_RegisterVar(&cv_nettimeout);
|
CV_RegisterVar(&cv_nettimeout);
|
||||||
|
CV_RegisterVar(&cv_jointimeout);
|
||||||
|
|
||||||
CV_RegisterVar(&cv_skipmapcheck);
|
CV_RegisterVar(&cv_skipmapcheck);
|
||||||
CV_RegisterVar(&cv_sleep);
|
CV_RegisterVar(&cv_sleep);
|
||||||
|
@ -1005,7 +1011,7 @@ UINT8 CanChangeSkin(INT32 playernum)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Force skin in effect.
|
// Force skin in effect.
|
||||||
if (!server && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
|
if (client && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Can change skin in intermission and whatnot.
|
// Can change skin in intermission and whatnot.
|
||||||
|
@ -1616,7 +1622,7 @@ static void Command_Map_f(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!server && !(adminplayer == consoleplayer))
|
if (client && !(adminplayer == consoleplayer))
|
||||||
{
|
{
|
||||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||||
return;
|
return;
|
||||||
|
@ -1943,7 +1949,7 @@ static void Got_Suicide(UINT8 **cp, INT32 playernum)
|
||||||
// You can't suicide someone else. Nice try, there.
|
// You can't suicide someone else. Nice try, there.
|
||||||
if (suicideplayer != playernum || (!G_PlatformGametype()))
|
if (suicideplayer != playernum || (!G_PlatformGametype()))
|
||||||
{
|
{
|
||||||
CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command recieved from %s\n"), player_names[playernum]);
|
CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command received from %s\n"), player_names[playernum]);
|
||||||
if (server)
|
if (server)
|
||||||
{
|
{
|
||||||
XBOXSTATIC UINT8 buf[2];
|
XBOXSTATIC UINT8 buf[2];
|
||||||
|
@ -2658,7 +2664,7 @@ static void Command_Changepassword_f(void)
|
||||||
// If we have no MD5 support then completely disable XD_LOGIN responses for security.
|
// If we have no MD5 support then completely disable XD_LOGIN responses for security.
|
||||||
CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
|
CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
|
||||||
#else
|
#else
|
||||||
if (!server) // cannot change remotely
|
if (client) // cannot change remotely
|
||||||
{
|
{
|
||||||
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
||||||
return;
|
return;
|
||||||
|
@ -2717,7 +2723,7 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
|
||||||
|
|
||||||
READMEM(*cp, sentmd5, 16);
|
READMEM(*cp, sentmd5, 16);
|
||||||
|
|
||||||
if (!server)
|
if (client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Do the final pass to compare with the sent md5
|
// Do the final pass to compare with the sent md5
|
||||||
|
@ -2739,7 +2745,7 @@ static void Command_Verify_f(void)
|
||||||
char *temp;
|
char *temp;
|
||||||
INT32 playernum;
|
INT32 playernum;
|
||||||
|
|
||||||
if (!server)
|
if (client)
|
||||||
{
|
{
|
||||||
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
||||||
return;
|
return;
|
||||||
|
@ -2823,7 +2829,7 @@ static void Command_MotD_f(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((netgame || multiplayer) && !server)
|
if ((netgame || multiplayer) && client)
|
||||||
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
|
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3080,7 +3086,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
|
||||||
READMEM(*cp, md5sum, 16);
|
READMEM(*cp, md5sum, 16);
|
||||||
|
|
||||||
// Only the server processes this message.
|
// Only the server processes this message.
|
||||||
if (!server)
|
if (client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Disallow non-printing characters and semicolons.
|
// Disallow non-printing characters and semicolons.
|
||||||
|
@ -3347,6 +3353,11 @@ static void NetTimeout_OnChange(void)
|
||||||
connectiontimeout = (tic_t)cv_nettimeout.value;
|
connectiontimeout = (tic_t)cv_nettimeout.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void JoinTimeout_OnChange(void)
|
||||||
|
{
|
||||||
|
jointimeout = (tic_t)cv_jointimeout.value;
|
||||||
|
}
|
||||||
|
|
||||||
UINT32 timelimitintics = 0;
|
UINT32 timelimitintics = 0;
|
||||||
|
|
||||||
/** Deals with a timelimit change by printing the change to the console.
|
/** Deals with a timelimit change by printing the change to the console.
|
||||||
|
|
132
src/d_netfil.c
132
src/d_netfil.c
|
@ -97,7 +97,7 @@ char downloaddir[256] = "DOWNLOAD";
|
||||||
|
|
||||||
#ifdef CLIENT_LOADINGSCREEN
|
#ifdef CLIENT_LOADINGSCREEN
|
||||||
// for cl loading screen
|
// for cl loading screen
|
||||||
INT32 lastfilenum = 0;
|
INT32 lastfilenum = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Fills a serverinfo packet with information about wad files loaded.
|
/** Fills a serverinfo packet with information about wad files loaded.
|
||||||
|
@ -487,6 +487,9 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
|
||||||
INT32 i;
|
INT32 i;
|
||||||
char wadfilename[MAX_WADPATH];
|
char wadfilename[MAX_WADPATH];
|
||||||
|
|
||||||
|
if (cv_noticedownload.value)
|
||||||
|
CONS_Printf("Sending file \"%s\" to node %d\n", filename, node);
|
||||||
|
|
||||||
// Find the last file in the list and set a pointer to its "next" field
|
// Find the last file in the list and set a pointer to its "next" field
|
||||||
q = &transfer[node].txlist;
|
q = &transfer[node].txlist;
|
||||||
while (*q)
|
while (*q)
|
||||||
|
@ -609,6 +612,8 @@ static void SV_EndFileSend(INT32 node)
|
||||||
switch (p->ram)
|
switch (p->ram)
|
||||||
{
|
{
|
||||||
case SF_FILE: // It's a file, close it and free its filename
|
case SF_FILE: // It's a file, close it and free its filename
|
||||||
|
if (cv_noticedownload.value)
|
||||||
|
CONS_Printf("Ending file transfer for node %d\n", node);
|
||||||
if (transfer[node].currentfile)
|
if (transfer[node].currentfile)
|
||||||
fclose(transfer[node].currentfile);
|
fclose(transfer[node].currentfile);
|
||||||
free(p->id.filename);
|
free(p->id.filename);
|
||||||
|
@ -636,6 +641,9 @@ static void SV_EndFileSend(INT32 node)
|
||||||
|
|
||||||
/** Handles file transmission
|
/** Handles file transmission
|
||||||
*
|
*
|
||||||
|
* \todo Use an acknowledging method more adapted to file transmission
|
||||||
|
* The current download speed suffers from lack of ack packets,
|
||||||
|
* especially when the one downloading has high latency
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void SV_FileSendTicker(void)
|
void SV_FileSendTicker(void)
|
||||||
|
@ -644,17 +652,34 @@ void SV_FileSendTicker(void)
|
||||||
filetx_pak *p;
|
filetx_pak *p;
|
||||||
size_t size;
|
size_t size;
|
||||||
filetx_t *f;
|
filetx_t *f;
|
||||||
INT32 packetsent = PACKETPERTIC, ram, i;
|
INT32 packetsent, ram, i, j;
|
||||||
|
INT32 maxpacketsent;
|
||||||
|
|
||||||
if (!filestosend)
|
if (!filestosend) // No file to send
|
||||||
return;
|
return;
|
||||||
if (!packetsent)
|
|
||||||
packetsent++;
|
if (cv_downloadspeed.value) // New (and experimental) behavior
|
||||||
|
{
|
||||||
|
packetsent = cv_downloadspeed.value;
|
||||||
|
// Don't send more packets than we have free acks
|
||||||
|
maxpacketsent = Net_GetFreeAcks(false) - 5; // Let 5 extra acks just in case
|
||||||
|
if (packetsent > maxpacketsent && maxpacketsent > 0) // Send at least one packet
|
||||||
|
packetsent = maxpacketsent;
|
||||||
|
}
|
||||||
|
else // Old behavior
|
||||||
|
{
|
||||||
|
packetsent = PACKETPERTIC;
|
||||||
|
if (!packetsent)
|
||||||
|
packetsent = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
netbuffer->packettype = PT_FILEFRAGMENT;
|
||||||
|
|
||||||
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
|
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
|
||||||
while (packetsent-- && filestosend != 0)
|
while (packetsent-- && filestosend != 0)
|
||||||
{
|
{
|
||||||
for (i = currentnode, ram = 0; ram < MAXNETNODES;
|
for (i = currentnode, j = 0; j < MAXNETNODES;
|
||||||
i = (i+1) % MAXNETNODES, ram++)
|
i = (i+1) % MAXNETNODES, j++)
|
||||||
{
|
{
|
||||||
if (transfer[i].txlist)
|
if (transfer[i].txlist)
|
||||||
goto found;
|
goto found;
|
||||||
|
@ -713,7 +738,6 @@ void SV_FileSendTicker(void)
|
||||||
p->position |= LONG(0x80000000);
|
p->position |= LONG(0x80000000);
|
||||||
p->fileid = f->fileid;
|
p->fileid = f->fileid;
|
||||||
p->size = SHORT((UINT16)size);
|
p->size = SHORT((UINT16)size);
|
||||||
netbuffer->packettype = PT_FILEFRAGMENT;
|
|
||||||
|
|
||||||
// Send the packet
|
// Send the packet
|
||||||
if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
|
if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
|
||||||
|
@ -735,27 +759,40 @@ void SV_FileSendTicker(void)
|
||||||
void Got_Filetxpak(void)
|
void Got_Filetxpak(void)
|
||||||
{
|
{
|
||||||
INT32 filenum = netbuffer->u.filetxpak.fileid;
|
INT32 filenum = netbuffer->u.filetxpak.fileid;
|
||||||
|
fileneeded_t *file = &fileneeded[filenum];
|
||||||
|
char *filename = file->filename;
|
||||||
static INT32 filetime = 0;
|
static INT32 filetime = 0;
|
||||||
|
|
||||||
|
if (!(strcmp(filename, "srb2.srb")
|
||||||
|
&& strcmp(filename, "srb2.wad")
|
||||||
|
&& strcmp(filename, "zones.dta")
|
||||||
|
&& strcmp(filename, "player.dta")
|
||||||
|
&& strcmp(filename, "rings.dta")
|
||||||
|
&& strcmp(filename, "patch.dta")
|
||||||
|
&& strcmp(filename, "music.dta")
|
||||||
|
))
|
||||||
|
I_Error("Tried to download \"%s\"", filename);
|
||||||
|
|
||||||
if (filenum >= fileneedednum)
|
if (filenum >= fileneedednum)
|
||||||
{
|
{
|
||||||
DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));
|
DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));
|
||||||
|
//I_Error("Received an unneeded file fragment (file id received: %d, file id needed: %d)\n", filenum, fileneedednum);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileneeded[filenum].status == FS_REQUESTED)
|
if (file->status == FS_REQUESTED)
|
||||||
{
|
{
|
||||||
if (fileneeded[filenum].file)
|
if (file->file)
|
||||||
I_Error("Got_Filetxpak: already open file\n");
|
I_Error("Got_Filetxpak: already open file\n");
|
||||||
fileneeded[filenum].file = fopen(fileneeded[filenum].filename, "wb");
|
file->file = fopen(filename, "wb");
|
||||||
if (!fileneeded[filenum].file)
|
if (!file->file)
|
||||||
I_Error("Can't create file %s: %s", fileneeded[filenum].filename, strerror(errno));
|
I_Error("Can't create file %s: %s", filename, strerror(errno));
|
||||||
CONS_Printf("\r%s...\n",fileneeded[filenum].filename);
|
CONS_Printf("\r%s...\n",filename);
|
||||||
fileneeded[filenum].currentsize = 0;
|
file->currentsize = 0;
|
||||||
fileneeded[filenum].status = FS_DOWNLOADING;
|
file->status = FS_DOWNLOADING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileneeded[filenum].status == FS_DOWNLOADING)
|
if (file->status == FS_DOWNLOADING)
|
||||||
{
|
{
|
||||||
UINT32 pos = LONG(netbuffer->u.filetxpak.position);
|
UINT32 pos = LONG(netbuffer->u.filetxpak.position);
|
||||||
UINT16 size = SHORT(netbuffer->u.filetxpak.size);
|
UINT16 size = SHORT(netbuffer->u.filetxpak.size);
|
||||||
|
@ -764,27 +801,47 @@ void Got_Filetxpak(void)
|
||||||
if (pos & 0x80000000)
|
if (pos & 0x80000000)
|
||||||
{
|
{
|
||||||
pos &= ~0x80000000;
|
pos &= ~0x80000000;
|
||||||
fileneeded[filenum].totalsize = pos + size;
|
file->totalsize = pos + size;
|
||||||
}
|
}
|
||||||
// We can receive packet in the wrong order, anyway all os support gaped file
|
// We can receive packet in the wrong order, anyway all os support gaped file
|
||||||
fseek(fileneeded[filenum].file, pos, SEEK_SET);
|
fseek(file->file, pos, SEEK_SET);
|
||||||
if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].file) != 1)
|
if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1)
|
||||||
I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].file)));
|
I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file)));
|
||||||
fileneeded[filenum].currentsize += size;
|
file->currentsize += size;
|
||||||
|
|
||||||
// Finished?
|
// Finished?
|
||||||
if (fileneeded[filenum].currentsize == fileneeded[filenum].totalsize)
|
if (file->currentsize == file->totalsize)
|
||||||
{
|
{
|
||||||
fclose(fileneeded[filenum].file);
|
fclose(file->file);
|
||||||
fileneeded[filenum].file = NULL;
|
file->file = NULL;
|
||||||
fileneeded[filenum].status = FS_FOUND;
|
file->status = FS_FOUND;
|
||||||
CONS_Printf(M_GetText("Downloading %s...(done)\n"),
|
CONS_Printf(M_GetText("Downloading %s...(done)\n"),
|
||||||
fileneeded[filenum].filename);
|
filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
I_Error("Received a file not requested\n");
|
{
|
||||||
|
const char *s;
|
||||||
|
switch(file->status)
|
||||||
|
{
|
||||||
|
case FS_NOTFOUND:
|
||||||
|
s = "FS_NOTFOUND";
|
||||||
|
break;
|
||||||
|
case FS_FOUND:
|
||||||
|
s = "FS_FOUND";
|
||||||
|
break;
|
||||||
|
case FS_OPEN:
|
||||||
|
s = "FS_OPEN";
|
||||||
|
break;
|
||||||
|
case FS_MD5SUMBAD:
|
||||||
|
s = "FS_MD5SUMBAD";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = "unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s);
|
||||||
|
}
|
||||||
// Send ack back quickly
|
// Send ack back quickly
|
||||||
if (++filetime == 3)
|
if (++filetime == 3)
|
||||||
{
|
{
|
||||||
|
@ -797,12 +854,23 @@ void Got_Filetxpak(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Cancels all file requests for a node
|
/** \brief Checks if a node is downloading a file
|
||||||
*
|
*
|
||||||
* \param node The destination
|
* \param node The node to check for
|
||||||
* \sa SV_EndFileSend
|
* \return True if the node is downloading a file
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
boolean SV_SendingFile(INT32 node)
|
||||||
|
{
|
||||||
|
return transfer[node].txlist != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cancels all file requests for a node
|
||||||
|
*
|
||||||
|
* \param node The destination
|
||||||
|
* \sa SV_EndFileSend
|
||||||
|
*
|
||||||
|
*/
|
||||||
void SV_AbortSendFiles(INT32 node)
|
void SV_AbortSendFiles(INT32 node)
|
||||||
{
|
{
|
||||||
while (transfer[node].txlist)
|
while (transfer[node].txlist)
|
||||||
|
|
|
@ -65,6 +65,7 @@ void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
|
||||||
|
|
||||||
void SV_FileSendTicker(void);
|
void SV_FileSendTicker(void);
|
||||||
void Got_Filetxpak(void);
|
void Got_Filetxpak(void);
|
||||||
|
boolean SV_SendingFile(INT32 node);
|
||||||
|
|
||||||
boolean CL_CheckDownloadable(void);
|
boolean CL_CheckDownloadable(void);
|
||||||
boolean CL_SendRequestFile(void);
|
boolean CL_SendRequestFile(void);
|
||||||
|
|
|
@ -470,7 +470,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
||||||
boolean action = false;
|
boolean action = false;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
CONS_Debug(DBG_NETPLAY,"Recieved SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
|
CONS_Debug(DBG_NETPLAY,"Received SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
|
||||||
|
|
||||||
target = READSINT8(*p);
|
target = READSINT8(*p);
|
||||||
flags = READUINT8(*p);
|
flags = READUINT8(*p);
|
||||||
|
@ -1101,7 +1101,19 @@ void HU_Drawer(void)
|
||||||
|
|
||||||
// draw desynch text
|
// draw desynch text
|
||||||
if (hu_resynching)
|
if (hu_resynching)
|
||||||
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP, "Resynching...");
|
{
|
||||||
|
static UINT32 resynch_ticker = 0;
|
||||||
|
char resynch_text[14];
|
||||||
|
INT32 i;
|
||||||
|
|
||||||
|
// Animate the dots
|
||||||
|
resynch_ticker++;
|
||||||
|
strcpy(resynch_text, "Resynching");
|
||||||
|
for (i = 0; i < (resynch_ticker / 16) % 4; i++)
|
||||||
|
strcat(resynch_text, ".");
|
||||||
|
|
||||||
|
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
|
@ -85,7 +85,7 @@ extern doomcom_t *doomcom;
|
||||||
|
|
||||||
/** \brief return packet in doomcom struct
|
/** \brief return packet in doomcom struct
|
||||||
*/
|
*/
|
||||||
extern void (*I_NetGet)(void);
|
extern boolean (*I_NetGet)(void);
|
||||||
|
|
||||||
/** \brief ask to driver if there is data waiting
|
/** \brief ask to driver if there is data waiting
|
||||||
*/
|
*/
|
||||||
|
|
97
src/i_tcp.c
97
src/i_tcp.c
|
@ -179,6 +179,7 @@ static UINT8 UPNP_support = TRUE;
|
||||||
#include "i_system.h"
|
#include "i_system.h"
|
||||||
#include "i_net.h"
|
#include "i_net.h"
|
||||||
#include "d_net.h"
|
#include "d_net.h"
|
||||||
|
#include "d_netfil.h"
|
||||||
#include "i_tcp.h"
|
#include "i_tcp.h"
|
||||||
#include "m_argv.h"
|
#include "m_argv.h"
|
||||||
|
|
||||||
|
@ -482,21 +483,12 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SINT8 getfreenode(void)
|
|
||||||
{
|
|
||||||
SINT8 j;
|
|
||||||
|
|
||||||
for (j = 0; j < MAXNETNODES; j++)
|
|
||||||
if (!nodeconnected[j])
|
|
||||||
{
|
|
||||||
nodeconnected[j] = true;
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a hack. For some reason, nodes aren't being freed properly.
|
// 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.
|
// 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.
|
||||||
|
* How? Because it removes nodes that are connected but not in game,
|
||||||
|
* which is exactly what clients downloading a file are.
|
||||||
|
*/
|
||||||
static void cleanupnodes(void)
|
static void cleanupnodes(void)
|
||||||
{
|
{
|
||||||
SINT8 j;
|
SINT8 j;
|
||||||
|
@ -506,13 +498,81 @@ static void cleanupnodes(void)
|
||||||
|
|
||||||
// Why can't I start at zero?
|
// Why can't I start at zero?
|
||||||
for (j = 1; j < MAXNETNODES; j++)
|
for (j = 1; j < MAXNETNODES; j++)
|
||||||
|
//if (!(nodeingame[j] || SV_SendingFile(j)))
|
||||||
if (!nodeingame[j])
|
if (!nodeingame[j])
|
||||||
nodeconnected[j] = false;
|
nodeconnected[j] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SINT8 getfreenode(void)
|
||||||
|
{
|
||||||
|
SINT8 j;
|
||||||
|
|
||||||
|
cleanupnodes();
|
||||||
|
|
||||||
|
for (j = 0; j < MAXNETNODES; j++)
|
||||||
|
if (!nodeconnected[j])
|
||||||
|
{
|
||||||
|
nodeconnected[j] = true;
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \warning No free node? Just in case a node might not have been freed properly,
|
||||||
|
* look if there are connected nodes that aren't in game, and forget them.
|
||||||
|
* It's dirty, and might result in a poor guy having to restart
|
||||||
|
* downloading a needed wad, but it's better than not letting anyone join...
|
||||||
|
*/
|
||||||
|
/*I_Error("No more free nodes!!1!11!11!!1111\n");
|
||||||
|
for (j = 1; j < MAXNETNODES; j++)
|
||||||
|
if (!nodeingame[j])
|
||||||
|
return j;*/
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUGMODE
|
||||||
|
void Command_Numnodes(void)
|
||||||
|
{
|
||||||
|
INT32 connected = 0;
|
||||||
|
INT32 ingame = 0;
|
||||||
|
INT32 i;
|
||||||
|
|
||||||
|
for (i = 1; i < MAXNETNODES; i++)
|
||||||
|
{
|
||||||
|
if (!(nodeconnected[i] || nodeingame[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nodeconnected[i])
|
||||||
|
connected++;
|
||||||
|
if (nodeingame[i])
|
||||||
|
ingame++;
|
||||||
|
|
||||||
|
CONS_Printf("%2d - ", i);
|
||||||
|
if (nodetoplayer[i] != -1)
|
||||||
|
CONS_Printf("player %.2d", nodetoplayer[i]);
|
||||||
|
else
|
||||||
|
CONS_Printf(" ");
|
||||||
|
if (nodeconnected[i])
|
||||||
|
CONS_Printf(" - connected");
|
||||||
|
else
|
||||||
|
CONS_Printf(" - ");
|
||||||
|
if (nodeingame[i])
|
||||||
|
CONS_Printf(" - ingame");
|
||||||
|
else
|
||||||
|
CONS_Printf(" - ");
|
||||||
|
CONS_Printf(" - %s\n", I_GetNodeAddress(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
CONS_Printf("\n"
|
||||||
|
"Connected: %d\n"
|
||||||
|
"Ingame: %d\n",
|
||||||
|
connected, ingame);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef NONET
|
#ifndef NONET
|
||||||
static void SOCK_Get(void)
|
// Returns true if a packet was received from a new node, false in all other cases
|
||||||
|
static boolean SOCK_Get(void)
|
||||||
{
|
{
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
int j;
|
int j;
|
||||||
|
@ -535,13 +595,12 @@ static void SOCK_Get(void)
|
||||||
doomcom->remotenode = (INT16)j; // good packet from a game player
|
doomcom->remotenode = (INT16)j; // good packet from a game player
|
||||||
doomcom->datalength = (INT16)c;
|
doomcom->datalength = (INT16)c;
|
||||||
nodesocket[j] = mysockets[n];
|
nodesocket[j] = mysockets[n];
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// not found
|
// not found
|
||||||
|
|
||||||
// find a free slot
|
// find a free slot
|
||||||
cleanupnodes();
|
|
||||||
j = getfreenode();
|
j = getfreenode();
|
||||||
if (j > 0)
|
if (j > 0)
|
||||||
{
|
{
|
||||||
|
@ -564,14 +623,15 @@ static void SOCK_Get(void)
|
||||||
}
|
}
|
||||||
if (i == numbans)
|
if (i == numbans)
|
||||||
SOCK_bannednode[j] = false;
|
SOCK_bannednode[j] = false;
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DEBFILE("New node detected: No more free slots\n");
|
DEBFILE("New node detected: No more free slots\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doomcom->remotenode = -1; // no packet
|
doomcom->remotenode = -1; // no packet
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1256,7 +1316,6 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
|
||||||
gaie = I_getaddrinfo(address, port, &hints, &ai);
|
gaie = I_getaddrinfo(address, port, &hints, &ai);
|
||||||
if (gaie == 0)
|
if (gaie == 0)
|
||||||
{
|
{
|
||||||
cleanupnodes();
|
|
||||||
newnode = getfreenode();
|
newnode = getfreenode();
|
||||||
}
|
}
|
||||||
if (newnode == -1)
|
if (newnode == -1)
|
||||||
|
|
|
@ -1684,7 +1684,7 @@ void P_CheckTimeLimit(void)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//Tagmode round end but only on the tic before the
|
//Tagmode round end but only on the tic before the
|
||||||
//XD_EXITLEVEL packet is recieved by all players.
|
//XD_EXITLEVEL packet is received by all players.
|
||||||
if (G_TagGametype())
|
if (G_TagGametype())
|
||||||
{
|
{
|
||||||
if (leveltime == (timelimitintics + 1))
|
if (leveltime == (timelimitintics + 1))
|
||||||
|
@ -1695,7 +1695,7 @@ void P_CheckTimeLimit(void)
|
||||||
|| (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT))
|
|| (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CONS_Printf(M_GetText("%s recieved double points for surviving the round.\n"), player_names[i]);
|
CONS_Printf(M_GetText("%s received double points for surviving the round.\n"), player_names[i]);
|
||||||
P_AddPlayerScore(&players[i], players[i].score);
|
P_AddPlayerScore(&players[i], players[i].score);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue