From a3353be0dce216dd7945a3c2f6af6ac24092e820 Mon Sep 17 00:00:00 2001 From: LZA <73-LZA@users.noreply.git.do.srb2.org> Date: Thu, 2 Dec 2021 22:50:44 +0000 Subject: [PATCH] Raise addon limit --- src/d_clisrv.c | 547 +++++++++++++++++++++++++++++++++++++------------ src/d_clisrv.h | 18 +- src/d_main.c | 102 +++++---- src/d_net.c | 2 + src/d_netcmd.c | 43 ++-- src/d_netcmd.h | 1 + src/d_netfil.c | 278 +++++++++++++++---------- src/d_netfil.h | 27 ++- src/doomdef.h | 3 + src/filesrch.c | 15 +- src/filesrch.h | 3 - src/m_menu.c | 11 +- src/w_wad.c | 74 ++----- src/w_wad.h | 20 +- 14 files changed, 768 insertions(+), 376 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index efe6473d4..36ced7f64 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -128,10 +128,14 @@ static UINT8 localtextcmd[MAXTEXTCMD]; static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen static tic_t neededtic; SINT8 servernode = 0; // the number of the server node + /// \brief do we accept new players? /// \todo WORK! boolean acceptnewnode = true; +static boolean serverisfull = false; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not +static tic_t firstconnectattempttime = 0; + // engine // Must be a power of two @@ -511,18 +515,24 @@ static INT16 Consistancy(void); typedef enum { CL_SEARCHING, + CL_CHECKFILES, CL_DOWNLOADFILES, CL_ASKJOIN, + CL_LOADFILES, CL_WAITJOINRESPONSE, CL_DOWNLOADSAVEGAME, CL_CONNECTED, - CL_ABORTED + CL_ABORTED, + CL_ASKFULLFILELIST, + CL_CONFIRMCONNECT } cl_mode_t; static void GetPackets(void); static cl_mode_t cl_mode = CL_SEARCHING; +static UINT16 cl_lastcheckedfilecount = 0; // used for full file list + #ifndef NONET #define SNAKE_SPEED 5 @@ -920,6 +930,8 @@ static void Snake_Draw(void) INT16 i; // Background + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + V_DrawFlatFill( SNAKE_LEFT_X + SNAKE_BORDER_SIZE, SNAKE_TOP_Y + SNAKE_BORDER_SIZE, @@ -1021,6 +1033,13 @@ static void Snake_Draw(void) ); } +static void CL_DrawConnectionStatusBox(void) +{ + M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); + if (cl_mode != CL_CONFIRMCONNECT) + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); +} + // // CL_DrawConnectionStatus // @@ -1031,28 +1050,32 @@ static inline void CL_DrawConnectionStatus(void) INT32 ccstime = I_GetTime(); // Draw background fade - if (!menuactive) // menu already draws its own fade - V_DrawFadeScreen(0xFF00, 16); // force default + V_DrawFadeScreen(0xFF00, 16); // force default - // Draw the bottom box. - M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); - - if (cl_mode != CL_DOWNLOADFILES) + if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_LOADFILES) { INT32 i, animtime = ((ccstime / 4) & 15) + 16; - UINT8 palstart = (cl_mode == CL_SEARCHING) ? 32 : 96; - // 15 pal entries total. + UINT8 palstart; const char *cltext; + // Draw the bottom box. + CL_DrawConnectionStatusBox(); + + if (cl_mode == CL_SEARCHING) + palstart = 32; // Red + else if (cl_mode == CL_CONFIRMCONNECT) + palstart = 48; // Orange + else + palstart = 96; // Green + if (!(cl_mode == CL_DOWNLOADSAVEGAME && lastfilenum != -1)) - for (i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) // 15 pal entries total. V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-16, 16, 8, palstart + ((animtime - i) & 15)); switch (cl_mode) { case CL_DOWNLOADSAVEGAME: - if (lastfilenum != -1) + if (fileneeded && lastfilenum != -1) { UINT32 currentsize = fileneeded[lastfilenum].currentsize; UINT32 totalsize = fileneeded[lastfilenum].totalsize; @@ -1076,9 +1099,22 @@ static inline void CL_DrawConnectionStatus(void) else cltext = M_GetText("Waiting to download game state..."); break; + case CL_ASKFULLFILELIST: + case CL_CHECKFILES: + cltext = M_GetText("Checking server addon list..."); + break; + case CL_CONFIRMCONNECT: + cltext = ""; + break; + case CL_LOADFILES: + cltext = M_GetText("Loading server addons..."); + break; case CL_ASKJOIN: case CL_WAITJOINRESPONSE: - cltext = M_GetText("Requesting to join..."); + if (serverisfull) + cltext = M_GetText("Server full, waiting for a slot..."); + else + cltext = M_GetText("Requesting to join..."); break; default: cltext = M_GetText("Connecting to server..."); @@ -1088,14 +1124,51 @@ static inline void CL_DrawConnectionStatus(void) } else { - if (lastfilenum != -1) + if (cl_mode == CL_LOADFILES) + { + INT32 totalfileslength; + INT32 loadcompletednum = 0; + INT32 i; + + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); + + //ima just count files here + if (fileneeded) + { + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_OPEN) + loadcompletednum++; + } + + // Loading progress + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, "Loading server addons..."); + totalfileslength = (INT32)((loadcompletednum/(double)(fileneedednum)) * 256); + M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, totalfileslength, 8, 96); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va(" %2u/%2u Files",loadcompletednum,fileneedednum)); + } + else if (lastfilenum != -1) { INT32 dldlength; static char tempname[28]; - fileneeded_t *file = &fileneeded[lastfilenum]; - char *filename = file->filename; + fileneeded_t *file; + char *filename; - Snake_Draw(); + if (snake) + Snake_Draw(); + + // Draw the bottom box. + CL_DrawConnectionStatusBox(); + + if (fileneeded) + { + file = &fileneeded[lastfilenum]; + filename = file->filename; + } + else + return; Net_GetNetStat(); dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); @@ -1128,20 +1201,32 @@ static inline void CL_DrawConnectionStatus(void) va("%3.1fK/s ", ((double)getbps)/1024)); } else + { + if (snake) + Snake_Draw(); + + CL_DrawConnectionStatusBox(); V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, M_GetText("Waiting to download files...")); + } } } #endif +static boolean CL_AskFileList(INT32 firstfile) +{ + netbuffer->packettype = PT_TELLFILESNEEDED; + netbuffer->u.filesneedednum = firstfile; + + return HSendPacket(servernode, false, 0, sizeof (INT32)); +} + /** Sends a special packet to declare how many players in local * Used only in arbitratrenetstart() * Sends a PT_CLIENTJOIN packet to the server * * \return True if the packet was successfully sent * \todo Improve the description... - * Because to be honest, I have no idea what arbitratrenetstart is... - * Is it even used...? * */ static boolean CL_SendJoin(void) @@ -1240,7 +1325,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) sizeof netbuffer->u.serverinfo.gametypename); netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); - netbuffer->u.serverinfo.isdedicated = (UINT8)dedicated; + netbuffer->u.serverinfo.flags = (dedicated ? SV_DEDICATED : 0); strncpy(netbuffer->u.serverinfo.servername, cv_servername.string, MAXSERVERNAME); strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7); @@ -1275,7 +1360,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) if (mapheaderinfo[gamemap-1]) netbuffer->u.serverinfo.actnum = mapheaderinfo[gamemap-1]->actnum; - p = PutFileNeeded(); + p = PutFileNeeded(0); HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); } @@ -1526,6 +1611,8 @@ static void CL_LoadReceivedSavegame(boolean reloading) size_t length, decompressedlen; char tmpsave[256]; + FreeFileNeeded(); + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); length = FIL_ReadFile(tmpsave, &savebuffer); @@ -1836,12 +1923,164 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room) #endif/*MASTERSERVER*/ } -static const char * InvalidServerReason (INT32 i) +#endif // ifndef NONET + +static void M_ConfirmConnect(event_t *ev) +{ +#ifndef NONET + if (ev->type == ev_keydown) + { + if (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER) + { + if (totalfilesrequestednum > 0) + { + if (CL_SendFileRequest()) + { + cl_mode = CL_DOWNLOADFILES; + Snake_Initialise(); + } + } + else + cl_mode = CL_LOADFILES; + + M_ClearMenus(true); + } + else if (ev->key == 'n' || ev->key == KEY_ESCAPE) + { + cl_mode = CL_ABORTED; + M_ClearMenus(true); + } + } +#else + (void)ev; +#endif +} + +static boolean CL_FinishedFileList(void) +{ + INT32 i; + char *downloadsize = NULL; + //CONS_Printf(M_GetText("Checking files...\n")); + i = CL_CheckFiles(); + if (i == 4) // still checking ... + { + return true; + } + else if (i == 3) // too many files + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "You have too many WAD files loaded\n" + "to add ones the server is using.\n" + "Please restart SRB2 before connecting.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + else if (i == 2) // cannot join for some reason + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "You have the wrong addons loaded.\n\n" + "To play on this server, restart\n" + "the game and don't load any addons.\n" + "SRB2 will automatically add\n" + "everything you need when you join.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + else if (i == 1) + { + if (serverisfull) + { + M_StartMessage(M_GetText( + "This server is full!\n" + "\n" + "You may load server addons (if any), and wait for a slot.\n" + "\n" + "Press ENTER to continue\nor ESC to cancel.\n\n" + ), M_ConfirmConnect, MM_EVENTHANDLER); + cl_mode = CL_CONFIRMCONNECT; + curfadevalue = 0; + } + else + cl_mode = CL_LOADFILES; + } + else + { + // must download something + // can we, though? + if (!CL_CheckDownloadable()) // nope! + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "An error occured when trying to\n" + "download missing addons.\n" + "(This is almost always a problem\n" + "with the server, not your game.)\n\n" + "See the console or log file\n" + "for additional details.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + +#ifndef NONET + downloadcompletednum = 0; + downloadcompletedsize = 0; + totalfilesrequestednum = 0; + totalfilesrequestedsize = 0; + + if (fileneeded == NULL) + I_Error("CL_FinishedFileList: fileneeded == NULL"); + + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD) + { + totalfilesrequestednum++; + totalfilesrequestedsize += fileneeded[i].totalsize; + } + + if (totalfilesrequestedsize>>20 >= 100) + downloadsize = Z_StrDup(va("%uM",totalfilesrequestedsize>>20)); + else + downloadsize = Z_StrDup(va("%uK",totalfilesrequestedsize>>10)); +#endif + + if (serverisfull) + M_StartMessage(va(M_GetText( + "This server is full!\n" + "Download of %s additional content\nis required to join.\n" + "\n" + "You may download, load server addons,\nand wait for a slot.\n" + "\n" + "Press ENTER to continue\nor ESC to cancel.\n" + ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); + else + M_StartMessage(va(M_GetText( + "Download of %s additional content\nis required to join.\n" + "\n" + "Press ENTER to continue\nor ESC to cancel.\n" + ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); + + Z_Free(downloadsize); + cl_mode = CL_CONFIRMCONNECT; + curfadevalue = 0; + } + return true; +} + +static const char * InvalidServerReason (serverinfo_pak *info) { #define EOT "\nPress ESC\n" - serverinfo_pak *info = &serverlist[i].info; - /* magic number for new packet format */ if (info->_255 != 255) { @@ -1902,8 +2141,6 @@ static const char * InvalidServerReason (INT32 i) #undef EOT } -#endif // ifndef NONET - /** Called by CL_ServerConnectionTicker * * \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit. @@ -1936,86 +2173,44 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) if (client) { - const char *reason = InvalidServerReason(i); + serverinfo_pak *info = &serverlist[i].info; - // Quit here rather than downloading files - // and being refused later. - if (reason) - { - char *message = Z_StrDup(reason); - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(message, NULL, MM_NOTHING); - Z_Free(message); - return false; - } - - D_ParseFileneeded(serverlist[i].info.fileneedednum, - serverlist[i].info.fileneeded); - CONS_Printf(M_GetText("Checking files...\n")); - i = CL_CheckFiles(); - if (i == 3) // too many files - { - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText( - "You have too many WAD files loaded\n" - "to add ones the server is using.\n" - "Please restart SRB2 before connecting.\n\n" - "Press ESC\n" - ), NULL, MM_NOTHING); - return false; - } - else if (i == 2) // cannot join for some reason - { - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText( - "You have the wrong addons loaded.\n\n" - "To play on this server, restart\n" - "the game and don't load any addons.\n" - "SRB2 will automatically add\n" - "everything you need when you join.\n\n" - "Press ESC\n" - ), NULL, MM_NOTHING); - return false; - } - else if (i == 1) - cl_mode = CL_ASKJOIN; + if (info->refusereason == REFUSE_SLOTS_FULL) + serverisfull = true; else { - // must download something - // can we, though? - if (!CL_CheckDownloadable()) // nope! + const char *reason = InvalidServerReason(info); + + // Quit here rather than downloading files + // and being refused later. + if (reason) { + char *message = Z_StrDup(reason); D_QuitNetGame(); CL_Reset(); D_StartTitle(); - M_StartMessage(M_GetText( - "You cannot connect to this server\n" - "because you cannot download the files\n" - "that you are missing from the server.\n\n" - "See the console or log file for\n" - "more details.\n\n" - "Press ESC\n" - ), NULL, MM_NOTHING); + M_StartMessage(message, NULL, MM_NOTHING); + Z_Free(message); return false; } - // no problem if can't send packet, we will retry later - if (CL_SendFileRequest()) - { - cl_mode = CL_DOWNLOADFILES; -#ifndef NONET - Snake_Initialise(); -#endif - } } + + D_ParseFileneeded(info->fileneedednum, info->fileneeded, 0); + + if (info->flags & SV_LOTSOFADDONS) + { + cl_mode = CL_ASKFULLFILELIST; + cl_lastcheckedfilecount = 0; + return true; + } + + cl_mode = CL_CHECKFILES; } else + { cl_mode = CL_ASKJOIN; // files need not be checked for the server. + *asksent = 0; + } return true; } @@ -2061,6 +2256,22 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic return false; break; + case CL_ASKFULLFILELIST: + if (cl_lastcheckedfilecount == UINT16_MAX) // All files retrieved + cl_mode = CL_CHECKFILES; + else if (fileneedednum != cl_lastcheckedfilecount || I_GetTime() >= *asksent) + { + if (CL_AskFileList(fileneedednum)) + { + cl_lastcheckedfilecount = fileneedednum; + *asksent = I_GetTime() + NEWTICRATE; + } + } + break; + case CL_CHECKFILES: + if (!CL_FinishedFileList()) + return false; + break; case CL_DOWNLOADFILES: waitmore = false; for (i = 0; i < fileneedednum; i++) @@ -2081,21 +2292,51 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic } #endif - cl_mode = CL_ASKJOIN; // don't break case continue to cljoin request now - /* FALLTHRU */ - + cl_mode = CL_LOADFILES; + break; + case CL_LOADFILES: + if (CL_LoadServerFiles()) + { + FreeFileNeeded(); + *asksent = 0; //This ensure the first join ask is right away + firstconnectattempttime = I_GetTime(); + cl_mode = CL_ASKJOIN; + } + break; case CL_ASKJOIN: - CL_LoadServerFiles(); + if (firstconnectattempttime + NEWTICRATE*300 < I_GetTime() && !server) + { + CONS_Printf(M_GetText("5 minute wait time exceeded.\n")); + CONS_Printf(M_GetText("Network game synchronization aborted.\n")); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "5 minute wait time exceeded.\n" + "You may retry connection.\n" + "\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } #ifndef NONET // prepare structures to save the file // WARNING: this can be useless in case of server not in GS_LEVEL // but since the network layer doesn't provide ordered packets... CL_PrepareDownloadSaveGame(tmpsave); #endif - if (CL_SendJoin()) + if (I_GetTime() >= *asksent && CL_SendJoin()) + { + *asksent = I_GetTime() + NEWTICRATE*3; cl_mode = CL_WAITJOINRESPONSE; + } + break; + case CL_WAITJOINRESPONSE: + if (I_GetTime() >= *asksent) + { + cl_mode = CL_ASKJOIN; + } break; - #ifndef NONET case CL_DOWNLOADSAVEGAME: // At this state, the first (and only) needed file is the gamestate @@ -2109,8 +2350,8 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic break; #endif - case CL_WAITJOINRESPONSE: case CL_CONNECTED: + case CL_CONFIRMCONNECT: //logic is handled by M_ConfirmConnect default: break; @@ -2118,7 +2359,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic case CL_ABORTED: cl_mode = CL_SEARCHING; return false; - } GetPackets(); @@ -2128,13 +2368,19 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic if (*oldtic != I_GetTime()) { I_OsPolling(); - for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) - G_MapEventsToControls(&events[eventtail]); - if (gamekeydown[KEY_ESCAPE] || gamekeydown[KEY_JOY1+1]) + if (cl_mode == CL_CONFIRMCONNECT) + D_ProcessEvents(); //needed for menu system to receive inputs + else + { + for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) + G_MapEventsToControls(&events[eventtail]); + } + + if (gamekeydown[KEY_ESCAPE] || gamekeydown[KEY_JOY1+1] || cl_mode == CL_ABORTED) { CONS_Printf(M_GetText("Network game synchronization aborted.\n")); -// M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); + M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); #ifndef NONET if (snake) @@ -2167,13 +2413,20 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic #ifndef NONET if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) { - if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_DOWNLOADSAVEGAME) + if (!snake) { F_MenuPresTicker(true); // title sky F_TitleScreenTicker(true); F_TitleScreenDrawer(); } CL_DrawConnectionStatus(); +#ifdef HAVE_THREADS + I_lock_mutex(&m_menu_mutex); +#endif + M_Drawer(); //Needed for drawing messageboxes on the connection screen +#ifdef HAVE_THREADS + I_unlock_mutex(m_menu_mutex); +#endif I_UpdateNoVsync(); // page flip or blit buffer if (moviemode) M_SaveFrame(); @@ -2235,8 +2488,10 @@ static void CL_ConnectToServer(void) ClearAdminPlayers(); pnumnodes = 1; oldtic = I_GetTime() - 1; + #ifndef NONET asksent = (tic_t) - TICRATE; + firstconnectattempttime = I_GetTime(); i = SL_SearchServer(servernode); @@ -2676,8 +2931,16 @@ void CL_Reset(void) SV_ResetServer(); // make sure we don't leave any fileneeded gunk over from a failed join + FreeFileNeeded(); fileneedednum = 0; - memset(fileneeded, 0, sizeof(fileneeded)); + +#ifndef NONET + totalfilesrequestednum = 0; + totalfilesrequestedsize = 0; +#endif + firstconnectattempttime = 0; + serverisfull = false; + connectiontimeout = (tic_t)cv_nettimeout.value; //reset this temporary hack // D_StartTitle should get done now, but the calling function will handle it } @@ -3968,31 +4231,40 @@ static void HandlePacketFromAwayNode(SINT8 node) switch (netbuffer->packettype) { case PT_ASKINFOVIAMS: -#if 0 + Net_CloseConnection(node); + break; + + case PT_TELLFILESNEEDED: if (server && serverrunning) { - INT32 clientnode; - if (ms_RoomId < 0) // ignore if we're not actually on the MS right now - { - Net_CloseConnection(node); // and yes, close connection - return; - } - clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr); - if (clientnode != -1) - { - SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time)); - SV_SendPlayerInfo(clientnode); // Send extra info - Net_CloseConnection(clientnode); - // Don't close connection to MS... - } - else - Net_CloseConnection(node); // ...unless the IP address is not valid + UINT8 *p; + INT32 firstfile = netbuffer->u.filesneedednum; + + netbuffer->packettype = PT_MOREFILESNEEDED; + netbuffer->u.filesneededcfg.first = firstfile; + netbuffer->u.filesneededcfg.more = 0; + + p = PutFileNeeded(firstfile); + + HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); + } + else // Shouldn't get this if you aren't the server...? + Net_CloseConnection(node); + break; + + case PT_MOREFILESNEEDED: + if (server && serverrunning) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + break; + } + SERVERONLY + if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum) + { + D_ParseFileneeded(netbuffer->u.filesneededcfg.num, netbuffer->u.filesneededcfg.files, netbuffer->u.filesneededcfg.first); + if (!netbuffer->u.filesneededcfg.more) + cl_lastcheckedfilecount = UINT16_MAX; // Got the whole file list } - else - Net_CloseConnection(node); // you're not supposed to get it, so ignore it -#else - Net_CloseConnection(node); -#endif break; case PT_ASKINFO: @@ -4018,13 +4290,24 @@ static void HandlePacketFromAwayNode(SINT8 node) if (!reason) I_Error("Out of memory!\n"); - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); + if (strstr(reason, "Maximum players reached")) + { + serverisfull = true; + //Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer + //We set it back to the value of cv_nettimeout.value in CL_Reset + connectiontimeout = NEWTICRATE*7; + cl_mode = CL_ASKJOIN; + free(reason); + break; + } M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), reason), NULL, MM_NOTHING); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + free(reason); // Will be reset by caller. Signals refusal. diff --git a/src/d_clisrv.h b/src/d_clisrv.h index a89c054e1..8e75fb963 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -94,6 +94,9 @@ typedef enum PT_LOGIN, // Login attempt from the client. + PT_TELLFILESNEEDED, // Client, to server: "what other files do I need starting from this number?" + PT_MOREFILESNEEDED, // Server, to client: "you need these (+ more on top of those)" + PT_PING, // Packet sent to tell clients the other client's latency to server. NUMPACKETTYPE } packettype_t; @@ -198,6 +201,9 @@ typedef struct char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME]; } ATTRPACK clientconfig_pak; +#define SV_DEDICATED 0x40 // server is dedicated +#define SV_LOTSOFADDONS 0x20 // flag used to ask for full file list in d_netfil + enum { REFUSE_JOINS_DISABLED = 1, REFUSE_SLOTS_FULL, @@ -225,7 +231,7 @@ typedef struct char gametypename[24]; UINT8 modifiedgame; UINT8 cheatsenabled; - UINT8 isdedicated; + UINT8 flags; UINT8 fileneedednum; tic_t time; tic_t leveltime; @@ -279,6 +285,14 @@ typedef struct UINT8 ctfteam; } ATTRPACK plrconfig; +typedef struct +{ + INT32 first; + UINT8 num; + UINT8 more; + UINT8 files[MAXFILENEEDED]; // is filled with writexxx (byteptr.h) +} ATTRPACK filesneededconfig_pak; + // // Network packet data // @@ -308,6 +322,8 @@ typedef struct msaskinfo_pak msaskinfo; // 22 bytes plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?) plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) + INT32 filesneedednum; // 4 bytes + filesneededconfig_pak filesneededcfg; // ??? bytes UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes } u; // This is needed to pack diff packet types data together } ATTRPACK doomdata_t; diff --git a/src/d_main.c b/src/d_main.c index 679a596b3..15f85f2e8 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -65,7 +65,7 @@ #include "m_cond.h" // condition initialization #include "fastcmp.h" #include "keys.h" -#include "filesrch.h" // refreshdirmenu, mainwadstally +#include "filesrch.h" // refreshdirmenu #include "g_input.h" // tutorial mode control scheming #include "m_perfstats.h" @@ -96,11 +96,8 @@ int SUBVERSION; // platform independant focus loss UINT8 window_notinfocus = false; -// -// DEMO LOOP -// -static char *startupwadfiles[MAX_WADFILES]; -static char *startuppwads[MAX_WADFILES]; +static addfilelist_t startupwadfiles; +static addfilelist_t startuppwads; boolean devparm = false; // started game with -devparm @@ -119,6 +116,9 @@ boolean midi_disabled = false; boolean sound_disabled = false; boolean digital_disabled = false; +// +// DEMO LOOP +// boolean advancedemo; #ifdef DEBUGFILE INT32 debugload = 0; @@ -923,51 +923,68 @@ void D_StartTitle(void) tutorialmode = false; } -// -// D_AddFile -// -static void D_AddFile(char **list, const char *file) -{ - size_t pnumwadfiles; - char *newfile; +#define REALLOC_FILE_LIST \ + if (list->files == NULL) \ + { \ + list->files = calloc(sizeof(list->files), 2); \ + list->numfiles = 1; \ + } \ + else \ + { \ + index = list->numfiles; \ + list->files = realloc(list->files, sizeof(list->files) * ((++list->numfiles) + 1)); \ + if (list->files == NULL) \ + I_Error("%s: No more free memory to add file %s", __FUNCTION__, file); \ + } - for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++) - ; +static void D_AddFile(addfilelist_t *list, const char *file) +{ + char *newfile; + size_t index = 0; + + REALLOC_FILE_LIST newfile = malloc(strlen(file) + 1); if (!newfile) - I_Error("No more free memory to AddFile %s",file); + I_Error("D_AddFile: No more free memory to add file %s", file); strcpy(newfile, file); - list[pnumwadfiles] = newfile; + list->files[index] = newfile; } -static void D_AddFolder(char **list, const char *file) +static void D_AddFolder(addfilelist_t *list, const char *file) { - size_t pnumwadfiles; char *newfile; + size_t index = 0; - for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++) - ; + REALLOC_FILE_LIST newfile = malloc(strlen(file) + 2); // Path delimiter + NULL terminator if (!newfile) - I_Error("No more free memory to AddFolder %s",file); + I_Error("D_AddFolder: No more free memory to add folder %s", file); strcpy(newfile, file); strcat(newfile, PATHSEP); - list[pnumwadfiles] = newfile; + list->files[index] = newfile; } -static inline void D_CleanFile(char **list) +#undef REALLOC_FILE_LIST + +static inline void D_CleanFile(addfilelist_t *list) { - size_t pnumwadfiles; - for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++) + if (list->files) { - free(list[pnumwadfiles]); - list[pnumwadfiles] = NULL; + size_t pnumwadfiles = 0; + + for (; pnumwadfiles < list->numfiles; pnumwadfiles++) + free(list->files[pnumwadfiles]); + + free(list->files); + list->files = NULL; } + + list->numfiles = 0; } ///\brief Checks if a netgame URL is being handled, and changes working directory to the EXE's if so. @@ -1051,7 +1068,7 @@ static void IdentifyVersion(void) // Load the IWAD if (srb2wad != NULL && FIL_ReadFileOK(srb2wad)) - D_AddFile(startupwadfiles, srb2wad); + D_AddFile(&startupwadfiles, srb2wad); else I_Error("srb2.pk3 not found! Expected in %s, ss file: %s\n", srb2waddir, srb2wad); @@ -1062,14 +1079,14 @@ static void IdentifyVersion(void) // checking in D_SRB2Main // Add the maps - D_AddFile(startupwadfiles, va(pandf,srb2waddir,"zones.pk3")); + D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "zones.pk3")); // Add the players - D_AddFile(startupwadfiles, va(pandf,srb2waddir, "player.dta")); + D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "player.dta")); #ifdef USE_PATCH_DTA // Add our crappy patches to fix our bugs - D_AddFile(startupwadfiles, va(pandf,srb2waddir,"patch.pk3")); + D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "patch.pk3")); #endif #if !defined (HAVE_SDL) || defined (HAVE_MIXER) @@ -1079,7 +1096,7 @@ static void IdentifyVersion(void) const char *musicpath = va(pandf,srb2waddir,str);\ int ms = W_VerifyNMUSlumps(musicpath, false); \ if (ms == 1) \ - D_AddFile(startupwadfiles, musicpath); \ + D_AddFile(&startupwadfiles, musicpath); \ else if (ms == 0) \ I_Error("File "str" has been modified with non-music/sound lumps"); \ } @@ -1269,9 +1286,9 @@ void D_SRB2Main(void) else if (myargv[i][0] == '-' || myargv[i][0] == '+') addontype = 0; else if (addontype == 1) - D_AddFile(startuppwads, myargv[i]); + D_AddFile(&startuppwads, myargv[i]); else if (addontype == 2) - D_AddFolder(startuppwads, myargv[i]); + D_AddFolder(&startuppwads, myargv[i]); } } @@ -1310,8 +1327,8 @@ void D_SRB2Main(void) // load wad, including the main wad file CONS_Printf("W_InitMultipleFiles(): Adding IWAD and main PWADs.\n"); - W_InitMultipleFiles(startupwadfiles); - D_CleanFile(startupwadfiles); + W_InitMultipleFiles(&startupwadfiles); + D_CleanFile(&startupwadfiles); #ifndef DEVELOP // md5s last updated 22/02/20 (ddmmyy) @@ -1326,8 +1343,6 @@ void D_SRB2Main(void) // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for. #endif //ifndef DEVELOP - mainwadstally = packetsizetally; // technically not accurate atm, remember to port the two-stage -file process from kart in 2.2.x - cht_Init(); //---------------------------------------------------- READY SCREEN @@ -1360,9 +1375,12 @@ void D_SRB2Main(void) CON_StopRefresh(); // Temporarily stop refreshing the screen for wad loading - CONS_Printf("W_InitMultipleFiles(): Adding extra PWADs.\n"); - W_InitMultipleFiles(startuppwads); - D_CleanFile(startuppwads); + if (startuppwads.numfiles) + { + CONS_Printf("W_InitMultipleFiles(): Adding extra PWADs.\n"); + W_InitMultipleFiles(&startuppwads); + D_CleanFile(&startuppwads); + } CON_StartRefresh(); // Restart the refresh! diff --git a/src/d_net.c b/src/d_net.c index 9e5abe24a..3a4746002 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -815,6 +815,8 @@ static const char *packettypename[NUMPACKETTYPE] = "CLIENTJOIN", "NODETIMEOUT", "LOGIN", + "TELLFILESNEEDED", + "MOREFILESNEEDED", "PING" }; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 5eb360bef..7024e64fb 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3223,7 +3223,7 @@ static void Command_RunSOC(void) static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum) { char filename[256]; - filestatus_t ncs = FS_NOTFOUND; + filestatus_t ncs = FS_NOTCHECKED; if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { @@ -3347,10 +3347,9 @@ static void Command_Addfile(void) break; ++p; - // check total packet size and no of files currently loaded - // See W_InitFile in w_wad.c - if ((numwadfiles >= MAX_WADFILES) - || ((packetsizetally + nameonlylength(fn) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8))) + // check no of files currently loaded + // See W_LoadWadFile in w_wad.c + if (numwadfiles >= MAX_WADFILES) { CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); return; @@ -3379,6 +3378,9 @@ static void Command_Addfile(void) for (i = 0; i < numwadfiles; i++) { + if (wadfiles[i]->type == RET_FOLDER) + continue; + if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) { CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), fn); @@ -3469,10 +3471,9 @@ static void Command_Addfolder(void) continue; } - // check total packet size and no of files currently loaded - // See W_InitFile in w_wad.c - if ((numwadfiles >= MAX_WADFILES) - || ((packetsizetally + strlen(fn) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8))) + // check no of files currently loaded + // See W_LoadWadFile in w_wad.c + if (numwadfiles >= MAX_WADFILES) { CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); return; @@ -3534,7 +3535,7 @@ static void Command_Addfolder(void) static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) { char filename[241]; - filestatus_t ncs = FS_NOTFOUND; + filestatus_t ncs = FS_NOTCHECKED; UINT8 md5sum[16]; boolean kick = false; boolean toomany = false; @@ -3559,9 +3560,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) return; } - // See W_InitFile in w_wad.c - if ((numwadfiles >= MAX_WADFILES) - || ((packetsizetally + nameonlylength(filename) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8))) + if (numwadfiles >= MAX_WADFILES) toomany = true; else ncs = findfile(filename,md5sum,true); @@ -3594,7 +3593,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) static void Got_RequestAddfoldercmd(UINT8 **cp, INT32 playernum) { char path[241]; - filestatus_t ncs = FS_NOTFOUND; + filestatus_t ncs = FS_NOTCHECKED; boolean kick = false; boolean toomany = false; INT32 i,j; @@ -3619,9 +3618,7 @@ static void Got_RequestAddfoldercmd(UINT8 **cp, INT32 playernum) return; } - // See W_InitFile in w_wad.c - if ((numwadfiles >= MAX_WADFILES) - || ((packetsizetally + strlen(path) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8))) + if (numwadfiles >= MAX_WADFILES) toomany = true; else ncs = findfolder(path); @@ -3652,7 +3649,7 @@ static void Got_RequestAddfoldercmd(UINT8 **cp, INT32 playernum) static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) { char filename[241]; - filestatus_t ncs = FS_NOTFOUND; + filestatus_t ncs = FS_NOTCHECKED; UINT8 md5sum[16]; READSTRINGN(*cp, filename, 240); @@ -3700,7 +3697,7 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) static void Got_Addfoldercmd(UINT8 **cp, INT32 playernum) { char path[241]; - filestatus_t ncs = FS_NOTFOUND; + filestatus_t ncs = FS_NOTCHECKED; READSTRINGN(*cp, path, 240); @@ -3744,7 +3741,13 @@ static void Command_ListWADS_f(void) { INT32 i = numwadfiles; char *tempname; - CONS_Printf(M_GetText("There are %d wads loaded:\n"),numwadfiles); + +#ifdef ENFORCE_WAD_LIMIT + CONS_Printf(M_GetText("There are %d/%d files loaded:\n"),numwadfiles,MAX_WADFILES); +#else + CONS_Printf(M_GetText("There are %d files loaded:\n"),numwadfiles); +#endif + for (i--; i >= 0; i--) { nameonly(tempname = va("%s", wadfiles[i]->filename)); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index cae32643e..efe00552a 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -73,6 +73,7 @@ extern consvar_t cv_teamscramble; extern consvar_t cv_scrambleonchange; extern consvar_t cv_netstat; +extern consvar_t cv_nettimeout; extern consvar_t cv_countdowntime; extern consvar_t cv_runscripts; diff --git a/src/d_netfil.c b/src/d_netfil.c index 12c5ee6a2..a1dd02eeb 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -52,7 +52,7 @@ #include // Prototypes -static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid); +static boolean AddFileToSendQueue(INT32 node, UINT8 fileid); // Sender structure typedef struct filetx_s @@ -87,7 +87,7 @@ static filetran_t transfer[MAXNETNODES]; // Receiver structure INT32 fileneedednum; // Number of files needed to join the server -fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files +fileneeded_t *fileneeded; // List of needed files static tic_t lasttimeackpacketsent = 0; char downloaddir[512] = "DOWNLOAD"; @@ -105,6 +105,10 @@ static pauseddownload_t *pauseddownload = NULL; #ifndef NONET // for cl loading screen INT32 lastfilenum = -1; +INT32 downloadcompletednum = 0; +UINT32 downloadcompletedsize = 0; +INT32 totalfilesrequestednum = 0; +UINT32 totalfilesrequestedsize = 0; #endif luafiletransfer_t *luafiletransfers = NULL; @@ -113,25 +117,62 @@ boolean waitingforluafilecommand = false; char luafiledir[256 + 16] = "luafiles"; +static UINT16 GetWadNumFromFileNeededId(UINT8 id) +{ + UINT16 wadnum; + + for (wadnum = mainwads; wadnum < numwadfiles; wadnum++) + { + if (!wadfiles[wadnum]->important) + continue; + if (id == 0) + return wadnum; + id--; + } + + return UINT16_MAX; +} + /** Fills a serverinfo packet with information about wad files loaded. * * \todo Give this function a better name since it is in global scope. * Used to have size limiting built in - now handled via W_InitFile in w_wad.c * */ -UINT8 *PutFileNeeded(void) +UINT8 *PutFileNeeded(UINT16 firstfile) { - size_t i, count = 0; - UINT8 *p = netbuffer->u.serverinfo.fileneeded; + size_t i; + UINT8 count = 0; + UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded; + UINT8 *p = p_start; char wadfilename[MAX_WADPATH] = ""; UINT8 filestatus, folder; - for (i = 0; i < numwadfiles; i++) + for (i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad { // If it has only music/sound lumps, don't put it in the list if (!wadfiles[i]->important) continue; + if (firstfile) + { // Skip files until we reach the first file. + firstfile--; + continue; + } + + nameonly(strcpy(wadfilename, wadfiles[i]->filename)); + + // Look below at the WRITE macros to understand what these numbers mean. + if (p + 1 + 4 + min(strlen(wadfilename) + 1, MAX_WADPATH) + 16 > p_start + MAXFILENEEDED) + { + // Too many files to send all at once + if (netbuffer->packettype == PT_MOREFILESNEEDED) + netbuffer->u.filesneededcfg.more = 1; + else + netbuffer->u.serverinfo.flags |= SV_LOTSOFADDONS; + break; + } + filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS folder = (wadfiles[i]->type == RET_FOLDER); @@ -148,32 +189,53 @@ UINT8 *PutFileNeeded(void) count++; WRITEUINT32(p, wadfiles[i]->filesize); - nameonly(strcpy(wadfilename, wadfiles[i]->filename)); WRITESTRINGN(p, wadfilename, MAX_WADPATH); WRITEMEM(p, wadfiles[i]->md5sum, 16); } - netbuffer->u.serverinfo.fileneedednum = (UINT8)count; + + if (netbuffer->packettype == PT_MOREFILESNEEDED) + netbuffer->u.filesneededcfg.num = count; + else + netbuffer->u.serverinfo.fileneedednum = count; return p; } +void AllocFileNeeded(INT32 size) +{ + if (fileneeded == NULL) + fileneeded = Z_Calloc(sizeof(fileneeded_t) * size, PU_STATIC, NULL); + else + fileneeded = Z_Realloc(fileneeded, sizeof(fileneeded_t) * size, PU_STATIC, NULL); +} + +void FreeFileNeeded(void) +{ + Z_Free(fileneeded); + fileneeded = NULL; +} + /** Parses the serverinfo packet and fills the fileneeded table on client * * \param fileneedednum_parm The number of files needed to join the server * \param fileneededstr The memory block containing the list of needed files * */ -void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr) +void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile) { INT32 i; UINT8 *p; UINT8 filestatus; - fileneedednum = fileneedednum_parm; + fileneedednum = firstfile + fileneedednum_parm; p = (UINT8 *)fileneededstr; - for (i = 0; i < fileneedednum; i++) + + AllocFileNeeded(fileneedednum); + + for (i = firstfile; i < fileneedednum; i++) { - fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet + fileneeded[i].type = FILENEEDED_WAD; + fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet fileneeded[i].justdownloaded = false; filestatus = READUINT8(p); // The first byte is the file status fileneeded[i].folder = READUINT8(p); // The second byte is the folder flag @@ -191,7 +253,11 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave) lastfilenum = -1; #endif + FreeFileNeeded(); + AllocFileNeeded(1); + fileneedednum = 1; + fileneeded[0].type = FILENEEDED_SAVEGAME; fileneeded[0].status = FS_REQUESTED; fileneeded[0].justdownloaded = false; fileneeded[0].totalsize = UINT32_MAX; @@ -322,14 +388,18 @@ boolean CL_SendFileRequest(void) if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)) { totalfreespaceneeded += fileneeded[i].totalsize; - nameonly(fileneeded[i].filename); + WRITEUINT8(p, i); // fileid - WRITESTRINGN(p, fileneeded[i].filename, MAX_WADPATH); + // put it in download dir + nameonly(fileneeded[i].filename); strcatbf(fileneeded[i].filename, downloaddir, "/"); + fileneeded[i].status = FS_REQUESTED; } + WRITEUINT8(p, 0xFF); + I_GetDiskFreeSpace(&availablefreespace); if (totalfreespaceneeded > availablefreespace) I_Error("To play on this server you must download %s KB,\n" @@ -345,21 +415,22 @@ boolean CL_SendFileRequest(void) // returns false if a requested file was not found or cannot be sent boolean PT_RequestFile(INT32 node) { - char wad[MAX_WADPATH+1]; UINT8 *p = netbuffer->u.textcmd; UINT8 id; + while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow { id = READUINT8(p); if (id == 0xFF) break; - READSTRINGN(p, wad, MAX_WADPATH); - if (!AddFileToSendQueue(node, wad, id)) + + if (!AddFileToSendQueue(node, id)) { SV_AbortSendFiles(node); return false; // don't read the rest of the files } } + return true; // no problems with any files } @@ -368,23 +439,16 @@ boolean PT_RequestFile(INT32 node) * \return 0 if some files are missing * 1 if all files exist * 2 if some already loaded files are not requested or are in a different order + * 3 too many files, over WADLIMIT + * 4 still checking, continuing next tic * */ INT32 CL_CheckFiles(void) { INT32 i, j; char wadfilename[MAX_WADPATH]; - INT32 ret = 1; - size_t packetsize = 0; - size_t filestoget = 0; - -// if (M_CheckParm("-nofiles")) -// return 1; - - // the first is the iwad (the main wad file) - // we don't care if it's called srb2.pk3 or not. - // Never download the IWAD, just assume it's there and identical - fileneeded[0].status = FS_OPEN; + size_t filestoload = 0; + boolean downloadrequired = false; // Modified game handling -- check for an identical file list // must be identical in files loaded AND in order @@ -392,7 +456,7 @@ INT32 CL_CheckFiles(void) if (modifiedgame) { CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n"); - for (i = 1, j = 1; i < fileneedednum || j < numwadfiles;) + for (i = 0, j = mainwads; i < fileneedednum || j < numwadfiles;) { if (j < numwadfiles && !wadfiles[j]->important) { @@ -419,15 +483,21 @@ INT32 CL_CheckFiles(void) return 1; } - // See W_InitFile in w_wad.c - packetsize = packetsizetally; - - for (i = 1; i < fileneedednum; i++) + for (i = 0; i < fileneedednum; i++) { + if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD) + downloadrequired = true; + + if (fileneeded[i].status != FS_OPEN) + filestoload++; + + if (fileneeded[i].status != FS_NOTCHECKED) //since we're running this over multiple tics now, its possible for us to come across files checked in previous tics + continue; + CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename); // Check in already loaded files - for (j = 1; wadfiles[j]; j++) + for (j = mainwads; wadfiles[j]; j++) { nameonly(strcpy(wadfilename, wadfiles[j]->filename)); if (!stricmp(wadfilename, fileneeded[i].filename) && @@ -435,43 +505,34 @@ INT32 CL_CheckFiles(void) { CONS_Debug(DBG_NETPLAY, "already loaded\n"); fileneeded[i].status = FS_OPEN; - break; + return 4; } } - if (fileneeded[i].status != FS_NOTFOUND) - continue; - - if (fileneeded[i].folder) - packetsize += strlen(fileneeded[i].filename) + FILENEEDEDSIZE; - else - packetsize += nameonlylength(fileneeded[i].filename) + FILENEEDEDSIZE; - - if ((numwadfiles+filestoget >= MAX_WADFILES) - || (packetsize > MAXFILENEEDED*sizeof(UINT8))) - return 3; - - filestoget++; if (fileneeded[i].folder) fileneeded[i].status = findfolder(fileneeded[i].filename); else fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true); + CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status); - if (fileneeded[i].status != FS_FOUND) - ret = 0; + return 4; } - return ret; + + //now making it here means we've checked the entire list and no FS_NOTCHECKED files remain + if (numwadfiles+filestoload > MAX_WADFILES) + return 3; + else if (downloadrequired) + return 0; //some stuff is FS_NOTFOUND, needs download + else + return 1; //everything is FS_OPEN or FS_FOUND, proceed to loading } // Load it now -void CL_LoadServerFiles(void) +boolean CL_LoadServerFiles(void) { INT32 i; -// if (M_CheckParm("-nofiles")) -// return; - - for (i = 1; i < fileneedednum; i++) + for (i = 0; i < fileneedednum; i++) { if (fileneeded[i].status == FS_OPEN) continue; // Already loaded @@ -483,6 +544,7 @@ void CL_LoadServerFiles(void) P_AddWadFile(fileneeded[i].filename); G_SetGameModified(true); fileneeded[i].status = FS_OPEN; + return false; } else if (fileneeded[i].status == FS_MD5SUMBAD) I_Error("Wrong version of file %s", fileneeded[i].filename); @@ -508,6 +570,7 @@ void CL_LoadServerFiles(void) fileneeded[i].status, s); } } + return true; } void AddLuaFileTransfer(const char *filename, const char *mode) @@ -689,7 +752,11 @@ void CL_PrepareDownloadLuaFile(void) netbuffer->packettype = PT_ASKLUAFILE; HSendPacket(servernode, true, 0, 0); + FreeFileNeeded(); + AllocFileNeeded(1); + fileneedednum = 1; + fileneeded[0].type = FILENEEDED_LUAFILE; fileneeded[0].status = FS_REQUESTED; fileneeded[0].justdownloaded = false; fileneeded[0].totalsize = UINT32_MAX; @@ -716,15 +783,11 @@ static INT32 filestosend = 0; * \sa AddLuaFileToSendQueue * */ -static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid) +static boolean AddFileToSendQueue(INT32 node, UINT8 fileid) { filetx_t **q; // A pointer to the "next" field of the last file in the list filetx_t *p; // The new file request - INT32 i; - char wadfilename[MAX_WADPATH]; - - if (cv_noticedownload.value) - CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node)); + UINT16 wadnum; // Find the last file in the list and set a pointer to its "next" field q = &transfer[node].txlist; @@ -744,51 +807,43 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid if (!p->id.filename) I_Error("AddFileToSendQueue: No more memory\n"); - // Set the file name and get rid of the path - strlcpy(p->id.filename, filename, MAX_WADPATH); - nameonly(p->id.filename); - - // Look for the requested file through all loaded files - for (i = 0; wadfiles[i]; i++) - { - strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH); - nameonly(wadfilename); - if (!stricmp(wadfilename, p->id.filename)) - { - // Copy file name with full path - strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH); - break; - } - } + // Find the wad the ID refers to + wadnum = GetWadNumFromFileNeededId(fileid); // Handle non-loaded file requests - if (!wadfiles[i]) + if (wadnum == UINT16_MAX) { - DEBFILE(va("%s not found in wadfiles\n", filename)); + DEBFILE(va("fileneeded %d not found in wadfiles\n", fileid)); // This formerly checked if (!findfile(p->id.filename, NULL, true)) // Not found // Don't inform client - DEBFILE(va("Client %d request %s: not found\n", node, filename)); + DEBFILE(va("Client %d request fileneeded %d: not found\n", node, fileid)); free(p->id.filename); free(p); *q = NULL; return false; // cancel the rest of the requests } + // Set the file name and get rid of the path + strlcpy(p->id.filename, wadfiles[wadnum]->filename, MAX_WADPATH); + // Handle huge file requests (i.e. bigger than cv_maxsend.value KB) - if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024) + if (wadfiles[wadnum]->filesize > (UINT32)cv_maxsend.value * 1024) { // Too big // Don't inform client (client sucks, man) - DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename)); + DEBFILE(va("Client %d request %s: file too big, not sending\n", node, p->id.filename)); free(p->id.filename); free(p); *q = NULL; return false; // cancel the rest of the requests } - DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node)); + if (cv_noticedownload.value) + CONS_Printf("Sending file \"%s\" to node %d (%s)\n", p->id.filename, node, I_GetNodeAddress(node)); + + DEBFILE(va("Sending file %s (id=%d) to %d\n", p->id.filename, fileid, node)); p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it p->fileid = fileid; p->next = NULL; // End of list @@ -1242,6 +1297,9 @@ void PT_FileFragment(void) UINT16 boundedfragmentsize = doomcom->datalength - BASEPACKETSIZE - sizeof(netbuffer->u.filetxpak); char *filename; + if (!file) + return; + filename = va("%s", file->filename); nameonly(filename); @@ -1353,6 +1411,7 @@ void PT_FileFragment(void) // Tell the server we have received the file netbuffer->packettype = PT_HASLUAFILE; HSendPacket(servernode, true, 0, 0); + FreeFileNeeded(); } } } @@ -1423,32 +1482,37 @@ void CloseNetFile(void) SV_AbortSendFiles(i); // Receiving a file? - for (i = 0; i < MAX_WADFILES; i++) - if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file) - { - fclose(fileneeded[i].file); - free(fileneeded[i].ackpacket); - - if (!pauseddownload && i != 0) // 0 is either srb2.srb or the gamestate... + if (fileneeded) + { + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file) { - // Don't remove the file, save it for later in case we resume the download - pauseddownload = malloc(sizeof(*pauseddownload)); - if (!pauseddownload) - I_Error("CloseNetFile: No more memory\n"); + fclose(fileneeded[i].file); + free(fileneeded[i].ackpacket); - strcpy(pauseddownload->filename, fileneeded[i].filename); - memcpy(pauseddownload->md5sum, fileneeded[i].md5sum, 16); - pauseddownload->currentsize = fileneeded[i].currentsize; - pauseddownload->receivedfragments = fileneeded[i].receivedfragments; - pauseddownload->fragmentsize = fileneeded[i].fragmentsize; + if (!pauseddownload && (fileneeded[i].type == FILENEEDED_WAD || i != 0)) // 0 is the gamestate... + { + // Don't remove the file, save it for later in case we resume the download + pauseddownload = malloc(sizeof(*pauseddownload)); + if (!pauseddownload) + I_Error("CloseNetFile: No more memory\n"); + + strcpy(pauseddownload->filename, fileneeded[i].filename); + memcpy(pauseddownload->md5sum, fileneeded[i].md5sum, 16); + pauseddownload->currentsize = fileneeded[i].currentsize; + pauseddownload->receivedfragments = fileneeded[i].receivedfragments; + pauseddownload->fragmentsize = fileneeded[i].fragmentsize; + } + else + { + // File is not complete, delete it. + free(fileneeded[i].receivedfragments); + remove(fileneeded[i].filename); + } } - else - { - free(fileneeded[i].receivedfragments); - // File is not complete delete it - remove(fileneeded[i].filename); - } - } + } + + FreeFileNeeded(); } void Command_Downloads_f(void) diff --git a/src/d_netfil.h b/src/d_netfil.h index 70b721bf7..3d713c150 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -27,6 +27,7 @@ typedef enum typedef enum { + FS_NOTCHECKED, FS_NOTFOUND, FS_FOUND, FS_REQUESTED, @@ -35,13 +36,21 @@ typedef enum FS_MD5SUMBAD } filestatus_t; +typedef enum +{ + FILENEEDED_WAD, + FILENEEDED_SAVEGAME, + FILENEEDED_LUAFILE +} fileneededtype_t; + typedef struct { - UINT8 willsend; // Is the server willing to send it? - UINT8 folder; // File is a folder char filename[MAX_WADPATH]; UINT8 md5sum[16]; filestatus_t status; // The value returned by recsearch + UINT8 willsend; // Is the server willing to send it? + UINT8 folder; // File is a folder + fileneededtype_t type; boolean justdownloaded; // To prevent late fragments from causing an I_Error // Used only for download @@ -58,19 +67,25 @@ typedef struct #define FILENEEDEDSIZE 23 extern INT32 fileneedednum; -extern fileneeded_t fileneeded[MAX_WADFILES]; +extern fileneeded_t *fileneeded; extern char downloaddir[512]; #ifndef NONET extern INT32 lastfilenum; +extern INT32 downloadcompletednum; +extern UINT32 downloadcompletedsize; +extern INT32 totalfilesrequestednum; +extern UINT32 totalfilesrequestedsize; #endif -UINT8 *PutFileNeeded(void); -void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr); +void AllocFileNeeded(INT32 size); +void FreeFileNeeded(void); +UINT8 *PutFileNeeded(UINT16 firstfile); +void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile); void CL_PrepareDownloadSaveGame(const char *tmpsave); INT32 CL_CheckFiles(void); -void CL_LoadServerFiles(void); +boolean CL_LoadServerFiles(void); void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid); diff --git a/src/doomdef.h b/src/doomdef.h index 37edca896..7e7e35599 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -152,6 +152,9 @@ extern char logfilename[1024]; // Comment or uncomment this as necessary. #define USE_PATCH_DTA +// Enforce a limit of loaded WAD files. +//#define ENFORCE_WAD_LIMIT + // Use .kart extension addons //#define USE_KART diff --git a/src/filesrch.c b/src/filesrch.c index b4039e526..ec095518e 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -338,9 +338,6 @@ size_t dir_on[menudepth]; UINT8 refreshdirmenu = 0; char *refreshdirname = NULL; -size_t packetsizetally = 0; -size_t mainwadstally = 0; - #define dirpathlen 1024 #define maxdirdepth 48 @@ -830,7 +827,7 @@ char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) pl #endif "\5.pk3", "\5.soc", "\5.lua"}; // addfile -char filenamebuf[MAX_WADFILES][MAX_WADPATH]; +static char (*filenamebuf)[MAX_WADPATH]; static boolean filemenucmp(char *haystack, char *needle) { @@ -1102,6 +1099,10 @@ boolean preparefilemenu(boolean samedepth) if (ext >= EXT_LOADSTART) { size_t i; + + if (filenamebuf == NULL) + filenamebuf = calloc(sizeof(char) * MAX_WADPATH, numwadfiles); + for (i = 0; i < numwadfiles; i++) { if (!filenamebuf[i][0]) @@ -1151,6 +1152,12 @@ boolean preparefilemenu(boolean samedepth) } } + if (filenamebuf) + { + free(filenamebuf); + filenamebuf = NULL; + } + closedir(dirhandle); if ((menudepthleft != menudepth-1) // now for UP... entry diff --git a/src/filesrch.h b/src/filesrch.h index 9d5f31bbb..59ef5269b 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -53,9 +53,6 @@ extern size_t dir_on[menudepth]; extern UINT8 refreshdirmenu; extern char *refreshdirname; -extern size_t packetsizetally; -extern size_t mainwadstally; - typedef enum { EXT_FOLDER = 0, diff --git a/src/m_menu.c b/src/m_menu.c index 7a82fd8fb..d5fa5e95b 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -3215,7 +3215,7 @@ boolean M_Responder(event_t *ev) if (gamestate == GS_TITLESCREEN && finalecount < TICRATE) return false; - if (CON_Ready()) + if (CON_Ready() && gamestate != GS_WAITINGPLAYERS) return false; if (noFurtherInput) @@ -6410,6 +6410,7 @@ static void M_Addons(INT32 choice) M_SetupNextMenu(&MISC_AddonsDef); } +#ifdef ENFORCE_WAD_LIMIT #define width 4 #define vpadding 27 #define h (BASEVIDHEIGHT-(2*vpadding)) @@ -6457,6 +6458,7 @@ static void M_DrawTemperature(INT32 x, fixed_t t) #undef vpadding #undef h #undef NUMCOLOURS +#endif static char *M_AddonsHeaderPath(void) { @@ -6550,21 +6552,20 @@ static void M_DrawAddons(void) V_DrawCenteredString(BASEVIDWIDTH/2, 5, 0, LOCATIONSTRING1); // (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1) +#ifdef ENFORCE_WAD_LIMIT if (numwadfiles <= mainwads+1) y = 0; else if (numwadfiles >= MAX_WADFILES) y = FRACUNIT; else { - x = FixedDiv(((ssize_t)(numwadfiles) - (ssize_t)(mainwads+1))< y) - y = x; + y = FixedDiv(((ssize_t)(numwadfiles) - (ssize_t)(mainwads+1))< FRACUNIT) // happens because of how we're shrinkin' it a little y = FRACUNIT; } M_DrawTemperature(BASEVIDWIDTH - 19 - 5, y); +#endif // DRAW MENU x = currentMenu->x; diff --git a/src/w_wad.c b/src/w_wad.c index 3ff301117..e49e0ce82 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -105,7 +105,7 @@ static UINT16 lumpnumcacheindex = 0; // GLOBALS //=========================================================================== UINT16 numwadfiles; // number of active wadfiles -wadfile_t *wadfiles[MAX_WADFILES]; // 0 to numwadfiles-1 are valid +wadfile_t **wadfiles; // 0 to numwadfiles-1 are valid // W_Shutdown // Closes all of the WAD files before quitting @@ -134,6 +134,8 @@ void W_Shutdown(void) Z_Free(wad->lumpinfo); Z_Free(wad); } + + Z_Free(wadfiles); } //=========================================================================== @@ -844,7 +846,6 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) #ifndef NOMD5 size_t i; #endif - size_t packetsize; UINT8 md5sum[16]; int important; @@ -862,9 +863,8 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) refreshdirname = NULL; //CONS_Debug(DBG_SETUP, "Loading %s\n", filename); - // - // check if limit of active wadfiles - // + + // Check if the game reached the limit of active wadfiles. if (numwadfiles >= MAX_WADFILES) { CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); @@ -884,24 +884,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) return INT16_MAX; } - // Check if wad files will overflow fileneededbuffer. Only the filename part - // is send in the packet; cf. - // see PutFileNeeded in d_netfil.c - if ((important = !important)) - { - packetsize = packetsizetally + nameonlylength(filename) + FILENEEDEDSIZE; - - if (packetsize > MAXFILENEEDED*sizeof(UINT8)) - { - CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); - refreshdirmenu |= REFRESHDIR_MAX; - if (handle) - fclose(handle); - return W_InitFileError(filename, startup); - } - - packetsizetally = packetsize; - } + important = !important; #ifndef NOMD5 // @@ -913,11 +896,12 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) for (i = 0; i < numwadfiles; i++) { + if (wadfiles[i]->type == RET_FOLDER) + continue; + if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) { CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename); - if (important) - packetsizetally -= nameonlylength(filename) + FILENEEDEDSIZE; if (handle) fclose(handle); return W_InitFileError(filename, false); @@ -984,6 +968,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) // add the wadfile // CONS_Printf(M_GetText("Added file %s (%u lumps)\n"), filename, numlumps); + wadfiles = Z_Realloc(wadfiles, sizeof(wadfile_t) * (numwadfiles + 1), PU_STATIC, NULL); wadfiles[numwadfiles] = wadfile; numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded @@ -1046,22 +1031,7 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup) return W_InitFileError(path, startup); } - important = 0; // ??? - - /// \todo Implement a W_VerifyFolder. - if ((important = !important)) - { - size_t packetsize = packetsizetally + strlen(path) + FILENEEDEDSIZE; - - if (packetsize > MAXFILENEEDED*sizeof(UINT8)) - { - CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); - refreshdirmenu |= REFRESHDIR_MAX; - return W_InitFileError(path, startup); - } - - packetsizetally = packetsize; - } + important = 0; /// \todo Implement a W_VerifyFolder. // Remove path delimiters. p = path + (strlen(path) - 1); @@ -1132,8 +1102,6 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup) if (samepaths(wadfiles[i]->path, fullpath) > 0) { CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), path); - if (important) - packetsizetally -= strlen(path) + FILENEEDEDSIZE; Z_Free(fn); Z_Free(fullpath); return W_InitFileError(path, false); @@ -1197,11 +1165,13 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup) * * \param filenames A null-terminated list of files to use. */ -void W_InitMultipleFiles(char **filenames) +void W_InitMultipleFiles(addfilelist_t *list) { - for (; *filenames; filenames++) + size_t i = 0; + + for (; i < list->numfiles; i++) { - const char *fn = (*filenames); + const char *fn = list->files[i]; char pathsep = fn[strlen(fn) - 1]; boolean mainfile = (numwadfiles < mainwads); @@ -1219,7 +1189,7 @@ void W_InitMultipleFiles(char **filenames) */ static boolean TestValidLump(UINT16 wad, UINT16 lump) { - I_Assert(wad < MAX_WADFILES); + I_Assert(wad < numwadfiles); if (!wadfiles[wad]) // make sure the wad file exists return false; @@ -1636,7 +1606,7 @@ size_t W_LumpLength(lumpnum_t lumpnum) // // W_IsLumpWad -// Is the lump a WAD? (presumably in a PK3) +// Is the lump a WAD? (presumably not in a WAD) // boolean W_IsLumpWad(lumpnum_t lumpnum) { @@ -1649,12 +1619,12 @@ boolean W_IsLumpWad(lumpnum_t lumpnum) return !strnicmp(lumpfullName + strlen(lumpfullName) - 4, ".wad", 4); } - return false; // WADs should never be inside non-PK3s as far as SRB2 is concerned + return false; // WADs should never be inside WADs as far as SRB2 is concerned } // // W_IsLumpFolder -// Is the lump a folder? (in a PK3 obviously) +// Is the lump a folder? (not in a WAD obviously) // boolean W_IsLumpFolder(UINT16 wad, UINT16 lump) { @@ -1665,7 +1635,7 @@ boolean W_IsLumpFolder(UINT16 wad, UINT16 lump) return (name[strlen(name)-1] == '/'); // folders end in '/' } - return false; // non-PK3s don't have folders + return false; // WADs don't have folders } #ifdef HAVE_ZLIB @@ -2217,7 +2187,7 @@ void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5) #else I_Error #endif - (M_GetText("File is old, is corrupt or has been modified: %s (found md5: %s, wanted: %s)\n"), wadfiles[wadfilenum]->filename, actualmd5text, matchmd5); + (M_GetText("File is old, is corrupt or has been modified:\n%s\nFound MD5: %s\nWanted MD5: %s\n"), wadfiles[wadfilenum]->filename, actualmd5text, matchmd5); } #endif } diff --git a/src/w_wad.h b/src/w_wad.h index 949bab9fe..a41ba1724 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -97,9 +97,15 @@ virtlump_t* vres_Find(const virtres_t*, const char*); // DYNAMIC WAD LOADING // ========================================================================= +// Maximum of files that can be loaded +// (there is a max of simultaneous open files anyway) +#ifdef ENFORCE_WAD_LIMIT +#define MAX_WADFILES 2048 // This cannot be any higher than UINT16_MAX. +#else +#define MAX_WADFILES UINT16_MAX +#endif + #define MAX_WADPATH 512 -#define MAX_WADFILES 48 // maximum of wad files used at the same time -// (there is a max of simultaneous open files anyway, and this should be plenty) #define lumpcache_t void * @@ -134,7 +140,13 @@ typedef struct wadfile_s #define LUMPNUM(lumpnum) (UINT16)((lumpnum)&0xFFFF) // lump number for this pwad extern UINT16 numwadfiles; -extern wadfile_t *wadfiles[MAX_WADFILES]; +extern wadfile_t **wadfiles; + +typedef struct +{ + char **files; + size_t numfiles; +} addfilelist_t; // ========================================================================= @@ -148,7 +160,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup); UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup); // W_InitMultipleFiles exits if a file was not found, but not if all is okay. -void W_InitMultipleFiles(char **filenames); +void W_InitMultipleFiles(addfilelist_t *list); #define W_FileHasFolders(wadfile) ((wadfile)->type == RET_PK3 || (wadfile)->type == RET_FOLDER)