diff --git a/debian-template/rules b/debian-template/rules index 0a77624cb..12ceaf98b 100644 --- a/debian-template/rules +++ b/debian-template/rules @@ -78,7 +78,7 @@ NONX86 = $(shell test "`echo $(CROSS_COMPILE_HOST) | grep 'i[3-6]86'`" || echo " MAKEARGS = $(OS) $(NONX86) $(PREFIX) EXENAME=$(EXENAME) DBGNAME=$(DBGNAME) NOOBJDUMP=1 # SDL_PKGCONFIG=sdl2 PNG_PKGCONFIG=libpng MENUFILE1 = ?package($(PACKAGE)):needs="X11" section="$(SECTION)" MENUFILE2 = title="$(TITLE)" command="/$(PKGDIR)/$(PACKAGE)" -BINDIR := $(DIR)/bin/Linux/Release +BINDIR := $(DIR)/bin/ # FIXME pkg-config dir hacks # Launchpad doesn't need this; it actually makes i386 builds fail due to cross-compile diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg index 33072643e..0d5b7ab92 100644 --- a/extras/conf/SRB2-22.cfg +++ b/extras/conf/SRB2-22.cfg @@ -776,7 +776,6 @@ linedeftypes { title = "Make FOF Bouncy"; prefix = "(76)"; - flags16384text = "[14] Dampen"; } } @@ -1999,7 +1998,7 @@ linedeftypes title = "Set Tagged Sector's Floor Height/Texture"; prefix = "(400)"; flags8text = "[3] Set delay by backside sector"; - flags64text = "[6] Keep floor flat"; + flags64text = "[6] Don't change floor texture"; } 401 @@ -2007,7 +2006,7 @@ linedeftypes title = "Set Tagged Sector's Ceiling Height/Texture"; prefix = "(401)"; flags8text = "[3] Set delay by backside sector"; - flags64text = "[6] Keep floor flat"; + flags64text = "[6] Don't change ceiling texture"; } 402 @@ -2118,7 +2117,7 @@ linedeftypes prefix = "(403)"; flags2text = "[1] Trigger linedef executor"; flags8text = "[3] Set delay by backside sector"; - flags64text = "[6] Change floor flat"; + flags64text = "[6] Change floor texture"; } 404 @@ -2127,7 +2126,7 @@ linedeftypes prefix = "(404)"; flags2text = "[1] Trigger linedef executor"; flags8text = "[3] Set delay by backside sector"; - flags64text = "[6] Change ceiling flat"; + flags64text = "[6] Change ceiling texture"; } 405 diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg index 674d20443..776e9ba2d 100644 --- a/extras/conf/udb/Includes/SRB222_linedefs.cfg +++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg @@ -1994,12 +1994,6 @@ udmf { title = "Bounce strength"; } - arg2 - { - title = "Dampen?"; - type = 11; - enum = "noyes"; - } } } diff --git a/src/Makefile.d/versions.mk b/src/Makefile.d/versions.mk index d7d0c3dd1..f0b59658e 100644 --- a/src/Makefile.d/versions.mk +++ b/src/Makefile.d/versions.mk @@ -35,8 +35,6 @@ ifndef GCC295 WFLAGS+=-Wendif-labels endif ifdef GCC41 - WFLAGS+=-Wdeclaration-after-statement - WFLAGS+=-Wno-error=declaration-after-statement WFLAGS+=-Wshadow endif #WFLAGS+=-Wlarger-than-%len% diff --git a/src/Makefile.d/win32.mk b/src/Makefile.d/win32.mk index 0c671b268..768133c15 100644 --- a/src/Makefile.d/win32.mk +++ b/src/Makefile.d/win32.mk @@ -8,6 +8,11 @@ else EXENAME?=srb2win64.exe endif +# disable dynamicbase if under msys2 +ifdef MSYSTEM +libs+=-Wl,--disable-dynamicbase +endif + sources+=win32/Srb2win.rc opts+=-DSTDC_HEADERS libs+=-ladvapi32 -lkernel32 -lmsvcrt -luser32 diff --git a/src/console.c b/src/console.c index f01e1824c..6f21aeb3d 100644 --- a/src/console.c +++ b/src/console.c @@ -484,6 +484,19 @@ void CON_Init(void) Unlock_state(); } } + +void CON_StartRefresh(void) +{ + if (con_startup) + con_refresh = true; +} + +void CON_StopRefresh(void) +{ + if (con_startup) + con_refresh = false; +} + // Console input initialization // static void CON_InputInit(void) diff --git a/src/console.h b/src/console.h index 28f40d308..accf89d96 100644 --- a/src/console.h +++ b/src/console.h @@ -16,6 +16,9 @@ void CON_Init(void); +void CON_StartRefresh(void); +void CON_StopRefresh(void); + boolean CON_Responder(event_t *ev); #ifdef HAVE_THREADS diff --git a/src/d_clisrv.c b/src/d_clisrv.c index b7071320c..78a3ebe6c 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); @@ -1838,12 +1925,162 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room) #endif // ifndef NONET -static const char * InvalidServerReason (INT32 i) +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) { @@ -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 } @@ -2932,6 +3195,34 @@ static void Command_Kick(void) else CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); } + +static void Command_ResendGamestate(void) +{ + SINT8 playernum; + + if (COM_Argc() == 1) + { + CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); + return; + } + else if (client) + { + CONS_Printf(M_GetText("Only the server can use this.\n")); + return; + } + + playernum = nametonum(COM_Argv(1)); + if (playernum == -1 || playernum == 0) + return; + + // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + if (!HSendPacket(playernode[playernum], true, 0, 0)) + { + CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n")); + return; + } +} #endif static void Got_KickCmd(UINT8 **p, INT32 playernum) @@ -3139,34 +3430,6 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) CL_RemovePlayer(pnum, kickreason); } -static void Command_ResendGamestate(void) -{ - SINT8 playernum; - - if (COM_Argc() == 1) - { - CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); - return; - } - else if (client) - { - CONS_Printf(M_GetText("Only the server can use this.\n")); - return; - } - - playernum = nametonum(COM_Argv(1)); - if (playernum == -1 || playernum == 0) - return; - - // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on - netbuffer->packettype = PT_WILLRESENDGAMESTATE; - if (!HSendPacket(playernode[playernum], true, 0, 0)) - { - CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n")); - return; - } -} - static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); @@ -3189,7 +3452,7 @@ consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE|CV_NETVAR, maxsend_ consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); // Speed of file downloading (in packets per tic) -static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t downloadspeed_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}}; consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE|CV_NETVAR, downloadspeed_cons_t, NULL); static void Got_AddPlayer(UINT8 **p, INT32 playernum); @@ -3903,6 +4166,7 @@ static void HandleServerInfo(SINT8 node) static void PT_WillResendGamestate(void) { +#ifndef NONET char tmpsave[256]; if (server || cl_redownloadinggamestate) @@ -3925,10 +4189,12 @@ static void PT_WillResendGamestate(void) CL_PrepareDownloadSaveGame(tmpsave); cl_redownloadinggamestate = true; +#endif } static void PT_CanReceiveGamestate(SINT8 node) { +#ifndef NONET if (client || sendingsavegame[node]) return; @@ -3936,6 +4202,9 @@ static void PT_CanReceiveGamestate(SINT8 node) SV_SendSaveGame(node, true); // Resend a complete game state resendingsavegame[node] = true; +#else + (void)node; +#endif } /** Handles a packet received from a node that isn't in game @@ -3962,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: @@ -4012,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. @@ -4222,8 +4511,10 @@ static void HandlePacketFromPlayer(SINT8 node) // Check player consistancy during the level if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) - && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime() - && !SV_ResendingSavegameToAnyone()) +#ifndef NONET + && !SV_ResendingSavegameToAnyone() +#endif + && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime()) { if (cv_resynchattempts.value) { @@ -4974,16 +5265,23 @@ void TryRunTics(tic_t realtics) // run the count * tics while (neededtic > gametic) { + boolean update_stats = !(paused || P_AutoPause()); + DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic)); - ps_tictime = I_GetPreciseTime(); + if (update_stats) + PS_START_TIMING(ps_tictime); G_Ticker((gametic % NEWTICRATERATIO) == 0); ExtraDataTicker(); gametic++; consistancy[gametic%BACKUPTICS] = Consistancy(); - ps_tictime = I_GetPreciseTime() - ps_tictime; + if (update_stats) + { + PS_STOP_TIMING(ps_tictime); + PS_UpdateTickStats(); + } // Leave a certain amount of tics present in the net buffer as long as we've ran at least one tic this frame. if (client && gamestate == GS_LEVEL && leveltime > 3 && neededtic <= gametic + cv_netticbuffer.value) @@ -5127,9 +5425,11 @@ void NetUpdate(void) if (client) { +#ifndef NONET // If the client just finished redownloading the game state, load it if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND) CL_ReloadReceivedSavegame(); +#endif CL_SendClientCmd(); // Send tic cmd hu_redownloadinggamestate = cl_redownloadinggamestate; 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 b4b668f4b..83419d266 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; @@ -272,7 +272,7 @@ void D_ProcessEvents(void) if (eaten) continue; // ate the event - if (!hooked && G_LuaResponder(ev)) + if (!hooked && !CON_Ready() && G_LuaResponder(ev)) continue; G_Responder(ev); @@ -476,7 +476,7 @@ static void D_Display(void) if (!automapactive && !dedicated && cv_renderview.value) { - ps_rendercalltime = I_GetPreciseTime(); + PS_START_TIMING(ps_rendercalltime); if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) { topleft = screens[0] + viewwindowy*vid.width + viewwindowx; @@ -523,7 +523,7 @@ static void D_Display(void) if (postimgtype2) V_DoPostProcessor(1, postimgtype2, postimgparam2); } - ps_rendercalltime = I_GetPreciseTime() - ps_rendercalltime; + PS_STOP_TIMING(ps_rendercalltime); } if (lastdraw) @@ -537,7 +537,7 @@ static void D_Display(void) lastdraw = false; } - ps_uitime = I_GetPreciseTime(); + PS_START_TIMING(ps_uitime); if (gamestate == GS_LEVEL) { @@ -550,7 +550,7 @@ static void D_Display(void) } else { - ps_uitime = I_GetPreciseTime(); + PS_START_TIMING(ps_uitime); } } @@ -592,7 +592,7 @@ static void D_Display(void) CON_Drawer(); - ps_uitime = I_GetPreciseTime() - ps_uitime; + PS_STOP_TIMING(ps_uitime); // // wipe update @@ -678,9 +678,9 @@ static void D_Display(void) M_DrawPerfStats(); } - ps_swaptime = I_GetPreciseTime(); + PS_START_TIMING(ps_swaptime); I_FinishUpdate(); // page flip or blit buffer - ps_swaptime = I_GetPreciseTime() - ps_swaptime; + PS_STOP_TIMING(ps_swaptime); } } @@ -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 @@ -1358,9 +1373,16 @@ void D_SRB2Main(void) I_RegisterSysCommands(); - CONS_Printf("W_InitMultipleFiles(): Adding extra PWADs.\n"); - W_InitMultipleFiles(startuppwads); - D_CleanFile(startuppwads); + CON_StopRefresh(); // Temporarily stop refreshing the screen for wad loading + + if (startuppwads.numfiles) + { + CONS_Printf("W_InitMultipleFiles(): Adding extra PWADs.\n"); + W_InitMultipleFiles(&startuppwads); + D_CleanFile(&startuppwads); + } + + CON_StartRefresh(); // Restart the refresh! CONS_Printf("HU_LoadGraphics()...\n"); HU_LoadGraphics(); 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..cca3102d0 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -47,6 +47,7 @@ #include "m_cond.h" #include "m_anigif.h" #include "md5.h" +#include "m_perfstats.h" #ifdef NETGAME_DEVMODE #define CV_RESTRICT CV_NETVAR @@ -374,7 +375,14 @@ consvar_t cv_sleep = CVAR_INIT ("cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL) static CV_PossibleValue_t perfstats_cons_t[] = { {0, "Off"}, {1, "Rendering"}, {2, "Logic"}, {3, "ThinkFrame"}, {0, NULL}}; -consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", 0, perfstats_cons_t, NULL); +consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", CV_CALL, perfstats_cons_t, PS_PerfStats_OnChange); +static CV_PossibleValue_t ps_samplesize_cons_t[] = { + {1, "MIN"}, {1000, "MAX"}, {0, NULL}}; +consvar_t cv_ps_samplesize = CVAR_INIT ("ps_samplesize", "1", CV_CALL, ps_samplesize_cons_t, PS_SampleSize_OnChange); +static CV_PossibleValue_t ps_descriptor_cons_t[] = { + {1, "Average"}, {2, "SD"}, {3, "Minimum"}, {4, "Maximum"}, {0, NULL}}; +consvar_t cv_ps_descriptor = CVAR_INIT ("ps_descriptor", "Average", 0, ps_descriptor_cons_t, NULL); + consvar_t cv_freedemocamera = CVAR_INIT("freedemocamera", "Off", CV_SAVE, CV_OnOff, NULL); char timedemo_name[256]; @@ -867,6 +875,8 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_soundtest); CV_RegisterVar(&cv_perfstats); + CV_RegisterVar(&cv_ps_samplesize); + CV_RegisterVar(&cv_ps_descriptor); // ingame object placing COM_AddCommand("objectplace", Command_ObjectPlace_f); @@ -3223,7 +3233,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 +3357,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 +3388,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 +3481,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 +3545,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 +3570,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 +3603,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 +3628,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 +3659,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 +3707,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 +3751,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..7bb7eab03 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; @@ -110,6 +111,8 @@ extern consvar_t cv_skipmapcheck; extern consvar_t cv_sleep; extern consvar_t cv_perfstats; +extern consvar_t cv_ps_samplesize; +extern consvar_t cv_ps_descriptor; extern char timedemo_name[256]; extern boolean timedemo_csv; diff --git a/src/d_netfil.c b/src/d_netfil.c index 12c5ee6a2..fdc0026a8 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 @@ -925,7 +980,6 @@ static void SV_EndFileSend(INT32 node) filestosend--; } -#define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH) #define FILEFRAGMENTSIZE (software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE)) /** Handles file transmission @@ -958,14 +1012,7 @@ void FileSendTicker(void) if (!filestosend) // No file to send return; - if (cv_downloadspeed.value) // New behavior - packetsent = cv_downloadspeed.value; - else // Old behavior - { - packetsent = PACKETPERTIC; - if (!packetsent) - packetsent = 1; - } + packetsent = cv_downloadspeed.value; netbuffer->packettype = PT_FILEFRAGMENT; @@ -1242,6 +1289,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 +1403,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 +1474,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/deh_tables.c b/src/deh_tables.c index f2fd38059..47256727a 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5226,6 +5226,7 @@ struct int_const_s const INT_CONST[] = { {"FF_CRUMBLE",FF_CRUMBLE}, ///< Falls 2 seconds after being stepped on, and randomly brings all touching crumbling 3dfloors down with it, providing their master sectors share the same tag (allows crumble platforms above or below, to also exist). {"FF_GOOWATER",FF_GOOWATER}, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop. {"FF_MARIO",FF_MARIO}, ///< Acts like a question block when hit from underneath. Goodie spawned at top is determined by master sector. + {"FF_BUSTUP",FF_BUSTUP}, ///< You can spin through/punch this block and it will crumble! {"FF_QUICKSAND",FF_QUICKSAND}, ///< Quicksand! {"FF_PLATFORM",FF_PLATFORM}, ///< You can jump up through this to the top. {"FF_REVERSEPLATFORM",FF_REVERSEPLATFORM}, ///< A fall-through floor in normal gravity, a platform in reverse gravity. @@ -5236,12 +5237,10 @@ struct int_const_s const INT_CONST[] = { {"FF_BOUNCY",FF_BOUNCY}, ///< Bounces players {"FF_SPLAT",FF_SPLAT}, ///< Use splat flat renderer (treat cyan pixels as invisible) - // FOF special flags - {"FS_PUSHABLES",FS_PUSHABLES}, - {"FS_EXECUTOR",FS_EXECUTOR}, - {"FS_ONLYBOTTOM",FS_ONLYBOTTOM}, - {"FS_BUSTMASK",FS_BUSTMASK}, - {"FS_DAMPEN",FS_DAMPEN}, + // FOF bustable flags + {"FB_PUSHABLES",FB_PUSHABLES}, + {"FB_EXECUTOR",FB_EXECUTOR}, + {"FB_ONLYBOTTOM",FB_ONLYBOTTOM}, // Bustable FOF type {"BT_TOUCH",BT_TOUCH}, 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/f_finale.c b/src/f_finale.c index aecf79fc2..8dd03d44f 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1091,11 +1091,11 @@ static const char *credits[] = { "Kepa \"Nev3r\" Iceta", "Thomas \"Shadow Hog\" Igoe", "Iestyn \"Monster Iestyn\" Jealous", - "\"Jimita\"", "\"Kaito Sinclaire\"", "\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog "Ronald \"Furyhunter\" Kinard", // The SDL2 port "\"Lat'\"", // SRB2-CHAT, the chat window from Kart + "\"LZA\"", "Matthew \"Shuffle\" Marsalko", "Steven \"StroggOnMeth\" McGranahan", "\"Morph\"", // For SRB2Morphed stuff @@ -1167,8 +1167,8 @@ static const char *credits[] = { "Alexander \"DrTapeworm\" Moench-Ford", "Stefan \"Stuf\" Rimalia", "Shane Mychal Sexton", - "David \"Big Wave Dave\" Spencer Sr.", - "David \"Instant Sonic\" Spencer Jr.", + "Dave \"Big Wave Dave\" Spencer", + "David \"instantSonic\" Spencer", "\"SSNTails\"", "", "\1Level Design", @@ -1219,7 +1219,7 @@ static const char *credits[] = { "Bill \"Tets\" Reed", "", "\1Special Thanks", - "iD Software", + "id Software", "Doom Legacy Project", "FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak "Kart Krew", 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/g_demo.c b/src/g_demo.c index 211239bfe..c97dbcf9e 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2433,12 +2433,13 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill) { WRITEUINT8(demo_p, (kill) ? METALDEATH : DEMOMARKER); // add the demo end (or metal death) marker WriteDemoChecksum(); - saved = FIL_WriteFile(va("%sMS.LMP", G_BuildMapName(gamemap)), demobuffer, demo_p - demobuffer); // finally output the file. + sprintf(demoname, "%sMS.LMP", G_BuildMapName(gamemap)); + saved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file. } free(demobuffer); metalrecording = false; if (saved) - I_Error("Saved to %sMS.LMP", G_BuildMapName(gamemap)); + I_Error("Saved to %s", demoname); I_Error("Failed to save demo!"); } diff --git a/src/g_game.c b/src/g_game.c index de1a774f4..ce2aa41f5 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1549,8 +1549,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) // Note: Majority of botstuffs are handled in G_Ticker now. if (player->bot == BOT_2PHUMAN) //Player-controlled bot { - G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); // empty, or external driver - // Fix offset angle for P2-controlled Tailsbot when P2's controls are set to non-Legacy + // Fix offset angle for P2-controlled Tailsbot when P2's controls are set to non-Strafe cmd->angleturn = (INT16)((localangle - *myangle) >> 16); } diff --git a/src/g_input.c b/src/g_input.c index cd4536bba..6383c3f00 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -233,323 +233,323 @@ typedef struct static keyname_t keynames[] = { - {KEY_SPACE, "SPACE"}, - {KEY_CAPSLOCK, "CAPS LOCK"}, - {KEY_ENTER, "ENTER"}, - {KEY_TAB, "TAB"}, - {KEY_ESCAPE, "ESCAPE"}, - {KEY_BACKSPACE, "BACKSPACE"}, + {KEY_SPACE, "space"}, + {KEY_CAPSLOCK, "caps lock"}, + {KEY_ENTER, "enter"}, + {KEY_TAB, "tab"}, + {KEY_ESCAPE, "escape"}, + {KEY_BACKSPACE, "backspace"}, - {KEY_NUMLOCK, "NUMLOCK"}, - {KEY_SCROLLLOCK, "SCROLLLOCK"}, + {KEY_NUMLOCK, "numlock"}, + {KEY_SCROLLLOCK, "scrolllock"}, // bill gates keys - {KEY_LEFTWIN, "LEFTWIN"}, - {KEY_RIGHTWIN, "RIGHTWIN"}, - {KEY_MENU, "MENU"}, + {KEY_LEFTWIN, "leftwin"}, + {KEY_RIGHTWIN, "rightwin"}, + {KEY_MENU, "menu"}, - {KEY_LSHIFT, "LSHIFT"}, - {KEY_RSHIFT, "RSHIFT"}, - {KEY_LSHIFT, "SHIFT"}, - {KEY_LCTRL, "LCTRL"}, - {KEY_RCTRL, "RCTRL"}, - {KEY_LCTRL, "CTRL"}, - {KEY_LALT, "LALT"}, - {KEY_RALT, "RALT"}, - {KEY_LALT, "ALT"}, + {KEY_LSHIFT, "lshift"}, + {KEY_RSHIFT, "rshift"}, + {KEY_LSHIFT, "shift"}, + {KEY_LCTRL, "lctrl"}, + {KEY_RCTRL, "rctrl"}, + {KEY_LCTRL, "ctrl"}, + {KEY_LALT, "lalt"}, + {KEY_RALT, "ralt"}, + {KEY_LALT, "alt"}, // keypad keys - {KEY_KPADSLASH, "KEYPAD /"}, - {KEY_KEYPAD7, "KEYPAD 7"}, - {KEY_KEYPAD8, "KEYPAD 8"}, - {KEY_KEYPAD9, "KEYPAD 9"}, - {KEY_MINUSPAD, "KEYPAD -"}, - {KEY_KEYPAD4, "KEYPAD 4"}, - {KEY_KEYPAD5, "KEYPAD 5"}, - {KEY_KEYPAD6, "KEYPAD 6"}, - {KEY_PLUSPAD, "KEYPAD +"}, - {KEY_KEYPAD1, "KEYPAD 1"}, - {KEY_KEYPAD2, "KEYPAD 2"}, - {KEY_KEYPAD3, "KEYPAD 3"}, - {KEY_KEYPAD0, "KEYPAD 0"}, - {KEY_KPADDEL, "KEYPAD ."}, + {KEY_KPADSLASH, "keypad /"}, + {KEY_KEYPAD7, "keypad 7"}, + {KEY_KEYPAD8, "keypad 8"}, + {KEY_KEYPAD9, "keypad 9"}, + {KEY_MINUSPAD, "keypad -"}, + {KEY_KEYPAD4, "keypad 4"}, + {KEY_KEYPAD5, "keypad 5"}, + {KEY_KEYPAD6, "keypad 6"}, + {KEY_PLUSPAD, "keypad +"}, + {KEY_KEYPAD1, "keypad 1"}, + {KEY_KEYPAD2, "keypad 2"}, + {KEY_KEYPAD3, "keypad 3"}, + {KEY_KEYPAD0, "keypad 0"}, + {KEY_KPADDEL, "keypad ."}, // extended keys (not keypad) - {KEY_HOME, "HOME"}, - {KEY_UPARROW, "UP ARROW"}, - {KEY_PGUP, "PGUP"}, - {KEY_LEFTARROW, "LEFT ARROW"}, - {KEY_RIGHTARROW, "RIGHT ARROW"}, - {KEY_END, "END"}, - {KEY_DOWNARROW, "DOWN ARROW"}, - {KEY_PGDN, "PGDN"}, - {KEY_INS, "INS"}, - {KEY_DEL, "DEL"}, + {KEY_HOME, "home"}, + {KEY_UPARROW, "up arrow"}, + {KEY_PGUP, "pgup"}, + {KEY_LEFTARROW, "left arrow"}, + {KEY_RIGHTARROW, "right arrow"}, + {KEY_END, "end"}, + {KEY_DOWNARROW, "down arrow"}, + {KEY_PGDN, "pgdn"}, + {KEY_INS, "ins"}, + {KEY_DEL, "del"}, // other keys - {KEY_F1, "F1"}, - {KEY_F2, "F2"}, - {KEY_F3, "F3"}, - {KEY_F4, "F4"}, - {KEY_F5, "F5"}, - {KEY_F6, "F6"}, - {KEY_F7, "F7"}, - {KEY_F8, "F8"}, - {KEY_F9, "F9"}, - {KEY_F10, "F10"}, - {KEY_F11, "F11"}, - {KEY_F12, "F12"}, + {KEY_F1, "f1"}, + {KEY_F2, "f2"}, + {KEY_F3, "f3"}, + {KEY_F4, "f4"}, + {KEY_F5, "f5"}, + {KEY_F6, "f6"}, + {KEY_F7, "f7"}, + {KEY_F8, "f8"}, + {KEY_F9, "f9"}, + {KEY_F10, "f10"}, + {KEY_F11, "f11"}, + {KEY_F12, "f12"}, // KEY_CONSOLE has an exception in the keyname code {'`', "TILDE"}, - {KEY_PAUSE, "PAUSE/BREAK"}, + {KEY_PAUSE, "pause/break"}, // virtual keys for mouse buttons and joystick buttons - {KEY_MOUSE1+0,"MOUSE1"}, - {KEY_MOUSE1+1,"MOUSE2"}, - {KEY_MOUSE1+2,"MOUSE3"}, - {KEY_MOUSE1+3,"MOUSE4"}, - {KEY_MOUSE1+4,"MOUSE5"}, - {KEY_MOUSE1+5,"MOUSE6"}, - {KEY_MOUSE1+6,"MOUSE7"}, - {KEY_MOUSE1+7,"MOUSE8"}, - {KEY_2MOUSE1+0,"SEC_MOUSE2"}, // BP: sorry my mouse handler swap button 1 and 2 - {KEY_2MOUSE1+1,"SEC_MOUSE1"}, - {KEY_2MOUSE1+2,"SEC_MOUSE3"}, - {KEY_2MOUSE1+3,"SEC_MOUSE4"}, - {KEY_2MOUSE1+4,"SEC_MOUSE5"}, - {KEY_2MOUSE1+5,"SEC_MOUSE6"}, - {KEY_2MOUSE1+6,"SEC_MOUSE7"}, - {KEY_2MOUSE1+7,"SEC_MOUSE8"}, - {KEY_MOUSEWHEELUP, "Wheel 1 UP"}, - {KEY_MOUSEWHEELDOWN, "Wheel 1 Down"}, - {KEY_2MOUSEWHEELUP, "Wheel 2 UP"}, - {KEY_2MOUSEWHEELDOWN, "Wheel 2 Down"}, + {KEY_MOUSE1+0,"mouse1"}, + {KEY_MOUSE1+1,"mouse2"}, + {KEY_MOUSE1+2,"mouse3"}, + {KEY_MOUSE1+3,"mouse4"}, + {KEY_MOUSE1+4,"mouse5"}, + {KEY_MOUSE1+5,"mouse6"}, + {KEY_MOUSE1+6,"mouse7"}, + {KEY_MOUSE1+7,"mouse8"}, + {KEY_2MOUSE1+0,"sec_mouse2"}, // BP: sorry my mouse handler swap button 1 and 2 + {KEY_2MOUSE1+1,"sec_mouse1"}, + {KEY_2MOUSE1+2,"sec_mouse3"}, + {KEY_2MOUSE1+3,"sec_mouse4"}, + {KEY_2MOUSE1+4,"sec_mouse5"}, + {KEY_2MOUSE1+5,"sec_mouse6"}, + {KEY_2MOUSE1+6,"sec_mouse7"}, + {KEY_2MOUSE1+7,"sec_mouse8"}, + {KEY_MOUSEWHEELUP, "wheel 1 up"}, + {KEY_MOUSEWHEELDOWN, "wheel 1 down"}, + {KEY_2MOUSEWHEELUP, "wheel 2 up"}, + {KEY_2MOUSEWHEELDOWN, "wheel 2 down"}, - {KEY_JOY1+0, "JOY1"}, - {KEY_JOY1+1, "JOY2"}, - {KEY_JOY1+2, "JOY3"}, - {KEY_JOY1+3, "JOY4"}, - {KEY_JOY1+4, "JOY5"}, - {KEY_JOY1+5, "JOY6"}, - {KEY_JOY1+6, "JOY7"}, - {KEY_JOY1+7, "JOY8"}, - {KEY_JOY1+8, "JOY9"}, + {KEY_JOY1+0, "joy1"}, + {KEY_JOY1+1, "joy2"}, + {KEY_JOY1+2, "joy3"}, + {KEY_JOY1+3, "joy4"}, + {KEY_JOY1+4, "joy5"}, + {KEY_JOY1+5, "joy6"}, + {KEY_JOY1+6, "joy7"}, + {KEY_JOY1+7, "joy8"}, + {KEY_JOY1+8, "joy9"}, #if !defined (NOMOREJOYBTN_1S) // we use up to 32 buttons in DirectInput - {KEY_JOY1+9, "JOY10"}, - {KEY_JOY1+10, "JOY11"}, - {KEY_JOY1+11, "JOY12"}, - {KEY_JOY1+12, "JOY13"}, - {KEY_JOY1+13, "JOY14"}, - {KEY_JOY1+14, "JOY15"}, - {KEY_JOY1+15, "JOY16"}, - {KEY_JOY1+16, "JOY17"}, - {KEY_JOY1+17, "JOY18"}, - {KEY_JOY1+18, "JOY19"}, - {KEY_JOY1+19, "JOY20"}, - {KEY_JOY1+20, "JOY21"}, - {KEY_JOY1+21, "JOY22"}, - {KEY_JOY1+22, "JOY23"}, - {KEY_JOY1+23, "JOY24"}, - {KEY_JOY1+24, "JOY25"}, - {KEY_JOY1+25, "JOY26"}, - {KEY_JOY1+26, "JOY27"}, - {KEY_JOY1+27, "JOY28"}, - {KEY_JOY1+28, "JOY29"}, - {KEY_JOY1+29, "JOY30"}, - {KEY_JOY1+30, "JOY31"}, - {KEY_JOY1+31, "JOY32"}, + {KEY_JOY1+9, "joy10"}, + {KEY_JOY1+10, "joy11"}, + {KEY_JOY1+11, "joy12"}, + {KEY_JOY1+12, "joy13"}, + {KEY_JOY1+13, "joy14"}, + {KEY_JOY1+14, "joy15"}, + {KEY_JOY1+15, "joy16"}, + {KEY_JOY1+16, "joy17"}, + {KEY_JOY1+17, "joy18"}, + {KEY_JOY1+18, "joy19"}, + {KEY_JOY1+19, "joy20"}, + {KEY_JOY1+20, "joy21"}, + {KEY_JOY1+21, "joy22"}, + {KEY_JOY1+22, "joy23"}, + {KEY_JOY1+23, "joy24"}, + {KEY_JOY1+24, "joy25"}, + {KEY_JOY1+25, "joy26"}, + {KEY_JOY1+26, "joy27"}, + {KEY_JOY1+27, "joy28"}, + {KEY_JOY1+28, "joy29"}, + {KEY_JOY1+29, "joy30"}, + {KEY_JOY1+30, "joy31"}, + {KEY_JOY1+31, "joy32"}, #endif // the DOS version uses Allegro's joystick support - {KEY_HAT1+0, "HATUP"}, - {KEY_HAT1+1, "HATDOWN"}, - {KEY_HAT1+2, "HATLEFT"}, - {KEY_HAT1+3, "HATRIGHT"}, - {KEY_HAT1+4, "HATUP2"}, - {KEY_HAT1+5, "HATDOWN2"}, - {KEY_HAT1+6, "HATLEFT2"}, - {KEY_HAT1+7, "HATRIGHT2"}, - {KEY_HAT1+8, "HATUP3"}, - {KEY_HAT1+9, "HATDOWN3"}, - {KEY_HAT1+10, "HATLEFT3"}, - {KEY_HAT1+11, "HATRIGHT3"}, - {KEY_HAT1+12, "HATUP4"}, - {KEY_HAT1+13, "HATDOWN4"}, - {KEY_HAT1+14, "HATLEFT4"}, - {KEY_HAT1+15, "HATRIGHT4"}, + {KEY_HAT1+0, "hatup"}, + {KEY_HAT1+1, "hatdown"}, + {KEY_HAT1+2, "hatleft"}, + {KEY_HAT1+3, "hatright"}, + {KEY_HAT1+4, "hatup2"}, + {KEY_HAT1+5, "hatdown2"}, + {KEY_HAT1+6, "hatleft2"}, + {KEY_HAT1+7, "hatright2"}, + {KEY_HAT1+8, "hatup3"}, + {KEY_HAT1+9, "hatdown3"}, + {KEY_HAT1+10, "hatleft3"}, + {KEY_HAT1+11, "hatright3"}, + {KEY_HAT1+12, "hatup4"}, + {KEY_HAT1+13, "hatdown4"}, + {KEY_HAT1+14, "hatleft4"}, + {KEY_HAT1+15, "hatright4"}, - {KEY_DBLMOUSE1+0, "DBLMOUSE1"}, - {KEY_DBLMOUSE1+1, "DBLMOUSE2"}, - {KEY_DBLMOUSE1+2, "DBLMOUSE3"}, - {KEY_DBLMOUSE1+3, "DBLMOUSE4"}, - {KEY_DBLMOUSE1+4, "DBLMOUSE5"}, - {KEY_DBLMOUSE1+5, "DBLMOUSE6"}, - {KEY_DBLMOUSE1+6, "DBLMOUSE7"}, - {KEY_DBLMOUSE1+7, "DBLMOUSE8"}, - {KEY_DBL2MOUSE1+0, "DBLSEC_MOUSE2"}, // BP: sorry my mouse handler swap button 1 and 2 - {KEY_DBL2MOUSE1+1, "DBLSEC_MOUSE1"}, - {KEY_DBL2MOUSE1+2, "DBLSEC_MOUSE3"}, - {KEY_DBL2MOUSE1+3, "DBLSEC_MOUSE4"}, - {KEY_DBL2MOUSE1+4, "DBLSEC_MOUSE5"}, - {KEY_DBL2MOUSE1+5, "DBLSEC_MOUSE6"}, - {KEY_DBL2MOUSE1+6, "DBLSEC_MOUSE7"}, - {KEY_DBL2MOUSE1+7, "DBLSEC_MOUSE8"}, + {KEY_DBLMOUSE1+0, "dblmouse1"}, + {KEY_DBLMOUSE1+1, "dblmouse2"}, + {KEY_DBLMOUSE1+2, "dblmouse3"}, + {KEY_DBLMOUSE1+3, "dblmouse4"}, + {KEY_DBLMOUSE1+4, "dblmouse5"}, + {KEY_DBLMOUSE1+5, "dblmouse6"}, + {KEY_DBLMOUSE1+6, "dblmouse7"}, + {KEY_DBLMOUSE1+7, "dblmouse8"}, + {KEY_DBL2MOUSE1+0, "dblsec_mouse2"}, // BP: sorry my mouse handler swap button 1 and 2 + {KEY_DBL2MOUSE1+1, "dblsec_mouse1"}, + {KEY_DBL2MOUSE1+2, "dblsec_mouse3"}, + {KEY_DBL2MOUSE1+3, "dblsec_mouse4"}, + {KEY_DBL2MOUSE1+4, "dblsec_mouse5"}, + {KEY_DBL2MOUSE1+5, "dblsec_mouse6"}, + {KEY_DBL2MOUSE1+6, "dblsec_mouse7"}, + {KEY_DBL2MOUSE1+7, "dblsec_mouse8"}, - {KEY_DBLJOY1+0, "DBLJOY1"}, - {KEY_DBLJOY1+1, "DBLJOY2"}, - {KEY_DBLJOY1+2, "DBLJOY3"}, - {KEY_DBLJOY1+3, "DBLJOY4"}, - {KEY_DBLJOY1+4, "DBLJOY5"}, - {KEY_DBLJOY1+5, "DBLJOY6"}, - {KEY_DBLJOY1+6, "DBLJOY7"}, - {KEY_DBLJOY1+7, "DBLJOY8"}, + {KEY_DBLJOY1+0, "dbljoy1"}, + {KEY_DBLJOY1+1, "dbljoy2"}, + {KEY_DBLJOY1+2, "dbljoy3"}, + {KEY_DBLJOY1+3, "dbljoy4"}, + {KEY_DBLJOY1+4, "dbljoy5"}, + {KEY_DBLJOY1+5, "dbljoy6"}, + {KEY_DBLJOY1+6, "dbljoy7"}, + {KEY_DBLJOY1+7, "dbljoy8"}, #if !defined (NOMOREJOYBTN_1DBL) - {KEY_DBLJOY1+8, "DBLJOY9"}, - {KEY_DBLJOY1+9, "DBLJOY10"}, - {KEY_DBLJOY1+10, "DBLJOY11"}, - {KEY_DBLJOY1+11, "DBLJOY12"}, - {KEY_DBLJOY1+12, "DBLJOY13"}, - {KEY_DBLJOY1+13, "DBLJOY14"}, - {KEY_DBLJOY1+14, "DBLJOY15"}, - {KEY_DBLJOY1+15, "DBLJOY16"}, - {KEY_DBLJOY1+16, "DBLJOY17"}, - {KEY_DBLJOY1+17, "DBLJOY18"}, - {KEY_DBLJOY1+18, "DBLJOY19"}, - {KEY_DBLJOY1+19, "DBLJOY20"}, - {KEY_DBLJOY1+20, "DBLJOY21"}, - {KEY_DBLJOY1+21, "DBLJOY22"}, - {KEY_DBLJOY1+22, "DBLJOY23"}, - {KEY_DBLJOY1+23, "DBLJOY24"}, - {KEY_DBLJOY1+24, "DBLJOY25"}, - {KEY_DBLJOY1+25, "DBLJOY26"}, - {KEY_DBLJOY1+26, "DBLJOY27"}, - {KEY_DBLJOY1+27, "DBLJOY28"}, - {KEY_DBLJOY1+28, "DBLJOY29"}, - {KEY_DBLJOY1+29, "DBLJOY30"}, - {KEY_DBLJOY1+30, "DBLJOY31"}, - {KEY_DBLJOY1+31, "DBLJOY32"}, + {KEY_DBLJOY1+8, "dbljoy9"}, + {KEY_DBLJOY1+9, "dbljoy10"}, + {KEY_DBLJOY1+10, "dbljoy11"}, + {KEY_DBLJOY1+11, "dbljoy12"}, + {KEY_DBLJOY1+12, "dbljoy13"}, + {KEY_DBLJOY1+13, "dbljoy14"}, + {KEY_DBLJOY1+14, "dbljoy15"}, + {KEY_DBLJOY1+15, "dbljoy16"}, + {KEY_DBLJOY1+16, "dbljoy17"}, + {KEY_DBLJOY1+17, "dbljoy18"}, + {KEY_DBLJOY1+18, "dbljoy19"}, + {KEY_DBLJOY1+19, "dbljoy20"}, + {KEY_DBLJOY1+20, "dbljoy21"}, + {KEY_DBLJOY1+21, "dbljoy22"}, + {KEY_DBLJOY1+22, "dbljoy23"}, + {KEY_DBLJOY1+23, "dbljoy24"}, + {KEY_DBLJOY1+24, "dbljoy25"}, + {KEY_DBLJOY1+25, "dbljoy26"}, + {KEY_DBLJOY1+26, "dbljoy27"}, + {KEY_DBLJOY1+27, "dbljoy28"}, + {KEY_DBLJOY1+28, "dbljoy29"}, + {KEY_DBLJOY1+29, "dbljoy30"}, + {KEY_DBLJOY1+30, "dbljoy31"}, + {KEY_DBLJOY1+31, "dbljoy32"}, #endif - {KEY_DBLHAT1+0, "DBLHATUP"}, - {KEY_DBLHAT1+1, "DBLHATDOWN"}, - {KEY_DBLHAT1+2, "DBLHATLEFT"}, - {KEY_DBLHAT1+3, "DBLHATRIGHT"}, - {KEY_DBLHAT1+4, "DBLHATUP2"}, - {KEY_DBLHAT1+5, "DBLHATDOWN2"}, - {KEY_DBLHAT1+6, "DBLHATLEFT2"}, - {KEY_DBLHAT1+7, "DBLHATRIGHT2"}, - {KEY_DBLHAT1+8, "DBLHATUP3"}, - {KEY_DBLHAT1+9, "DBLHATDOWN3"}, - {KEY_DBLHAT1+10, "DBLHATLEFT3"}, - {KEY_DBLHAT1+11, "DBLHATRIGHT3"}, - {KEY_DBLHAT1+12, "DBLHATUP4"}, - {KEY_DBLHAT1+13, "DBLHATDOWN4"}, - {KEY_DBLHAT1+14, "DBLHATLEFT4"}, - {KEY_DBLHAT1+15, "DBLHATRIGHT4"}, + {KEY_DBLHAT1+0, "dblhatup"}, + {KEY_DBLHAT1+1, "dblhatdown"}, + {KEY_DBLHAT1+2, "dblhatleft"}, + {KEY_DBLHAT1+3, "dblhatright"}, + {KEY_DBLHAT1+4, "dblhatup2"}, + {KEY_DBLHAT1+5, "dblhatdown2"}, + {KEY_DBLHAT1+6, "dblhatleft2"}, + {KEY_DBLHAT1+7, "dblhatright2"}, + {KEY_DBLHAT1+8, "dblhatup3"}, + {KEY_DBLHAT1+9, "dblhatdown3"}, + {KEY_DBLHAT1+10, "dblhatleft3"}, + {KEY_DBLHAT1+11, "dblhatright3"}, + {KEY_DBLHAT1+12, "dblhatup4"}, + {KEY_DBLHAT1+13, "dblhatdown4"}, + {KEY_DBLHAT1+14, "dblhatleft4"}, + {KEY_DBLHAT1+15, "dblhatright4"}, - {KEY_2JOY1+0, "SEC_JOY1"}, - {KEY_2JOY1+1, "SEC_JOY2"}, - {KEY_2JOY1+2, "SEC_JOY3"}, - {KEY_2JOY1+3, "SEC_JOY4"}, - {KEY_2JOY1+4, "SEC_JOY5"}, - {KEY_2JOY1+5, "SEC_JOY6"}, - {KEY_2JOY1+6, "SEC_JOY7"}, - {KEY_2JOY1+7, "SEC_JOY8"}, + {KEY_2JOY1+0, "sec_joy1"}, + {KEY_2JOY1+1, "sec_joy2"}, + {KEY_2JOY1+2, "sec_joy3"}, + {KEY_2JOY1+3, "sec_joy4"}, + {KEY_2JOY1+4, "sec_joy5"}, + {KEY_2JOY1+5, "sec_joy6"}, + {KEY_2JOY1+6, "sec_joy7"}, + {KEY_2JOY1+7, "sec_joy8"}, #if !defined (NOMOREJOYBTN_2S) // we use up to 32 buttons in DirectInput - {KEY_2JOY1+8, "SEC_JOY9"}, - {KEY_2JOY1+9, "SEC_JOY10"}, - {KEY_2JOY1+10, "SEC_JOY11"}, - {KEY_2JOY1+11, "SEC_JOY12"}, - {KEY_2JOY1+12, "SEC_JOY13"}, - {KEY_2JOY1+13, "SEC_JOY14"}, - {KEY_2JOY1+14, "SEC_JOY15"}, - {KEY_2JOY1+15, "SEC_JOY16"}, - {KEY_2JOY1+16, "SEC_JOY17"}, - {KEY_2JOY1+17, "SEC_JOY18"}, - {KEY_2JOY1+18, "SEC_JOY19"}, - {KEY_2JOY1+19, "SEC_JOY20"}, - {KEY_2JOY1+20, "SEC_JOY21"}, - {KEY_2JOY1+21, "SEC_JOY22"}, - {KEY_2JOY1+22, "SEC_JOY23"}, - {KEY_2JOY1+23, "SEC_JOY24"}, - {KEY_2JOY1+24, "SEC_JOY25"}, - {KEY_2JOY1+25, "SEC_JOY26"}, - {KEY_2JOY1+26, "SEC_JOY27"}, - {KEY_2JOY1+27, "SEC_JOY28"}, - {KEY_2JOY1+28, "SEC_JOY29"}, - {KEY_2JOY1+29, "SEC_JOY30"}, - {KEY_2JOY1+30, "SEC_JOY31"}, - {KEY_2JOY1+31, "SEC_JOY32"}, + {KEY_2JOY1+8, "sec_joy9"}, + {KEY_2JOY1+9, "sec_joy10"}, + {KEY_2JOY1+10, "sec_joy11"}, + {KEY_2JOY1+11, "sec_joy12"}, + {KEY_2JOY1+12, "sec_joy13"}, + {KEY_2JOY1+13, "sec_joy14"}, + {KEY_2JOY1+14, "sec_joy15"}, + {KEY_2JOY1+15, "sec_joy16"}, + {KEY_2JOY1+16, "sec_joy17"}, + {KEY_2JOY1+17, "sec_joy18"}, + {KEY_2JOY1+18, "sec_joy19"}, + {KEY_2JOY1+19, "sec_joy20"}, + {KEY_2JOY1+20, "sec_joy21"}, + {KEY_2JOY1+21, "sec_joy22"}, + {KEY_2JOY1+22, "sec_joy23"}, + {KEY_2JOY1+23, "sec_joy24"}, + {KEY_2JOY1+24, "sec_joy25"}, + {KEY_2JOY1+25, "sec_joy26"}, + {KEY_2JOY1+26, "sec_joy27"}, + {KEY_2JOY1+27, "sec_joy28"}, + {KEY_2JOY1+28, "sec_joy29"}, + {KEY_2JOY1+29, "sec_joy30"}, + {KEY_2JOY1+30, "sec_joy31"}, + {KEY_2JOY1+31, "sec_joy32"}, #endif // the DOS version uses Allegro's joystick support - {KEY_2HAT1+0, "SEC_HATUP"}, - {KEY_2HAT1+1, "SEC_HATDOWN"}, - {KEY_2HAT1+2, "SEC_HATLEFT"}, - {KEY_2HAT1+3, "SEC_HATRIGHT"}, - {KEY_2HAT1+4, "SEC_HATUP2"}, - {KEY_2HAT1+5, "SEC_HATDOWN2"}, - {KEY_2HAT1+6, "SEC_HATLEFT2"}, - {KEY_2HAT1+7, "SEC_HATRIGHT2"}, - {KEY_2HAT1+8, "SEC_HATUP3"}, - {KEY_2HAT1+9, "SEC_HATDOWN3"}, - {KEY_2HAT1+10, "SEC_HATLEFT3"}, - {KEY_2HAT1+11, "SEC_HATRIGHT3"}, - {KEY_2HAT1+12, "SEC_HATUP4"}, - {KEY_2HAT1+13, "SEC_HATDOWN4"}, - {KEY_2HAT1+14, "SEC_HATLEFT4"}, - {KEY_2HAT1+15, "SEC_HATRIGHT4"}, + {KEY_2HAT1+0, "sec_hatup"}, + {KEY_2HAT1+1, "sec_hatdown"}, + {KEY_2HAT1+2, "sec_hatleft"}, + {KEY_2HAT1+3, "sec_hatright"}, + {KEY_2HAT1+4, "sec_hatup2"}, + {KEY_2HAT1+5, "sec_hatdown2"}, + {KEY_2HAT1+6, "sec_hatleft2"}, + {KEY_2HAT1+7, "sec_hatright2"}, + {KEY_2HAT1+8, "sec_hatup3"}, + {KEY_2HAT1+9, "sec_hatdown3"}, + {KEY_2HAT1+10, "sec_hatleft3"}, + {KEY_2HAT1+11, "sec_hatright3"}, + {KEY_2HAT1+12, "sec_hatup4"}, + {KEY_2HAT1+13, "sec_hatdown4"}, + {KEY_2HAT1+14, "sec_hatleft4"}, + {KEY_2HAT1+15, "sec_hatright4"}, - {KEY_DBL2JOY1+0, "DBLSEC_JOY1"}, - {KEY_DBL2JOY1+1, "DBLSEC_JOY2"}, - {KEY_DBL2JOY1+2, "DBLSEC_JOY3"}, - {KEY_DBL2JOY1+3, "DBLSEC_JOY4"}, - {KEY_DBL2JOY1+4, "DBLSEC_JOY5"}, - {KEY_DBL2JOY1+5, "DBLSEC_JOY6"}, - {KEY_DBL2JOY1+6, "DBLSEC_JOY7"}, - {KEY_DBL2JOY1+7, "DBLSEC_JOY8"}, + {KEY_DBL2JOY1+0, "dblsec_joy1"}, + {KEY_DBL2JOY1+1, "dblsec_joy2"}, + {KEY_DBL2JOY1+2, "dblsec_joy3"}, + {KEY_DBL2JOY1+3, "dblsec_joy4"}, + {KEY_DBL2JOY1+4, "dblsec_joy5"}, + {KEY_DBL2JOY1+5, "dblsec_joy6"}, + {KEY_DBL2JOY1+6, "dblsec_joy7"}, + {KEY_DBL2JOY1+7, "dblsec_joy8"}, #if !defined (NOMOREJOYBTN_2DBL) - {KEY_DBL2JOY1+8, "DBLSEC_JOY9"}, - {KEY_DBL2JOY1+9, "DBLSEC_JOY10"}, - {KEY_DBL2JOY1+10, "DBLSEC_JOY11"}, - {KEY_DBL2JOY1+11, "DBLSEC_JOY12"}, - {KEY_DBL2JOY1+12, "DBLSEC_JOY13"}, - {KEY_DBL2JOY1+13, "DBLSEC_JOY14"}, - {KEY_DBL2JOY1+14, "DBLSEC_JOY15"}, - {KEY_DBL2JOY1+15, "DBLSEC_JOY16"}, - {KEY_DBL2JOY1+16, "DBLSEC_JOY17"}, - {KEY_DBL2JOY1+17, "DBLSEC_JOY18"}, - {KEY_DBL2JOY1+18, "DBLSEC_JOY19"}, - {KEY_DBL2JOY1+19, "DBLSEC_JOY20"}, - {KEY_DBL2JOY1+20, "DBLSEC_JOY21"}, - {KEY_DBL2JOY1+21, "DBLSEC_JOY22"}, - {KEY_DBL2JOY1+22, "DBLSEC_JOY23"}, - {KEY_DBL2JOY1+23, "DBLSEC_JOY24"}, - {KEY_DBL2JOY1+24, "DBLSEC_JOY25"}, - {KEY_DBL2JOY1+25, "DBLSEC_JOY26"}, - {KEY_DBL2JOY1+26, "DBLSEC_JOY27"}, - {KEY_DBL2JOY1+27, "DBLSEC_JOY28"}, - {KEY_DBL2JOY1+28, "DBLSEC_JOY29"}, - {KEY_DBL2JOY1+29, "DBLSEC_JOY30"}, - {KEY_DBL2JOY1+30, "DBLSEC_JOY31"}, - {KEY_DBL2JOY1+31, "DBLSEC_JOY32"}, + {KEY_DBL2JOY1+8, "dblsec_joy9"}, + {KEY_DBL2JOY1+9, "dblsec_joy10"}, + {KEY_DBL2JOY1+10, "dblsec_joy11"}, + {KEY_DBL2JOY1+11, "dblsec_joy12"}, + {KEY_DBL2JOY1+12, "dblsec_joy13"}, + {KEY_DBL2JOY1+13, "dblsec_joy14"}, + {KEY_DBL2JOY1+14, "dblsec_joy15"}, + {KEY_DBL2JOY1+15, "dblsec_joy16"}, + {KEY_DBL2JOY1+16, "dblsec_joy17"}, + {KEY_DBL2JOY1+17, "dblsec_joy18"}, + {KEY_DBL2JOY1+18, "dblsec_joy19"}, + {KEY_DBL2JOY1+19, "dblsec_joy20"}, + {KEY_DBL2JOY1+20, "dblsec_joy21"}, + {KEY_DBL2JOY1+21, "dblsec_joy22"}, + {KEY_DBL2JOY1+22, "dblsec_joy23"}, + {KEY_DBL2JOY1+23, "dblsec_joy24"}, + {KEY_DBL2JOY1+24, "dblsec_joy25"}, + {KEY_DBL2JOY1+25, "dblsec_joy26"}, + {KEY_DBL2JOY1+26, "dblsec_joy27"}, + {KEY_DBL2JOY1+27, "dblsec_joy28"}, + {KEY_DBL2JOY1+28, "dblsec_joy29"}, + {KEY_DBL2JOY1+29, "dblsec_joy30"}, + {KEY_DBL2JOY1+30, "dblsec_joy31"}, + {KEY_DBL2JOY1+31, "dblsec_joy32"}, #endif - {KEY_DBL2HAT1+0, "DBLSEC_HATUP"}, - {KEY_DBL2HAT1+1, "DBLSEC_HATDOWN"}, - {KEY_DBL2HAT1+2, "DBLSEC_HATLEFT"}, - {KEY_DBL2HAT1+3, "DBLSEC_HATRIGHT"}, - {KEY_DBL2HAT1+4, "DBLSEC_HATUP2"}, - {KEY_DBL2HAT1+5, "DBLSEC_HATDOWN2"}, - {KEY_DBL2HAT1+6, "DBLSEC_HATLEFT2"}, - {KEY_DBL2HAT1+7, "DBLSEC_HATRIGHT2"}, - {KEY_DBL2HAT1+8, "DBLSEC_HATUP3"}, - {KEY_DBL2HAT1+9, "DBLSEC_HATDOWN3"}, - {KEY_DBL2HAT1+10, "DBLSEC_HATLEFT3"}, - {KEY_DBL2HAT1+11, "DBLSEC_HATRIGHT3"}, - {KEY_DBL2HAT1+12, "DBLSEC_HATUP4"}, - {KEY_DBL2HAT1+13, "DBLSEC_HATDOWN4"}, - {KEY_DBL2HAT1+14, "DBLSEC_HATLEFT4"}, - {KEY_DBL2HAT1+15, "DBLSEC_HATRIGHT4"}, + {KEY_DBL2HAT1+0, "dblsec_hatup"}, + {KEY_DBL2HAT1+1, "dblsec_hatdown"}, + {KEY_DBL2HAT1+2, "dblsec_hatleft"}, + {KEY_DBL2HAT1+3, "dblsec_hatright"}, + {KEY_DBL2HAT1+4, "dblsec_hatup2"}, + {KEY_DBL2HAT1+5, "dblsec_hatdown2"}, + {KEY_DBL2HAT1+6, "dblsec_hatleft2"}, + {KEY_DBL2HAT1+7, "dblsec_hatright2"}, + {KEY_DBL2HAT1+8, "dblsec_hatup3"}, + {KEY_DBL2HAT1+9, "dblsec_hatdown3"}, + {KEY_DBL2HAT1+10, "dblsec_hatleft3"}, + {KEY_DBL2HAT1+11, "dblsec_hatright3"}, + {KEY_DBL2HAT1+12, "dblsec_hatup4"}, + {KEY_DBL2HAT1+13, "dblsec_hatdown4"}, + {KEY_DBL2HAT1+14, "dblsec_hatleft4"}, + {KEY_DBL2HAT1+15, "dblsec_hatright4"}, }; diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index 0ac33d136..da0319bcc 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -245,13 +245,16 @@ void HWR_RenderBatches(void) currently_batching = false;// no longer collecting batches if (!polygonArraySize) { - ps_hw_numpolys = ps_hw_numcalls = ps_hw_numshaders = ps_hw_numtextures = ps_hw_numpolyflags = ps_hw_numcolors = 0; + ps_hw_numpolys.value.i = ps_hw_numcalls.value.i = ps_hw_numshaders.value.i + = ps_hw_numtextures.value.i = ps_hw_numpolyflags.value.i + = ps_hw_numcolors.value.i = 0; return;// nothing to draw } // init stats vars - ps_hw_numpolys = polygonArraySize; - ps_hw_numcalls = ps_hw_numverts = 0; - ps_hw_numshaders = ps_hw_numtextures = ps_hw_numpolyflags = ps_hw_numcolors = 1; + ps_hw_numpolys.value.i = polygonArraySize; + ps_hw_numcalls.value.i = ps_hw_numverts.value.i = 0; + ps_hw_numshaders.value.i = ps_hw_numtextures.value.i + = ps_hw_numpolyflags.value.i = ps_hw_numcolors.value.i = 1; // init polygonIndexArray for (i = 0; i < polygonArraySize; i++) { @@ -259,12 +262,12 @@ void HWR_RenderBatches(void) } // sort polygons - ps_hw_batchsorttime = I_GetPreciseTime(); + PS_START_TIMING(ps_hw_batchsorttime); if (cv_glshaders.value && gl_shadersavailable) qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygons); else qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygonsNoShaders); - ps_hw_batchsorttime = I_GetPreciseTime() - ps_hw_batchsorttime; + PS_STOP_TIMING(ps_hw_batchsorttime); // sort order // 1. shader // 2. texture @@ -272,7 +275,7 @@ void HWR_RenderBatches(void) // 4. colors + light level // not sure about what order of the last 2 should be, or if it even matters - ps_hw_batchdrawtime = I_GetPreciseTime(); + PS_START_TIMING(ps_hw_batchdrawtime); currentShader = polygonArray[polygonIndexArray[0]].shader; currentTexture = polygonArray[polygonIndexArray[0]].texture; @@ -408,8 +411,8 @@ void HWR_RenderBatches(void) // execute draw call HWD.pfnDrawIndexedTriangles(¤tSurfaceInfo, finalVertexArray, finalIndexWritePos, currentPolyFlags, finalVertexIndexArray); // update stats - ps_hw_numcalls++; - ps_hw_numverts += finalIndexWritePos; + ps_hw_numcalls.value.i++; + ps_hw_numverts.value.i += finalIndexWritePos; // reset write positions finalVertexWritePos = 0; finalIndexWritePos = 0; @@ -426,7 +429,7 @@ void HWR_RenderBatches(void) currentShader = nextShader; changeShader = false; - ps_hw_numshaders++; + ps_hw_numshaders.value.i++; } if (changeTexture) { @@ -435,21 +438,21 @@ void HWR_RenderBatches(void) currentTexture = nextTexture; changeTexture = false; - ps_hw_numtextures++; + ps_hw_numtextures.value.i++; } if (changePolyFlags) { currentPolyFlags = nextPolyFlags; changePolyFlags = false; - ps_hw_numpolyflags++; + ps_hw_numpolyflags.value.i++; } if (changeSurfaceInfo) { currentSurfaceInfo = nextSurfaceInfo; changeSurfaceInfo = false; - ps_hw_numcolors++; + ps_hw_numcolors.value.i++; } // and that should be it? } @@ -457,7 +460,7 @@ void HWR_RenderBatches(void) polygonArraySize = 0; unsortedVertexArraySize = 0; - ps_hw_batchdrawtime = I_GetPreciseTime() - ps_hw_batchdrawtime; + PS_STOP_TIMING(ps_hw_batchdrawtime); } diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index f496de2ce..83a8595d1 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -147,22 +147,22 @@ static angle_t gl_aimingangle; static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox); // Render stats -precise_t ps_hw_skyboxtime = 0; -precise_t ps_hw_nodesorttime = 0; -precise_t ps_hw_nodedrawtime = 0; -precise_t ps_hw_spritesorttime = 0; -precise_t ps_hw_spritedrawtime = 0; +ps_metric_t ps_hw_skyboxtime = {0}; +ps_metric_t ps_hw_nodesorttime = {0}; +ps_metric_t ps_hw_nodedrawtime = {0}; +ps_metric_t ps_hw_spritesorttime = {0}; +ps_metric_t ps_hw_spritedrawtime = {0}; // Render stats for batching -int ps_hw_numpolys = 0; -int ps_hw_numverts = 0; -int ps_hw_numcalls = 0; -int ps_hw_numshaders = 0; -int ps_hw_numtextures = 0; -int ps_hw_numpolyflags = 0; -int ps_hw_numcolors = 0; -precise_t ps_hw_batchsorttime = 0; -precise_t ps_hw_batchdrawtime = 0; +ps_metric_t ps_hw_numpolys = {0}; +ps_metric_t ps_hw_numverts = {0}; +ps_metric_t ps_hw_numcalls = {0}; +ps_metric_t ps_hw_numshaders = {0}; +ps_metric_t ps_hw_numtextures = {0}; +ps_metric_t ps_hw_numpolyflags = {0}; +ps_metric_t ps_hw_numcolors = {0}; +ps_metric_t ps_hw_batchsorttime = {0}; +ps_metric_t ps_hw_batchdrawtime = {0}; boolean gl_init = false; boolean gl_maploaded = false; @@ -3235,7 +3235,7 @@ static void HWR_Subsector(size_t num) } // for render stats - ps_numpolyobjects += numpolys; + ps_numpolyobjects.value.i += numpolys; // Sort polyobjects R_SortPolyObjects(sub); @@ -3343,7 +3343,7 @@ static void HWR_RenderBSPNode(INT32 bspnum) // Decide which side the view point is on INT32 side; - ps_numbspcalls++; + ps_numbspcalls.value.i++; // Found a subsector? if (bspnum & NF_SUBSECTOR) @@ -4718,7 +4718,7 @@ static void HWR_CreateDrawNodes(void) // that is already lying around. This should all be in some sort of linked list or lists. sortindex = Z_Calloc(sizeof(size_t) * (numplanes + numpolyplanes + numwalls), PU_STATIC, NULL); - ps_hw_nodesorttime = I_GetPreciseTime(); + PS_START_TIMING(ps_hw_nodesorttime); for (i = 0; i < numplanes; i++, p++) { @@ -4738,7 +4738,7 @@ static void HWR_CreateDrawNodes(void) sortindex[p] = p; } - ps_numdrawnodes = p; + ps_numdrawnodes.value.i = p; // p is the number of stuff to sort @@ -4773,9 +4773,9 @@ static void HWR_CreateDrawNodes(void) } } - ps_hw_nodesorttime = I_GetPreciseTime() - ps_hw_nodesorttime; + PS_STOP_TIMING(ps_hw_nodesorttime); - ps_hw_nodedrawtime = I_GetPreciseTime(); + PS_START_TIMING(ps_hw_nodedrawtime); // Okay! Let's draw it all! Woo! HWD.pfnSetTransform(&atransform); @@ -4812,7 +4812,7 @@ static void HWR_CreateDrawNodes(void) } } - ps_hw_nodedrawtime = I_GetPreciseTime() - ps_hw_nodedrawtime; + PS_STOP_TIMING(ps_hw_nodedrawtime); numwalls = 0; numplanes = 0; @@ -6095,10 +6095,10 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) if (viewnumber == 0) // Only do it if it's the first screen being rendered HWD.pfnClearBuffer(true, false, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs. - ps_hw_skyboxtime = I_GetPreciseTime(); + PS_START_TIMING(ps_hw_skyboxtime); if (skybox && drawsky) // If there's a skybox and we should be drawing the sky, draw the skybox HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind - ps_hw_skyboxtime = I_GetPreciseTime() - ps_hw_skyboxtime; + PS_STOP_TIMING(ps_hw_skyboxtime); { // do we really need to save player (is it not the same)? @@ -6208,9 +6208,9 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) // Reset the shader state. HWR_SetShaderState(); - ps_numbspcalls = 0; - ps_numpolyobjects = 0; - ps_bsptime = I_GetPreciseTime(); + ps_numbspcalls.value.i = 0; + ps_numpolyobjects.value.i = 0; + PS_START_TIMING(ps_bsptime); validcount++; @@ -6248,7 +6248,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) } #endif - ps_bsptime = I_GetPreciseTime() - ps_bsptime; + PS_STOP_TIMING(ps_bsptime); if (cv_glbatching.value) HWR_RenderBatches(); @@ -6263,22 +6263,22 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) #endif // Draw MD2 and sprites - ps_numsprites = gl_visspritecount; - ps_hw_spritesorttime = I_GetPreciseTime(); + ps_numsprites.value.i = gl_visspritecount; + PS_START_TIMING(ps_hw_spritesorttime); HWR_SortVisSprites(); - ps_hw_spritesorttime = I_GetPreciseTime() - ps_hw_spritesorttime; - ps_hw_spritedrawtime = I_GetPreciseTime(); + PS_STOP_TIMING(ps_hw_spritesorttime); + PS_START_TIMING(ps_hw_spritedrawtime); HWR_DrawSprites(); - ps_hw_spritedrawtime = I_GetPreciseTime() - ps_hw_spritedrawtime; + PS_STOP_TIMING(ps_hw_spritedrawtime); #ifdef NEWCORONAS //Hurdler: they must be drawn before translucent planes, what about gl fog? HWR_DrawCoronas(); #endif - ps_numdrawnodes = 0; - ps_hw_nodesorttime = 0; - ps_hw_nodedrawtime = 0; + ps_numdrawnodes.value.i = 0; + ps_hw_nodesorttime.value.p = 0; + ps_hw_nodedrawtime.value.p = 0; if (numplanes || numpolyplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything { HWR_CreateDrawNodes(); diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index b751b2a6e..3f90f0ae1 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -20,6 +20,8 @@ #include "../d_player.h" #include "../r_defs.h" +#include "../m_perfstats.h" + // Startup & Shutdown the hardware mode renderer void HWR_Startup(void); void HWR_Switch(void); @@ -116,22 +118,22 @@ extern FTransform atransform; // Render stats -extern precise_t ps_hw_skyboxtime; -extern precise_t ps_hw_nodesorttime; -extern precise_t ps_hw_nodedrawtime; -extern precise_t ps_hw_spritesorttime; -extern precise_t ps_hw_spritedrawtime; +extern ps_metric_t ps_hw_skyboxtime; +extern ps_metric_t ps_hw_nodesorttime; +extern ps_metric_t ps_hw_nodedrawtime; +extern ps_metric_t ps_hw_spritesorttime; +extern ps_metric_t ps_hw_spritedrawtime; // Render stats for batching -extern int ps_hw_numpolys; -extern int ps_hw_numverts; -extern int ps_hw_numcalls; -extern int ps_hw_numshaders; -extern int ps_hw_numtextures; -extern int ps_hw_numpolyflags; -extern int ps_hw_numcolors; -extern precise_t ps_hw_batchsorttime; -extern precise_t ps_hw_batchdrawtime; +extern ps_metric_t ps_hw_numpolys; +extern ps_metric_t ps_hw_numverts; +extern ps_metric_t ps_hw_numcalls; +extern ps_metric_t ps_hw_numshaders; +extern ps_metric_t ps_hw_numtextures; +extern ps_metric_t ps_hw_numpolyflags; +extern ps_metric_t ps_hw_numcolors; +extern ps_metric_t ps_hw_batchsorttime; +extern ps_metric_t ps_hw_batchdrawtime; extern boolean gl_init; extern boolean gl_maploaded; diff --git a/src/i_system.h b/src/i_system.h index e046fd620..a2dd81cca 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -50,7 +50,7 @@ tic_t I_GetTime(void); */ precise_t I_GetPreciseTime(void); -/** \brief Returns the difference between precise times as microseconds. +/** \brief Converts a precise_t to microseconds and casts it to a 32 bit integer. */ int I_PreciseToMicros(precise_t); @@ -318,10 +318,6 @@ void I_RegisterSysCommands(void); */ void I_GetCursorPosition(INT32 *x, INT32 *y); -/** \brief Returns whether the mouse is grabbed -*/ -boolean I_GetMouseGrab(void); - /** \brief Sets whether the mouse is grabbed */ void I_SetMouseGrab(boolean grab); diff --git a/src/info.c b/src/info.c index efcf1c044..f56e5d78e 100644 --- a/src/info.c +++ b/src/info.c @@ -2069,7 +2069,7 @@ state_t states[NUMSTATES] = {SPR_TVFL, 2, 18, {A_GiveShield}, SH_FLAMEAURA, 0, S_NULL}, // S_FLAMEAURA_ICON2 {SPR_TVBB, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_BUBBLEWRAP_ICON2}, // S_BUBBLEWRAP_ICON1 - {SPR_TVBB, 2, 18, {A_GiveShield}, SH_BUBBLEWRAP, 0, S_NULL}, // S_BUBBLERWAP_ICON2 + {SPR_TVBB, 2, 18, {A_GiveShield}, SH_BUBBLEWRAP, 0, S_NULL}, // S_BUBBLEWRAP_ICON2 {SPR_TVZP, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_THUNDERCOIN_ICON2}, // S_THUNDERCOIN_ICON1 {SPR_TVZP, 2, 18, {A_GiveShield}, SH_THUNDERCOIN, 0, S_NULL}, // S_THUNDERCOIN_ICON2 @@ -5199,7 +5199,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 24*FRACUNIT, // radius 34*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 0, // damage sfx_None, // activesound MF_NOGRAVITY|MF_NOBLOCKMAP|MF_FIRE|MF_PAIN, // flags @@ -7974,7 +7974,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset - 4, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_SCENERY|MF_NOCLIPHEIGHT, // flags @@ -8001,7 +8001,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 14*FRACUNIT, // height 0, // display offset - 4, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPHEIGHT|MF_PAPERCOLLISION, // flags @@ -11430,7 +11430,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 17*FRACUNIT, // radius 34*FRACUNIT, // height 1, // display offset - 0, // mass + DMG_SPIKE, // mass 1, // damage sfx_s3kc9s, //sfx_mswing, -- activesound MF_SCENERY|MF_PAIN|MF_NOGRAVITY, // flags @@ -11457,7 +11457,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 34*FRACUNIT, // radius 68*FRACUNIT, // height 1, // display offset - 0, // mass + DMG_SPIKE, // mass 1, // damage sfx_s3kc9s, //sfx_mswing, -- activesound MF_SCENERY|MF_PAIN|MF_NOGRAVITY, // flags @@ -13401,7 +13401,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 30*FRACUNIT, // radius 48*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_PAIN|MF_NOGRAVITY|MF_FIRE, // flags @@ -13806,7 +13806,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset - 0, // mass + 0, // mass 0, // damage sfx_None, // activesound MF_NOGRAVITY|MF_PAIN, // flags @@ -20380,7 +20380,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 18*FRACUNIT, // radius 28*FRACUNIT, // height 0, // display offset - 0, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_NOGRAVITY|MF_PAIN, // flags diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 7c1d61a9c..f51143556 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -31,6 +31,7 @@ #include "m_misc.h" // M_MapNumber #include "b_bot.h" // B_UpdateBotleader #include "d_clisrv.h" // CL_RemovePlayer +#include "i_system.h" // I_GetPreciseTime, I_PreciseToMicros #include "lua_script.h" #include "lua_libs.h" @@ -187,6 +188,8 @@ static const struct { {META_MAPHEADER, "mapheader_t"}, {META_POLYOBJ, "polyobj_t"}, + {META_POLYOBJVERTICES, "polyobj_t.vertices"}, + {META_POLYOBJLINES, "polyobj_t.lines"}, {META_CVAR, "consvar_t"}, @@ -216,6 +219,7 @@ static const struct { {META_LUABANKS, "luabanks[]"}, + {META_KEYEVENT, "keyevent_t"}, {META_MOUSE, "mouse_t"}, {NULL, NULL} }; @@ -3877,6 +3881,12 @@ static int lib_gTicsToMilliseconds(lua_State *L) return 1; } +static int lib_getTimeMicros(lua_State *L) +{ + lua_pushinteger(L, I_PreciseToMicros(I_GetPreciseTime())); + return 1; +} + static luaL_Reg lib[] = { {"print", lib_print}, {"chatprint", lib_chatprint}, @@ -4151,6 +4161,8 @@ static luaL_Reg lib[] = { {"G_TicsToCentiseconds",lib_gTicsToCentiseconds}, {"G_TicsToMilliseconds",lib_gTicsToMilliseconds}, + {"getTimeMicros",lib_getTimeMicros}, + {NULL, NULL} }; diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 32b5e52fb..a72b22b5a 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -505,7 +505,7 @@ static int call_hooks calls += call_mobj_type_hooks(hook, MT_NULL); calls += call_mobj_type_hooks(hook, hook->mobj_type); - ps_lua_mobjhooks += calls; + ps_lua_mobjhooks.value.i += calls; } else calls += call_mapped(hook, &hookIds[hook->hook_type]); @@ -868,7 +868,7 @@ void LUA_HookLinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) LUA_PushUserdata(gL, line, META_LINE); LUA_PushUserdata(gL, mo, META_MOBJ); LUA_PushUserdata(gL, sector, META_SECTOR); - ps_lua_mobjhooks += call_hooks(&hook, 0, res_none); + ps_lua_mobjhooks.value.i += call_hooks(&hook, 0, res_none); } } diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index fca832053..0dd951efd 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -265,7 +265,7 @@ static int hudinfo_num(lua_State *L) static int colormap_get(lua_State *L) { - UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP)); + const UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP)); UINT32 i = luaL_checkinteger(L, 2); if (i >= 256) return luaL_error(L, "colormap index %d out of range (0 - %d)", i, 255); @@ -273,23 +273,6 @@ static int colormap_get(lua_State *L) return 1; } -static int colormap_set(lua_State *L) -{ - UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP)); - UINT32 i = luaL_checkinteger(L, 2); - if (i >= 256) - return luaL_error(L, "colormap index %d out of range (0 - %d)", i, 255); - colormap[i] = (UINT8)luaL_checkinteger(L, 3); - return 0; -} - -static int colormap_free(lua_State *L) -{ - UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP)); - Z_Free(colormap); - return 0; -} - static int patch_get(lua_State *L) { patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH)); @@ -1057,7 +1040,7 @@ static int libd_getColormap(lua_State *L) // all was successful above, now we generate the colormap at last! - colormap = R_GetTranslationColormap(skinnum, color, 0); + colormap = R_GetTranslationColormap(skinnum, color, GTC_CACHE); LUA_PushUserdata(L, colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use! return 1; } @@ -1066,14 +1049,10 @@ static int libd_getStringColormap(lua_State *L) { INT32 flags = luaL_checkinteger(L, 1); UINT8* colormap = NULL; - UINT8* lua_colormap = NULL; HUDONLY colormap = V_GetStringColormap(flags & V_CHARCOLORMASK); if (colormap) { - lua_colormap = Z_Malloc(256 * sizeof(UINT8), PU_LUA, NULL); - memcpy(lua_colormap, colormap, 256 * sizeof(UINT8)); - - LUA_PushUserdata(L, lua_colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use! + LUA_PushUserdata(L, colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use! return 1; } return 0; @@ -1348,12 +1327,6 @@ int LUA_HudLib(lua_State *L) luaL_newmetatable(L, META_COLORMAP); lua_pushcfunction(L, colormap_get); lua_setfield(L, -2, "__index"); - - lua_pushcfunction(L, colormap_set); - lua_setfield(L, -2, "__newindex"); - - lua_pushcfunction(L, colormap_free); - lua_setfield(L, -2, "__gc"); lua_pop(L,1); luaL_newmetatable(L, META_PATCH); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 52800535c..0ee87d2d2 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -204,7 +204,7 @@ enum ffloor_e { ffloor_next, ffloor_prev, ffloor_alpha, - ffloor_specialflags, + ffloor_bustflags, ffloor_busttype, ffloor_busttag, ffloor_sinkspeed, @@ -228,7 +228,7 @@ static const char *const ffloor_opt[] = { "next", "prev", "alpha", - "specialflags", + "bustflags", "busttype", "busttag", "sinkspeed", @@ -1851,8 +1851,8 @@ static int ffloor_get(lua_State *L) case ffloor_alpha: lua_pushinteger(L, ffloor->alpha); return 1; - case ffloor_specialflags: - lua_pushinteger(L, ffloor->specialflags); + case ffloor_bustflags: + lua_pushinteger(L, ffloor->bustflags); return 1; case ffloor_busttype: lua_pushinteger(L, ffloor->busttype); diff --git a/src/m_menu.c b/src/m_menu.c index 7a82fd8fb..fc1e33b67 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) @@ -4062,14 +4062,6 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop) for (i = 1; i < SLIDER_RANGE; i++) V_DrawScaledPatch (x+i*8, y, 0,p); - if (ontop) - { - V_DrawCharacter(x - 6 - (skullAnimCounter/5), y, - '\x1C' | V_YELLOWMAP, false); - V_DrawCharacter(x+i*8 + 8 + (skullAnimCounter/5), y, - '\x1D' | V_YELLOWMAP, false); - } - p = W_CachePatchName("M_SLIDER", PU_PATCH); V_DrawScaledPatch(x+i*8, y, 0, p); @@ -4105,6 +4097,16 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop) range = 100; V_DrawMappedPatch(x + 2 + (SLIDER_RANGE*8*range)/100, y, 0, p, yellowmap); + + if (ontop) + { + V_DrawCharacter(x - 6 - (skullAnimCounter/5), y, + '\x1C' | V_YELLOWMAP, false); + V_DrawCharacter(x + 80 + (skullAnimCounter/5), y, + '\x1D' | V_YELLOWMAP, false); + V_DrawCenteredString(x + 40, y, V_30TRANS, + (cv->flags & CV_FLOAT) ? va("%.2f", FIXED_TO_FLOAT(cv->value)) : va("%d", cv->value)); + } } // @@ -6410,6 +6412,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 +6460,7 @@ static void M_DrawTemperature(INT32 x, fixed_t t) #undef vpadding #undef h #undef NUMCOLOURS +#endif static char *M_AddonsHeaderPath(void) { @@ -6550,21 +6554,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; @@ -7187,13 +7190,20 @@ static void M_HandleChecklist(INT32 choice) static void M_DrawChecklist(void) { - INT32 i = check_on, j = 0, y = currentMenu->y; + INT32 i = check_on, j = 0, y = currentMenu->y, emblems = numemblems+numextraemblems; UINT32 condnum, previd, maxcond; condition_t *cond; // draw title (or big pic) M_DrawMenuTitle(); + // draw emblem counter + if (emblems > 0) + { + V_DrawString(42, 20, (emblems == M_CountEmblems()) ? V_GREENMAP : 0, va("%d/%d", M_CountEmblems(), emblems)); + V_DrawSmallScaledPatch(28, 20, 0, W_CachePatchName("EMBLICON", PU_PATCH)); + } + if (check_on) V_DrawString(10, y-(skullAnimCounter/5), V_YELLOWMAP, "\x1A"); @@ -8652,6 +8662,12 @@ static void M_DrawLoad(void) loadgameoffset = 0; M_DrawLoadGameData(); + + if (modifiedgame && !savemoddata) + { + V_DrawCenteredThinString(BASEVIDWIDTH/2, 184, 0, "\x85WARNING: \x80The game is modified."); + V_DrawCenteredThinString(BASEVIDWIDTH/2, 192, 0, "Progress will not be saved."); + } } // @@ -8953,7 +8969,7 @@ static void M_HandleLoadSave(INT32 choice) break; case KEY_ENTER: - if (ultimate_selectable && saveSlotSelected == NOSAVESLOT) + if (ultimate_selectable && saveSlotSelected == NOSAVESLOT && !savemoddata && !modifiedgame) { loadgamescroll = 0; S_StartSound(NULL, sfx_skid); diff --git a/src/m_perfstats.c b/src/m_perfstats.c index 8a99312e6..439a9da1c 100644 --- a/src/m_perfstats.c +++ b/src/m_perfstats.c @@ -22,560 +22,802 @@ #include "hardware/hw_main.h" #endif -struct perfstatcol; struct perfstatrow; -typedef struct perfstatcol perfstatcol_t; typedef struct perfstatrow perfstatrow_t; -struct perfstatcol { - INT32 lores_x; - INT32 hires_x; - INT32 color; - perfstatrow_t * rows; -}; - struct perfstatrow { - const char * lores_label; - const char * hires_label; - void * value; + const char * lores_label; + const char * hires_label; + ps_metric_t * metric; + UINT8 flags; }; -static precise_t ps_frametime = 0; +// perfstatrow_t flags -precise_t ps_tictime = 0; +#define PS_TIME 1 // metric measures time (uses precise_t instead of INT32) +#define PS_LEVEL 2 // metric is valid only when a level is active +#define PS_SW 4 // metric is valid only in software mode +#define PS_HW 8 // metric is valid only in opengl mode +#define PS_BATCHING 16 // metric is valid only when opengl batching is active +#define PS_HIDE_ZERO 32 // hide metric if its value is zero -precise_t ps_playerthink_time = 0; -precise_t ps_thinkertime = 0; +static ps_metric_t ps_frametime = {0}; -precise_t ps_thlist_times[NUM_THINKERLISTS]; +ps_metric_t ps_tictime = {0}; -int ps_checkposition_calls = 0; +ps_metric_t ps_playerthink_time = {0}; +ps_metric_t ps_thinkertime = {0}; -precise_t ps_lua_thinkframe_time = 0; -int ps_lua_mobjhooks = 0; +ps_metric_t ps_thlist_times[NUM_THINKERLISTS]; + +static ps_metric_t ps_thinkercount = {0}; +static ps_metric_t ps_polythcount = {0}; +static ps_metric_t ps_mainthcount = {0}; +static ps_metric_t ps_mobjcount = {0}; +static ps_metric_t ps_regularcount = {0}; +static ps_metric_t ps_scenerycount = {0}; +static ps_metric_t ps_nothinkcount = {0}; +static ps_metric_t ps_dynslopethcount = {0}; +static ps_metric_t ps_precipcount = {0}; +static ps_metric_t ps_removecount = {0}; + +ps_metric_t ps_checkposition_calls = {0}; + +ps_metric_t ps_lua_thinkframe_time = {0}; +ps_metric_t ps_lua_mobjhooks = {0}; + +ps_metric_t ps_otherlogictime = {0}; + +// Columns for perfstats pages. + +// Position on screen is determined separately in the drawing functions. + +// New columns must also be added to the drawing and update functions. +// Drawing functions: PS_DrawRenderStats, PS_DrawGameLogicStats, etc. +// Update functions: +// - PS_UpdateFrameStats for frame-dependent values +// - PS_UpdateTickStats for tick-dependent values + +// Rendering stats columns + +perfstatrow_t rendertime_rows[] = { + {"frmtime", "Frame time: ", &ps_frametime, PS_TIME}, + {"drwtime", "3d rendering: ", &ps_rendercalltime, PS_TIME|PS_LEVEL}, + +#ifdef HWRENDER + {" skybox ", " Skybox render: ", &ps_hw_skyboxtime, PS_TIME|PS_LEVEL|PS_HW}, + {" bsptime", " RenderBSPNode: ", &ps_bsptime, PS_TIME|PS_LEVEL|PS_HW}, + {" batsort", " Batch sort: ", &ps_hw_batchsorttime, PS_TIME|PS_LEVEL|PS_HW|PS_BATCHING}, + {" batdraw", " Batch render: ", &ps_hw_batchdrawtime, PS_TIME|PS_LEVEL|PS_HW|PS_BATCHING}, + {" sprsort", " Sprite sort: ", &ps_hw_spritesorttime, PS_TIME|PS_LEVEL|PS_HW}, + {" sprdraw", " Sprite render: ", &ps_hw_spritedrawtime, PS_TIME|PS_LEVEL|PS_HW}, + {" nodesrt", " Drwnode sort: ", &ps_hw_nodesorttime, PS_TIME|PS_LEVEL|PS_HW}, + {" nodedrw", " Drwnode render:", &ps_hw_nodedrawtime, PS_TIME|PS_LEVEL|PS_HW}, + {" other ", " Other: ", &ps_otherrendertime, PS_TIME|PS_LEVEL|PS_HW}, +#endif + + {" bsptime", " RenderBSPNode: ", &ps_bsptime, PS_TIME|PS_LEVEL|PS_SW}, + {" sprclip", " R_ClipSprites: ", &ps_sw_spritecliptime, PS_TIME|PS_LEVEL|PS_SW}, + {" portals", " Portals+Skybox:", &ps_sw_portaltime, PS_TIME|PS_LEVEL|PS_SW}, + {" planes ", " R_DrawPlanes: ", &ps_sw_planetime, PS_TIME|PS_LEVEL|PS_SW}, + {" masked ", " R_DrawMasked: ", &ps_sw_maskedtime, PS_TIME|PS_LEVEL|PS_SW}, + {" other ", " Other: ", &ps_otherrendertime, PS_TIME|PS_LEVEL|PS_SW}, + + {"ui ", "UI render: ", &ps_uitime, PS_TIME}, + {"finupdt", "I_FinishUpdate:", &ps_swaptime, PS_TIME}, + {0} +}; + +perfstatrow_t gamelogicbrief_row[] = { + {"logic ", "Game logic: ", &ps_tictime, PS_TIME}, + {0} +}; + +perfstatrow_t commoncounter_rows[] = { + {"bspcall", "BSP calls: ", &ps_numbspcalls, 0}, + {"sprites", "Sprites: ", &ps_numsprites, 0}, + {"drwnode", "Drawnodes: ", &ps_numdrawnodes, 0}, + {"plyobjs", "Polyobjects: ", &ps_numpolyobjects, 0}, + {0} +}; + +#ifdef HWRENDER +perfstatrow_t batchcount_rows[] = { + {"polygon", "Polygons: ", &ps_hw_numpolys, 0}, + {"vertex ", "Vertices: ", &ps_hw_numverts, 0}, + {0} +}; + +perfstatrow_t batchcalls_rows[] = { + {"drwcall", "Draw calls:", &ps_hw_numcalls, 0}, + {"shaders", "Shaders: ", &ps_hw_numshaders, 0}, + {"texture", "Textures: ", &ps_hw_numtextures, 0}, + {"polyflg", "Polyflags: ", &ps_hw_numpolyflags, 0}, + {"colors ", "Colors: ", &ps_hw_numcolors, 0}, + {0} +}; +#endif + +// Game logic stats columns + +perfstatrow_t gamelogic_rows[] = { + {"logic ", "Game logic: ", &ps_tictime, PS_TIME}, + {" plrthnk", " P_PlayerThink: ", &ps_playerthink_time, PS_TIME|PS_LEVEL}, + {" thnkers", " P_RunThinkers: ", &ps_thinkertime, PS_TIME|PS_LEVEL}, + {" plyobjs", " Polyobjects: ", &ps_thlist_times[THINK_POLYOBJ], PS_TIME|PS_LEVEL}, + {" main ", " Main: ", &ps_thlist_times[THINK_MAIN], PS_TIME|PS_LEVEL}, + {" mobjs ", " Mobjs: ", &ps_thlist_times[THINK_MOBJ], PS_TIME|PS_LEVEL}, + {" dynslop", " Dynamic slopes: ", &ps_thlist_times[THINK_DYNSLOPE], PS_TIME|PS_LEVEL}, + {" precip ", " Precipitation: ", &ps_thlist_times[THINK_PRECIP], PS_TIME|PS_LEVEL}, + {" lthinkf", " LUAh_ThinkFrame:", &ps_lua_thinkframe_time, PS_TIME|PS_LEVEL}, + {" other ", " Other: ", &ps_otherlogictime, PS_TIME|PS_LEVEL}, + {0} +}; + +perfstatrow_t thinkercount_rows[] = { + {"thnkers", "Thinkers: ", &ps_thinkercount, PS_LEVEL}, + {" plyobjs", " Polyobjects: ", &ps_polythcount, PS_LEVEL}, + {" main ", " Main: ", &ps_mainthcount, PS_LEVEL}, + {" mobjs ", " Mobjs: ", &ps_mobjcount, PS_LEVEL}, + {" regular", " Regular: ", &ps_regularcount, PS_LEVEL}, + {" scenery", " Scenery: ", &ps_scenerycount, PS_LEVEL}, + {" nothink", " Nothink: ", &ps_nothinkcount, PS_HIDE_ZERO|PS_LEVEL}, + {" dynslop", " Dynamic slopes: ", &ps_dynslopethcount, PS_LEVEL}, + {" precip ", " Precipitation: ", &ps_precipcount, PS_LEVEL}, + {" remove ", " Pending removal:", &ps_removecount, PS_LEVEL}, + {0} +}; + +perfstatrow_t misc_calls_rows[] = { + {"lmhook", "Lua mobj hooks: ", &ps_lua_mobjhooks, PS_LEVEL}, + {"chkpos", "P_CheckPosition:", &ps_checkposition_calls, PS_LEVEL}, + {0} +}; + +// Sample collection status for averaging. +// Maximum of these two is shown to user if nonzero to tell that +// the reported averages are not correct yet. +int ps_frame_samples_left = 0; +int ps_tick_samples_left = 0; +// History writing positions for frame and tick based metrics +int ps_frame_index = 0; +int ps_tick_index = 0; // dynamically allocated resizeable array for thinkframe hook stats ps_hookinfo_t *thinkframe_hooks = NULL; int thinkframe_hooks_length = 0; int thinkframe_hooks_capacity = 16; -static INT32 draw_row; - void PS_SetThinkFrameHookInfo(int index, precise_t time_taken, char* short_src) { if (!thinkframe_hooks) { // array needs to be initialized - thinkframe_hooks = Z_Malloc(sizeof(ps_hookinfo_t) * thinkframe_hooks_capacity, PU_STATIC, NULL); + thinkframe_hooks = Z_Calloc(sizeof(ps_hookinfo_t) * thinkframe_hooks_capacity, PU_STATIC, NULL); } if (index >= thinkframe_hooks_capacity) { // array needs more space, realloc with double size - thinkframe_hooks_capacity *= 2; + int new_capacity = thinkframe_hooks_capacity * 2; thinkframe_hooks = Z_Realloc(thinkframe_hooks, - sizeof(ps_hookinfo_t) * thinkframe_hooks_capacity, PU_STATIC, NULL); + sizeof(ps_hookinfo_t) * new_capacity, PU_STATIC, NULL); + // initialize new memory with zeros so the pointers in the structs are null + memset(&thinkframe_hooks[thinkframe_hooks_capacity], 0, + sizeof(ps_hookinfo_t) * thinkframe_hooks_capacity); + thinkframe_hooks_capacity = new_capacity; } - thinkframe_hooks[index].time_taken = time_taken; + thinkframe_hooks[index].time_taken.value.p = time_taken; memcpy(thinkframe_hooks[index].short_src, short_src, LUA_IDSIZE * sizeof(char)); // since the values are set sequentially from begin to end, the last call should leave // the correct value to this variable thinkframe_hooks_length = index + 1; } -static void PS_SetFrameTime(void) -{ - precise_t currenttime = I_GetPreciseTime(); - ps_frametime = currenttime - ps_prevframetime; - ps_prevframetime = currenttime; -} - -static boolean M_HighResolution(void) +static boolean PS_HighResolution(void) { return (vid.width >= 640 && vid.height >= 400); } -enum { - PERF_TIME, - PERF_COUNT, -}; - -static void M_DrawPerfString(perfstatcol_t *col, int type) +static boolean PS_IsLevelActive(void) { - const boolean hires = M_HighResolution(); + return gamestate == GS_LEVEL || + (gamestate == GS_TITLESCREEN && titlemapinaction); +} - INT32 draw_flags = V_MONOSPACE | col->color; +// Is the row valid in the current context? +static boolean PS_IsRowValid(perfstatrow_t *row) +{ + return !((row->flags & PS_LEVEL && !PS_IsLevelActive()) || + (row->flags & PS_SW && rendermode != render_soft) || + (row->flags & PS_HW && rendermode != render_opengl) || + (row->flags & PS_BATCHING && !cv_glbatching.value)); +} +// Should the row be visible on the screen? +static boolean PS_IsRowVisible(perfstatrow_t *row) +{ + boolean value_is_zero; + + if (row->flags & PS_TIME) + value_is_zero = row->metric->value.p == 0; + else + value_is_zero = row->metric->value.i == 0; + + return !(!PS_IsRowValid(row) || + (row->flags & PS_HIDE_ZERO && value_is_zero)); +} + +static INT32 PS_GetMetricAverage(ps_metric_t *metric, boolean time_metric) +{ + char* history_read_pos = metric->history; // char* used for pointer arithmetic + INT64 sum = 0; + int i; + int value_size = time_metric ? sizeof(precise_t) : sizeof(INT32); + + for (i = 0; i < cv_ps_samplesize.value; i++) + { + if (time_metric) + sum += I_PreciseToMicros(*((precise_t*)history_read_pos)); + else + sum += *((INT32*)history_read_pos); + history_read_pos += value_size; + } + + return sum / cv_ps_samplesize.value; +} + +static INT32 PS_GetMetricMinOrMax(ps_metric_t *metric, boolean time_metric, boolean get_max) +{ + char* history_read_pos = metric->history; // char* used for pointer arithmetic + INT32 found_value = get_max ? INT32_MIN : INT32_MAX; + int i; + int value_size = time_metric ? sizeof(precise_t) : sizeof(INT32); + + for (i = 0; i < cv_ps_samplesize.value; i++) + { + INT32 value; + if (time_metric) + value = I_PreciseToMicros(*((precise_t*)history_read_pos)); + else + value = *((INT32*)history_read_pos); + + if ((get_max && value > found_value) || + (!get_max && value < found_value)) + { + found_value = value; + } + history_read_pos += value_size; + } + + return found_value; +} + +// Calculates the standard deviation for metric. +static INT32 PS_GetMetricSD(ps_metric_t *metric, boolean time_metric) +{ + char* history_read_pos = metric->history; // char* used for pointer arithmetic + INT64 sum = 0; + int i; + int value_size = time_metric ? sizeof(precise_t) : sizeof(INT32); + INT32 avg = PS_GetMetricAverage(metric, time_metric); + + for (i = 0; i < cv_ps_samplesize.value; i++) + { + INT64 value; + if (time_metric) + value = I_PreciseToMicros(*((precise_t*)history_read_pos)); + else + value = *((INT32*)history_read_pos); + + value -= avg; + sum += value * value; + + history_read_pos += value_size; + } + + return round(sqrt(sum / cv_ps_samplesize.value)); +} + +// Returns the value to show on screen for metric. +static INT32 PS_GetMetricScreenValue(ps_metric_t *metric, boolean time_metric) +{ + if (cv_ps_samplesize.value > 1 && metric->history) + { + if (cv_ps_descriptor.value == 1) + return PS_GetMetricAverage(metric, time_metric); + else if (cv_ps_descriptor.value == 2) + return PS_GetMetricSD(metric, time_metric); + else if (cv_ps_descriptor.value == 3) + return PS_GetMetricMinOrMax(metric, time_metric, false); + else + return PS_GetMetricMinOrMax(metric, time_metric, true); + } + else + { + if (time_metric) + return I_PreciseToMicros(metric->value.p); + else + return metric->value.i; + } +} + +static int PS_DrawPerfRows(int x, int y, int color, perfstatrow_t *rows) +{ + const boolean hires = PS_HighResolution(); + INT32 draw_flags = V_MONOSPACE | color; perfstatrow_t * row; - - int value; + int draw_y = y; if (hires) draw_flags |= V_ALLOWLOWERCASE; - for (row = col->rows; row->lores_label; ++row) + for (row = rows; row->lores_label; ++row) { - if (type == PERF_TIME) - value = I_PreciseToMicros(*(precise_t *)row->value); - else - value = *(int *)row->value; + const char *label; + INT32 value; + char *final_str; + + if (!PS_IsRowVisible(row)) + continue; + + label = hires ? row->hires_label : row->lores_label; + value = PS_GetMetricScreenValue(row->metric, !!(row->flags & PS_TIME)); + final_str = va("%s %d", label, value); if (hires) { - V_DrawSmallString(col->hires_x, draw_row, draw_flags, - va("%s %d", row->hires_label, value)); - - draw_row += 5; + V_DrawSmallString(x, draw_y, draw_flags, final_str); + draw_y += 5; } else { - V_DrawThinString(col->lores_x, draw_row, draw_flags, - va("%s %d", row->lores_label, value)); - - draw_row += 8; + V_DrawThinString(x, draw_y, draw_flags, final_str); + draw_y += 8; } } + + return draw_y; +} + +static void PS_UpdateMetricHistory(ps_metric_t *metric, boolean time_metric, boolean frame_metric, boolean set_user) +{ + int index = frame_metric ? ps_frame_index : ps_tick_index; + + if (!metric->history) + { + // allocate history table + int value_size = time_metric ? sizeof(precise_t) : sizeof(INT32); + void** memory_user = set_user ? &metric->history : NULL; + + metric->history = Z_Calloc(value_size * cv_ps_samplesize.value, PU_PERFSTATS, + memory_user); + + // reset "samples left" counter since this history table needs to be filled + if (frame_metric) + ps_frame_samples_left = cv_ps_samplesize.value; + else + ps_tick_samples_left = cv_ps_samplesize.value; + } + + if (time_metric) + { + precise_t *history = (precise_t*)metric->history; + history[index] = metric->value.p; + } + else + { + INT32 *history = (INT32*)metric->history; + history[index] = metric->value.i; + } } -static void M_DrawPerfTiming(perfstatcol_t *col) +static void PS_UpdateRowHistories(perfstatrow_t *rows, boolean frame_metric) { - M_DrawPerfString(col, PERF_TIME); -} - -static void M_DrawPerfCount(perfstatcol_t *col) -{ - M_DrawPerfString(col, PERF_COUNT); -} - -static void M_DrawRenderStats(void) -{ - const boolean hires = M_HighResolution(); - - const int half_row = hires ? 5 : 4; - - precise_t extrarendertime; - - perfstatrow_t frametime_row[] = { - {"frmtime", "Frame time: ", &ps_frametime}, - {0} - }; - - perfstatrow_t rendercalltime_row[] = { - {"drwtime", "3d rendering: ", &ps_rendercalltime}, - {0} - }; - - perfstatrow_t opengltime_row[] = { - {"skybox ", "Skybox render: ", &ps_hw_skyboxtime}, - {"bsptime", "RenderBSPNode: ", &ps_bsptime}, - {"nodesrt", "Drwnode sort: ", &ps_hw_nodesorttime}, - {"nodedrw", "Drwnode render:", &ps_hw_nodedrawtime}, - {"sprsort", "Sprite sort: ", &ps_hw_spritesorttime}, - {"sprdraw", "Sprite render: ", &ps_hw_spritedrawtime}, - {"other ", "Other: ", &extrarendertime}, - {0} - }; - - perfstatrow_t softwaretime_row[] = { - {"bsptime", "RenderBSPNode: ", &ps_bsptime}, - {"sprclip", "R_ClipSprites: ", &ps_sw_spritecliptime}, - {"portals", "Portals+Skybox:", &ps_sw_portaltime}, - {"planes ", "R_DrawPlanes: ", &ps_sw_planetime}, - {"masked ", "R_DrawMasked: ", &ps_sw_maskedtime}, - {"other ", "Other: ", &extrarendertime}, - {0} - }; - - perfstatrow_t uiswaptime_row[] = { - {"ui ", "UI render: ", &ps_uitime}, - {"finupdt", "I_FinishUpdate:", &ps_swaptime}, - {0} - }; - - perfstatrow_t tictime_row[] = { - {"logic ", "Game logic: ", &ps_tictime}, - {0} - }; - - perfstatrow_t rendercalls_row[] = { - {"bspcall", "BSP calls: ", &ps_numbspcalls}, - {"sprites", "Sprites: ", &ps_numsprites}, - {"drwnode", "Drawnodes: ", &ps_numdrawnodes}, - {"plyobjs", "Polyobjects: ", &ps_numpolyobjects}, - {0} - }; - - perfstatrow_t batchtime_row[] = { - {"batsort", "Batch sort: ", &ps_hw_batchsorttime}, - {"batdraw", "Batch render:", &ps_hw_batchdrawtime}, - {0} - }; - - perfstatrow_t batchcount_row[] = { - {"polygon", "Polygons: ", &ps_hw_numpolys}, - {"vertex ", "Vertices: ", &ps_hw_numverts}, - {0} - }; - - perfstatrow_t batchcalls_row[] = { - {"drwcall", "Draw calls:", &ps_hw_numcalls}, - {"shaders", "Shaders: ", &ps_hw_numshaders}, - {"texture", "Textures: ", &ps_hw_numtextures}, - {"polyflg", "Polyflags: ", &ps_hw_numpolyflags}, - {"colors ", "Colors: ", &ps_hw_numcolors}, - {0} - }; - - perfstatcol_t frametime_col = {20, 20, V_YELLOWMAP, frametime_row}; - perfstatcol_t rendercalltime_col = {20, 20, V_YELLOWMAP, rendercalltime_row}; - - perfstatcol_t opengltime_col = {24, 24, V_YELLOWMAP, opengltime_row}; - perfstatcol_t softwaretime_col = {24, 24, V_YELLOWMAP, softwaretime_row}; - - perfstatcol_t uiswaptime_col = {20, 20, V_YELLOWMAP, uiswaptime_row}; - perfstatcol_t tictime_col = {20, 20, V_GRAYMAP, tictime_row}; - - perfstatcol_t rendercalls_col = {90, 115, V_BLUEMAP, rendercalls_row}; - - perfstatcol_t batchtime_col = {90, 115, V_REDMAP, batchtime_row}; - - perfstatcol_t batchcount_col = {155, 200, V_PURPLEMAP, batchcount_row}; - perfstatcol_t batchcalls_col = {220, 200, V_PURPLEMAP, batchcalls_row}; - - - boolean rendering = ( - gamestate == GS_LEVEL || - (gamestate == GS_TITLESCREEN && titlemapinaction) - ); - - draw_row = 10; - M_DrawPerfTiming(&frametime_col); - - if (rendering) + perfstatrow_t *row; + for (row = rows; row->lores_label; row++) { - M_DrawPerfTiming(&rendercalltime_col); + if (PS_IsRowValid(row)) + PS_UpdateMetricHistory(row->metric, !!(row->flags & PS_TIME), frame_metric, true); + } +} +// Update all metrics that are calculated on every frame. +static void PS_UpdateFrameStats(void) +{ + // update frame time + precise_t currenttime = I_GetPreciseTime(); + ps_frametime.value.p = currenttime - ps_prevframetime; + ps_prevframetime = currenttime; + + // update 3d rendering stats + if (PS_IsLevelActive()) + { // Remember to update this calculation when adding more 3d rendering stats! - extrarendertime = ps_rendercalltime - ps_bsptime; + ps_otherrendertime.value.p = ps_rendercalltime.value.p - ps_bsptime.value.p; #ifdef HWRENDER if (rendermode == render_opengl) { - extrarendertime -= - ps_hw_skyboxtime + - ps_hw_nodesorttime + - ps_hw_nodedrawtime + - ps_hw_spritesorttime + - ps_hw_spritedrawtime; + ps_otherrendertime.value.p -= + ps_hw_skyboxtime.value.p + + ps_hw_nodesorttime.value.p + + ps_hw_nodedrawtime.value.p + + ps_hw_spritesorttime.value.p + + ps_hw_spritedrawtime.value.p; if (cv_glbatching.value) { - extrarendertime -= - ps_hw_batchsorttime + - ps_hw_batchdrawtime; + ps_otherrendertime.value.p -= + ps_hw_batchsorttime.value.p + + ps_hw_batchdrawtime.value.p; } - - M_DrawPerfTiming(&opengltime_col); } else #endif { - extrarendertime -= - ps_sw_spritecliptime + - ps_sw_portaltime + - ps_sw_planetime + - ps_sw_maskedtime; - - M_DrawPerfTiming(&softwaretime_col); + ps_otherrendertime.value.p -= + ps_sw_spritecliptime.value.p + + ps_sw_portaltime.value.p + + ps_sw_planetime.value.p + + ps_sw_maskedtime.value.p; } } - M_DrawPerfTiming(&uiswaptime_col); - - draw_row += half_row; - M_DrawPerfTiming(&tictime_col); - - if (rendering) + if (cv_ps_samplesize.value > 1) { - draw_row = 10; - M_DrawPerfCount(&rendercalls_col); + PS_UpdateRowHistories(rendertime_rows, true); + if (PS_IsLevelActive()) + PS_UpdateRowHistories(commoncounter_rows, true); #ifdef HWRENDER if (rendermode == render_opengl && cv_glbatching.value) { - draw_row += half_row; - M_DrawPerfTiming(&batchtime_col); - - draw_row = 10; - M_DrawPerfCount(&batchcount_col); - - if (hires) - draw_row += half_row; - else - draw_row = 10; - - M_DrawPerfCount(&batchcalls_col); + PS_UpdateRowHistories(batchcount_rows, true); + PS_UpdateRowHistories(batchcalls_rows, true); } #endif + + ps_frame_index++; + if (ps_frame_index >= cv_ps_samplesize.value) + ps_frame_index = 0; + if (ps_frame_samples_left) + ps_frame_samples_left--; } } -static void M_DrawTickStats(void) +// Update thinker counters by iterating the thinker lists. +static void PS_CountThinkers(void) { - int i = 0; + int i; thinker_t *thinker; - int thinkercount = 0; - int polythcount = 0; - int mainthcount = 0; - int mobjcount = 0; - int nothinkcount = 0; - int scenerycount = 0; - int regularcount = 0; - int dynslopethcount = 0; - int precipcount = 0; - int removecount = 0; - precise_t extratime = - ps_tictime - - ps_playerthink_time - - ps_thinkertime - - ps_lua_thinkframe_time; - - perfstatrow_t tictime_row[] = { - {"logic ", "Game logic: ", &ps_tictime}, - {0} - }; - - perfstatrow_t thinker_time_row[] = { - {"plrthnk", "P_PlayerThink: ", &ps_playerthink_time}, - {"thnkers", "P_RunThinkers: ", &ps_thinkertime}, - {0} - }; - - perfstatrow_t detailed_thinker_time_row[] = { - {"plyobjs", "Polyobjects: ", &ps_thlist_times[THINK_POLYOBJ]}, - {"main ", "Main: ", &ps_thlist_times[THINK_MAIN]}, - {"mobjs ", "Mobjs: ", &ps_thlist_times[THINK_MOBJ]}, - {"dynslop", "Dynamic slopes: ", &ps_thlist_times[THINK_DYNSLOPE]}, - {"precip ", "Precipitation: ", &ps_thlist_times[THINK_PRECIP]}, - {0} - }; - - perfstatrow_t extra_thinker_time_row[] = { - {"lthinkf", "LUAh_ThinkFrame:", &ps_lua_thinkframe_time}, - {"other ", "Other: ", &extratime}, - {0} - }; - - perfstatrow_t thinkercount_row[] = { - {"thnkers", "Thinkers: ", &thinkercount}, - {0} - }; - - perfstatrow_t detailed_thinkercount_row[] = { - {"plyobjs", "Polyobjects: ", &polythcount}, - {"main ", "Main: ", &mainthcount}, - {"mobjs ", "Mobjs: ", &mobjcount}, - {0} - }; - - perfstatrow_t mobjthinkercount_row[] = { - {"regular", "Regular: ", ®ularcount}, - {"scenery", "Scenery: ", &scenerycount}, - {0} - }; - - perfstatrow_t nothinkcount_row[] = { - {"nothink", "Nothink: ", ¬hinkcount}, - {0} - }; - - perfstatrow_t detailed_thinkercount_row2[] = { - {"dynslop", "Dynamic slopes: ", &dynslopethcount}, - {"precip ", "Precipitation: ", &precipcount}, - {"remove ", "Pending removal:", &removecount}, - {0} - }; - - perfstatrow_t misc_calls_row[] = { - {"lmhook", "Lua mobj hooks: ", &ps_lua_mobjhooks}, - {"chkpos", "P_CheckPosition:", &ps_checkposition_calls}, - {0} - }; - - perfstatcol_t tictime_col = {20, 20, V_YELLOWMAP, tictime_row}; - perfstatcol_t thinker_time_col = {24, 24, V_YELLOWMAP, thinker_time_row}; - perfstatcol_t detailed_thinker_time_col = {28, 28, V_YELLOWMAP, detailed_thinker_time_row}; - perfstatcol_t extra_thinker_time_col = {24, 24, V_YELLOWMAP, extra_thinker_time_row}; - - perfstatcol_t thinkercount_col = {90, 115, V_BLUEMAP, thinkercount_row}; - perfstatcol_t detailed_thinkercount_col = {94, 119, V_BLUEMAP, detailed_thinkercount_row}; - perfstatcol_t mobjthinkercount_col = {98, 123, V_BLUEMAP, mobjthinkercount_row}; - perfstatcol_t nothinkcount_col = {98, 123, V_BLUEMAP, nothinkcount_row}; - perfstatcol_t detailed_thinkercount_col2 = {94, 119, V_BLUEMAP, detailed_thinkercount_row2}; - perfstatcol_t misc_calls_col = {170, 216, V_PURPLEMAP, misc_calls_row}; + ps_thinkercount.value.i = 0; + ps_polythcount.value.i = 0; + ps_mainthcount.value.i = 0; + ps_mobjcount.value.i = 0; + ps_regularcount.value.i = 0; + ps_scenerycount.value.i = 0; + ps_nothinkcount.value.i = 0; + ps_dynslopethcount.value.i = 0; + ps_precipcount.value.i = 0; + ps_removecount.value.i = 0; for (i = 0; i < NUM_THINKERLISTS; i++) { for (thinker = thlist[i].next; thinker != &thlist[i]; thinker = thinker->next) { - thinkercount++; + ps_thinkercount.value.i++; if (thinker->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - removecount++; + ps_removecount.value.i++; else if (i == THINK_POLYOBJ) - polythcount++; + ps_polythcount.value.i++; else if (i == THINK_MAIN) - mainthcount++; + ps_mainthcount.value.i++; else if (i == THINK_MOBJ) { if (thinker->function.acp1 == (actionf_p1)P_MobjThinker) { mobj_t *mobj = (mobj_t*)thinker; - mobjcount++; + ps_mobjcount.value.i++; if (mobj->flags & MF_NOTHINK) - nothinkcount++; + ps_nothinkcount.value.i++; else if (mobj->flags & MF_SCENERY) - scenerycount++; + ps_scenerycount.value.i++; else - regularcount++; + ps_regularcount.value.i++; } } else if (i == THINK_DYNSLOPE) - dynslopethcount++; + ps_dynslopethcount.value.i++; else if (i == THINK_PRECIP) - precipcount++; + ps_precipcount.value.i++; } } +} - draw_row = 10; - M_DrawPerfTiming(&tictime_col); - M_DrawPerfTiming(&thinker_time_col); - M_DrawPerfTiming(&detailed_thinker_time_col); - M_DrawPerfTiming(&extra_thinker_time_col); - - draw_row = 10; - M_DrawPerfCount(&thinkercount_col); - M_DrawPerfCount(&detailed_thinkercount_col); - M_DrawPerfCount(&mobjthinkercount_col); - - if (nothinkcount) - M_DrawPerfCount(¬hinkcount_col); - - M_DrawPerfCount(&detailed_thinkercount_col2); - - if (M_HighResolution()) +// Update all metrics that are calculated on every tick. +void PS_UpdateTickStats(void) +{ + if (cv_perfstats.value == 1 && cv_ps_samplesize.value > 1) { + PS_UpdateRowHistories(gamelogicbrief_row, false); + } + if (cv_perfstats.value == 2) + { + if (PS_IsLevelActive()) + { + ps_otherlogictime.value.p = + ps_tictime.value.p - + ps_playerthink_time.value.p - + ps_thinkertime.value.p - + ps_lua_thinkframe_time.value.p; + + PS_CountThinkers(); + } + + if (cv_ps_samplesize.value > 1) + { + PS_UpdateRowHistories(gamelogic_rows, false); + PS_UpdateRowHistories(thinkercount_rows, false); + PS_UpdateRowHistories(misc_calls_rows, false); + } + } + if (cv_perfstats.value == 3 && cv_ps_samplesize.value > 1 && PS_IsLevelActive()) + { + int i; + for (i = 0; i < thinkframe_hooks_length; i++) + { + PS_UpdateMetricHistory(&thinkframe_hooks[i].time_taken, true, false, false); + } + } + if (cv_perfstats.value && cv_ps_samplesize.value > 1) + { + ps_tick_index++; + if (ps_tick_index >= cv_ps_samplesize.value) + ps_tick_index = 0; + if (ps_tick_samples_left) + ps_tick_samples_left--; + } +} + +static void PS_DrawDescriptorHeader(void) +{ + if (cv_ps_samplesize.value > 1) + { + const char* descriptor_names[] = { + "average", + "standard deviation", + "minimum", + "maximum" + }; + const boolean hires = PS_HighResolution(); + char* str; + INT32 flags = V_MONOSPACE | V_ALLOWLOWERCASE; + int samples_left = max(ps_frame_samples_left, ps_tick_samples_left); + int x, y; + + if (cv_perfstats.value == 3) + { + x = 2; + y = 0; + } + else + { + x = 20; + y = hires ? 5 : 2; + } + + if (samples_left) + { + str = va("Samples needed for correct results: %d", samples_left); + flags |= V_REDMAP; + } + else + { + str = va("Showing the %s of %d samples.", + descriptor_names[cv_ps_descriptor.value - 1], cv_ps_samplesize.value); + flags |= V_GREENMAP; + } + + if (hires) + V_DrawSmallString(x, y, flags, str); + else + V_DrawThinString(x, y, flags, str); + } +} + +static void PS_DrawRenderStats(void) +{ + const boolean hires = PS_HighResolution(); + const int half_row = hires ? 5 : 4; + int x, y; + + PS_DrawDescriptorHeader(); + + y = PS_DrawPerfRows(20, 10, V_YELLOWMAP, rendertime_rows); + + PS_DrawPerfRows(20, y + half_row, V_GRAYMAP, gamelogicbrief_row); + + if (PS_IsLevelActive()) + { + x = hires ? 115 : 90; + PS_DrawPerfRows(x, 10, V_BLUEMAP, commoncounter_rows); + +#ifdef HWRENDER + if (rendermode == render_opengl && cv_glbatching.value) + { + x = hires ? 200 : 155; + y = PS_DrawPerfRows(x, 10, V_PURPLEMAP, batchcount_rows); + + x = hires ? 200 : 220; + y = hires ? y + half_row : 10; + PS_DrawPerfRows(x, y, V_PURPLEMAP, batchcalls_rows); + } +#endif + } +} + +static void PS_DrawGameLogicStats(void) +{ + const boolean hires = PS_HighResolution(); + int x, y; + + PS_DrawDescriptorHeader(); + + PS_DrawPerfRows(20, 10, V_YELLOWMAP, gamelogic_rows); + + x = hires ? 115 : 90; + PS_DrawPerfRows(x, 10, V_BLUEMAP, thinkercount_rows); + + if (hires) V_DrawSmallString(212, 10, V_MONOSPACE | V_ALLOWLOWERCASE | V_PURPLEMAP, "Calls:"); - draw_row = 15; - } - else - { - draw_row = 10; - } + x = hires ? 216 : 170; + y = hires ? 15 : 10; + PS_DrawPerfRows(x, y, V_PURPLEMAP, misc_calls_rows); +} - M_DrawPerfCount(&misc_calls_col); +static void PS_DrawThinkFrameStats(void) +{ + char s[100]; + int i; + // text writing position + int x = 2; + int y = 4; + UINT32 text_color; + char tempbuffer[LUA_IDSIZE]; + char last_mod_name[LUA_IDSIZE]; + last_mod_name[0] = '\0'; + + PS_DrawDescriptorHeader(); + + for (i = 0; i < thinkframe_hooks_length; i++) + { + +#define NEXT_ROW() \ +y += 4; \ +if (y > 192) \ +{ \ + y = 4; \ + x += 106; \ + if (x > 214) \ + break; \ +} + + char* str = thinkframe_hooks[i].short_src; + char* tempstr = tempbuffer; + int len = (int)strlen(str); + char* str_ptr; + if (strcmp(".lua", str + len - 4) == 0) + { + str[len-4] = '\0'; // remove .lua at end + len -= 4; + } + // we locate the wad/pk3 name in the string and compare it to + // what we found on the previous iteration. + // if the name has changed, print it out on the screen + strcpy(tempstr, str); + str_ptr = strrchr(tempstr, '|'); + if (str_ptr) + { + *str_ptr = '\0'; + str = str_ptr + 1; // this is the name of the hook without the mod file name + str_ptr = strrchr(tempstr, PATHSEP[0]); + if (str_ptr) + tempstr = str_ptr + 1; + // tempstr should now point to the mod name, (wad/pk3) possibly truncated + if (strcmp(tempstr, last_mod_name) != 0) + { + strcpy(last_mod_name, tempstr); + len = (int)strlen(tempstr); + if (len > 25) + tempstr += len - 25; + snprintf(s, sizeof s - 1, "%s", tempstr); + V_DrawSmallString(x, y, V_MONOSPACE | V_ALLOWLOWERCASE | V_GRAYMAP, s); + NEXT_ROW() + } + text_color = V_YELLOWMAP; + } + else + { + // probably a standalone lua file + // cut off the folder if it's there + str_ptr = strrchr(tempstr, PATHSEP[0]); + if (str_ptr) + str = str_ptr + 1; + text_color = 0; // white + } + len = (int)strlen(str); + if (len > 20) + str += len - 20; + snprintf(s, sizeof s - 1, "%20s: %d", str, + PS_GetMetricScreenValue(&thinkframe_hooks[i].time_taken, true)); + V_DrawSmallString(x, y, V_MONOSPACE | V_ALLOWLOWERCASE | text_color, s); + NEXT_ROW() + +#undef NEXT_ROW + + } } void M_DrawPerfStats(void) { - char s[100]; - - PS_SetFrameTime(); - if (cv_perfstats.value == 1) // rendering { - M_DrawRenderStats(); + PS_UpdateFrameStats(); + PS_DrawRenderStats(); } else if (cv_perfstats.value == 2) // logic { - M_DrawTickStats(); + // PS_UpdateTickStats is called in TryRunTics, since otherwise it would miss + // tics when frame skips happen + PS_DrawGameLogicStats(); } else if (cv_perfstats.value == 3) // lua thinkframe { - if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))) + if (!PS_IsLevelActive()) return; - if (vid.width < 640 || vid.height < 400) // low resolution + if (!PS_HighResolution()) { - // it's not gonna fit very well.. - V_DrawThinString(30, 30, V_MONOSPACE | V_ALLOWLOWERCASE | V_YELLOWMAP, "Not available for resolutions below 640x400"); + // Low resolutions can't really use V_DrawSmallString that is used by thinkframe stats. + // A low-res version using V_DrawThinString could be implemented, + // but it would have much less space for information. + V_DrawThinString(80, 92, V_MONOSPACE | V_ALLOWLOWERCASE | V_YELLOWMAP, "Perfstats 3 is not available"); + V_DrawThinString(80, 100, V_MONOSPACE | V_ALLOWLOWERCASE | V_YELLOWMAP, "for resolutions below 640x400."); } - else // high resolution + else { - int i; - // text writing position - int x = 2; - int y = 4; - UINT32 text_color; - char tempbuffer[LUA_IDSIZE]; - char last_mod_name[LUA_IDSIZE]; - last_mod_name[0] = '\0'; - for (i = 0; i < thinkframe_hooks_length; i++) - { - char* str = thinkframe_hooks[i].short_src; - char* tempstr = tempbuffer; - int len = (int)strlen(str); - char* str_ptr; - if (strcmp(".lua", str + len - 4) == 0) - { - str[len-4] = '\0'; // remove .lua at end - len -= 4; - } - // we locate the wad/pk3 name in the string and compare it to - // what we found on the previous iteration. - // if the name has changed, print it out on the screen - strcpy(tempstr, str); - str_ptr = strrchr(tempstr, '|'); - if (str_ptr) - { - *str_ptr = '\0'; - str = str_ptr + 1; // this is the name of the hook without the mod file name - str_ptr = strrchr(tempstr, PATHSEP[0]); - if (str_ptr) - tempstr = str_ptr + 1; - // tempstr should now point to the mod name, (wad/pk3) possibly truncated - if (strcmp(tempstr, last_mod_name) != 0) - { - strcpy(last_mod_name, tempstr); - len = (int)strlen(tempstr); - if (len > 25) - tempstr += len - 25; - snprintf(s, sizeof s - 1, "%s", tempstr); - V_DrawSmallString(x, y, V_MONOSPACE | V_ALLOWLOWERCASE | V_GRAYMAP, s); - y += 4; // repeated code! - if (y > 192) - { - y = 4; - x += 106; - if (x > 214) - break; - } - } - text_color = V_YELLOWMAP; - } - else - { - // probably a standalone lua file - // cut off the folder if it's there - str_ptr = strrchr(tempstr, PATHSEP[0]); - if (str_ptr) - str = str_ptr + 1; - text_color = 0; // white - } - len = (int)strlen(str); - if (len > 20) - str += len - 20; - snprintf(s, sizeof s - 1, "%20s: %d", str, I_PreciseToMicros(thinkframe_hooks[i].time_taken)); - V_DrawSmallString(x, y, V_MONOSPACE | V_ALLOWLOWERCASE | text_color, s); - y += 4; // repeated code! - if (y > 192) - { - y = 4; - x += 106; - if (x > 214) - break; - } - } + PS_DrawThinkFrameStats(); } } } + +// remove and unallocate history from all metrics +static void PS_ClearHistory(void) +{ + int i; + + Z_FreeTag(PU_PERFSTATS); + // thinkframe hook metric history pointers need to be cleared manually + for (i = 0; i < thinkframe_hooks_length; i++) + { + thinkframe_hooks[i].time_taken.history = NULL; + } + + ps_frame_index = ps_tick_index = 0; + // PS_UpdateMetricHistory will set these correctly when it runs + ps_frame_samples_left = ps_tick_samples_left = 0; +} + +void PS_PerfStats_OnChange(void) +{ + if (cv_perfstats.value && cv_ps_samplesize.value > 1) + PS_ClearHistory(); +} + +void PS_SampleSize_OnChange(void) +{ + if (cv_ps_samplesize.value > 1) + PS_ClearHistory(); +} diff --git a/src/m_perfstats.h b/src/m_perfstats.h index 71208fbc1..3ff0e6c6b 100644 --- a/src/m_perfstats.h +++ b/src/m_perfstats.h @@ -16,26 +16,45 @@ #include "lua_script.h" #include "p_local.h" -extern precise_t ps_tictime; - -extern precise_t ps_playerthink_time; -extern precise_t ps_thinkertime; - -extern precise_t ps_thlist_times[]; - -extern int ps_checkposition_calls; - -extern precise_t ps_lua_thinkframe_time; -extern int ps_lua_mobjhooks; +typedef struct +{ + union { + precise_t p; + INT32 i; + } value; + void *history; +} ps_metric_t; typedef struct { - precise_t time_taken; + ps_metric_t time_taken; char short_src[LUA_IDSIZE]; } ps_hookinfo_t; +#define PS_START_TIMING(metric) metric.value.p = I_GetPreciseTime() +#define PS_STOP_TIMING(metric) metric.value.p = I_GetPreciseTime() - metric.value.p + +extern ps_metric_t ps_tictime; + +extern ps_metric_t ps_playerthink_time; +extern ps_metric_t ps_thinkertime; + +extern ps_metric_t ps_thlist_times[]; + +extern ps_metric_t ps_checkposition_calls; + +extern ps_metric_t ps_lua_thinkframe_time; +extern ps_metric_t ps_lua_mobjhooks; + +extern ps_metric_t ps_otherlogictime; + void PS_SetThinkFrameHookInfo(int index, precise_t time_taken, char* short_src); +void PS_UpdateTickStats(void); + void M_DrawPerfStats(void); +void PS_PerfStats_OnChange(void); +void PS_SampleSize_OnChange(void); + #endif diff --git a/src/p_enemy.c b/src/p_enemy.c index e79baa679..1216bb095 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3518,9 +3518,7 @@ void A_Scream(mobj_t *actor) if (LUA_CallAction(A_SCREAM, actor)) return; - if (actor->tracer && (actor->tracer->type == MT_SHELL || actor->tracer->type == MT_FIREBALL)) - S_StartScreamSound(actor, sfx_mario2); - else if (actor->info->deathsound) + if (actor->info->deathsound && !S_SoundPlaying(actor, sfx_mario2)) S_StartScreamSound(actor, actor->info->deathsound); } @@ -5284,7 +5282,7 @@ void A_OverlayThink(mobj_t *actor) actor->z = actor->target->z + actor->target->height - mobjinfo[actor->type].height - ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT; else actor->z = actor->target->z + ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT; - actor->angle = actor->target->angle + actor->movedir; + actor->angle = (actor->target->player ? actor->target->player->drawangle : actor->target->angle) + actor->movedir; actor->eflags = actor->target->eflags; actor->momx = actor->target->momx; diff --git a/src/p_floor.c b/src/p_floor.c index 6a4ef554e..b587c169f 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -988,6 +988,7 @@ static mobj_t *SearchMarioNode(msecnode_t *node) case MT_THUNDERCOIN_ORB: case MT_IVSP: case MT_SUPERSPARK: + case MT_BOXSPARKLE: case MT_RAIN: case MT_SNOWFLAKE: case MT_SPLISH: diff --git a/src/p_inter.c b/src/p_inter.c index d7f0fb8a2..d84cb8ce5 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2385,7 +2385,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget mobj_t *mo; if (inflictor && (inflictor->type == MT_SHELL || inflictor->type == MT_FIREBALL)) - P_SetTarget(&target->tracer, inflictor); + S_StartScreamSound(target, sfx_mario2); if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && target->player && target->player->nightstime > 6) target->player->nightstime = 6; // Just let P_Ticker take care of the rest. @@ -3645,7 +3645,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return true; } - if (!force && inflictor && inflictor->flags & MF_FIRE) + if (!force && inflictor && inflictor->flags & MF_FIRE && !(damagetype && damagetype != DMG_FIRE)) { if (player->powers[pw_shield] & SH_PROTECTFIRE) return false; // Invincible to fire objects diff --git a/src/p_map.c b/src/p_map.c index e55bebb9a..836e75c4e 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1156,7 +1156,7 @@ static boolean PIT_CheckThing(mobj_t *thing) else thing->z = tmthing->z + tmthing->height + FixedMul(FRACUNIT, tmthing->scale); if (thing->flags & MF_SHOOTABLE) - P_DamageMobj(thing, tmthing, tmthing, 1, 0); + P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE); return true; } @@ -2029,7 +2029,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) subsector_t *newsubsec; boolean blockval = true; - ps_checkposition_calls++; + ps_checkposition_calls.value.i++; I_Assert(thing != NULL); #ifdef PARANOIA diff --git a/src/p_mobj.c b/src/p_mobj.c index a0a48ab6d..da0bde867 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -78,7 +78,7 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum) // // P_SetupStateAnimation // -FUNCINLINE static ATTRINLINE void P_SetupStateAnimation(mobj_t *mobj, state_t *st) +static void P_SetupStateAnimation(mobj_t *mobj, state_t *st) { INT32 animlength = (mobj->sprite == SPR_PLAY && mobj->skin) ? (INT32)(((skin_t *)mobj->skin)->sprites[mobj->sprite2].numframes) - 1 @@ -1688,7 +1688,7 @@ static void P_PushableCheckBustables(mobj_t *mo) if (!(rover->flags & FF_BUSTUP)) continue; - if (!(rover->specialflags & FS_PUSHABLES)) + if (!(rover->bustflags & FB_PUSHABLES)) continue; if (rover->master->frontsector->crumblestate != CRUMBLE_NONE) @@ -1698,7 +1698,7 @@ static void P_PushableCheckBustables(mobj_t *mo) bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL); // Height checks - if (rover->specialflags & FS_ONLYBOTTOM) + if (rover->bustflags & FB_ONLYBOTTOM) { if (mo->z + mo->momz + mo->height < bottomheight) continue; @@ -1740,7 +1740,7 @@ static void P_PushableCheckBustables(mobj_t *mo) EV_CrumbleChain(NULL, rover); // node->m_sector // Run a linedef executor?? - if (rover->specialflags & FS_EXECUTOR) + if (rover->bustflags & FB_EXECUTOR) P_LinedefExecute(rover->busttag, mo, node->m_sector); goto bustupdone; @@ -3241,8 +3241,8 @@ void P_MobjCheckWater(mobj_t *mobj) || ((rover->flags & FF_BLOCKOTHERS) && !mobj->player))) continue; - topheight = P_GetFFloorTopZAt (rover, mobj->x, mobj->y); - bottomheight = P_GetFFloorBottomZAt(rover, mobj->x, mobj->y); + topheight = P_GetSpecialTopZ(mobj, sectors + rover->secnum, sector); + bottomheight = P_GetSpecialBottomZ(mobj, sectors + rover->secnum, sector); if (mobj->eflags & MFE_VERTICALFLIP) { @@ -6842,7 +6842,7 @@ void P_RunOverlays(void) mo->eflags = (mo->eflags & ~MFE_VERTICALFLIP) | (mo->target->eflags & MFE_VERTICALFLIP); mo->scale = mo->destscale = mo->target->scale; - mo->angle = mo->target->angle + mo->movedir; + mo->angle = (mo->target->player ? mo->target->player->drawangle : mo->target->angle) + mo->movedir; if (!(mo->state->frame & FF_ANIMATE)) zoffs = FixedMul(((signed)mo->state->var2)*FRACUNIT, mo->scale); diff --git a/src/p_setup.c b/src/p_setup.c index ce0e27e38..ab0254c08 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3284,8 +3284,6 @@ static void P_ConvertBinaryMap(void) case 76: //Make FOF bouncy lines[i].args[0] = tag; lines[i].args[1] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; - if (lines[i].flags & ML_BOUNCY) - lines[i].args[2] = 1; break; case 100: //FOF: solid, opaque, shadowcasting case 101: //FOF: solid, opaque, non-shadowcasting diff --git a/src/p_spec.c b/src/p_spec.c index 9d2734270..c2caeb859 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2078,7 +2078,7 @@ void P_SwitchWeather(INT32 weathernum) continue; // not a precipmobj thinker precipmobj = (precipmobj_t *)think; - if (weathernum == (PRECIP_RAIN || PRECIP_STORM || PRECIP_STORM_NOSTRIKES)) // Snow To Rain + if (weathernum == PRECIP_RAIN || weathernum == PRECIP_STORM || weathernum == PRECIP_STORM_NOSTRIKES) // Snow To Rain { precipmobj->flags = mobjinfo[MT_RAIN].flags; st = &states[mobjinfo[MT_RAIN].spawnstate]; @@ -5903,10 +5903,6 @@ static void P_MakeFOFBouncy(line_t *paramline, line_t *masterline) rover->flags |= FF_BOUNCY; rover->spawnflags |= FF_BOUNCY; rover->bouncestrength = (paramline->args[1]<< FRACBITS)/100; - if (paramline->args[2]) - rover->specialflags |= FS_DAMPEN; - else - rover->specialflags &= ~FS_DAMPEN; CheckForBouncySector = true; break; } @@ -6536,7 +6532,7 @@ void P_SpawnSpecials(boolean fromnetsave) case 254: // Bustable block { UINT8 busttype = BT_REGULAR; - ffloorspecialflags_e bustflags = 0; + ffloorbustflags_e bustflags = 0; ffloorflags = FF_EXISTS|FF_BLOCKOTHERS|FF_RENDERALL|FF_BUSTUP; @@ -6559,15 +6555,15 @@ void P_SpawnSpecials(boolean fromnetsave) //Flags if (lines[i].args[3] & TMFB_PUSHABLES) - bustflags |= FS_PUSHABLES; + bustflags |= FB_PUSHABLES; if (lines[i].args[3] & TMFB_EXECUTOR) - bustflags |= FS_EXECUTOR; + bustflags |= FB_EXECUTOR; if (lines[i].args[3] & TMFB_ONLYBOTTOM) - bustflags |= FS_ONLYBOTTOM; + bustflags |= FB_ONLYBOTTOM; if (lines[i].args[3] & TMFB_SPLAT) ffloorflags |= FF_SPLAT; - if (busttype != BT_TOUCH || bustflags & FS_ONLYBOTTOM) + if (busttype != BT_TOUCH || bustflags & FB_ONLYBOTTOM) ffloorflags |= FF_BLOCKPLAYER; TAG_ITER_SECTORS(lines[i].args[0], s) @@ -6575,8 +6571,8 @@ void P_SpawnSpecials(boolean fromnetsave) ffloor_t *fflr = P_AddFakeFloor(§ors[s], lines[i].frontsector, lines + i, lines[i].args[1], ffloorflags, secthinkers); if (!fflr) continue; + fflr->bustflags = bustflags; fflr->busttype = busttype; - fflr->specialflags = bustflags; fflr->busttag = lines[i].args[4]; } break; @@ -6636,12 +6632,12 @@ void P_SpawnSpecials(boolean fromnetsave) } if (lines[i].args[3] & TMFB_ONLYBOTTOM) - fflr->specialflags |= FS_ONLYBOTTOM; + fflr->bustflags |= FB_ONLYBOTTOM; if (lines[i].flags & ML_EFFECT4) - fflr->specialflags |= FS_PUSHABLES; + fflr->bustflags |= FB_PUSHABLES; if (lines[i].flags & ML_EFFECT5) { - fflr->specialflags |= FS_EXECUTOR; + fflr->bustflags |= FB_EXECUTOR; fflr->busttag = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; } } @@ -6962,7 +6958,7 @@ void P_SpawnSpecials(boolean fromnetsave) case 74: // Make FOF bustable { UINT8 busttype = BT_REGULAR; - ffloorspecialflags_e bustflags = 0; + ffloorbustflags_e bustflags = 0; if (!udmf) break; @@ -6984,11 +6980,11 @@ void P_SpawnSpecials(boolean fromnetsave) } if (lines[i].args[2] & TMFB_PUSHABLES) - bustflags |= FS_PUSHABLES; + bustflags |= FB_PUSHABLES; if (lines[i].args[2] & TMFB_EXECUTOR) - bustflags |= FS_EXECUTOR; + bustflags |= FB_EXECUTOR; if (lines[i].args[2] & TMFB_ONLYBOTTOM) - bustflags |= FS_ONLYBOTTOM; + bustflags |= FB_ONLYBOTTOM; TAG_ITER_LINES(lines[i].args[0], l) { @@ -7006,9 +7002,8 @@ void P_SpawnSpecials(boolean fromnetsave) rover->flags |= FF_BUSTUP; rover->spawnflags |= FF_BUSTUP; + rover->bustflags = bustflags; rover->busttype = busttype; - rover->specialflags &= ~FS_BUSTMASK; - rover->specialflags |= bustflags; rover->busttag = lines[i].args[3]; CheckForBustableBlocks = true; break; diff --git a/src/p_tick.c b/src/p_tick.c index 1a8242db7..d34272045 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -329,7 +329,7 @@ static inline void P_RunThinkers(void) size_t i; for (i = 0; i < NUM_THINKERLISTS; i++) { - ps_thlist_times[i] = I_GetPreciseTime(); + PS_START_TIMING(ps_thlist_times[i]); for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = currentthinker->next) { #ifdef PARANOIA @@ -337,7 +337,7 @@ static inline void P_RunThinkers(void) #endif currentthinker->function.acp1(currentthinker); } - ps_thlist_times[i] = I_GetPreciseTime() - ps_thlist_times[i]; + PS_STOP_TIMING(ps_thlist_times[i]); } } @@ -493,7 +493,7 @@ static inline void P_DoSpecialStageStuff(void) continue; // If in water, deplete timer 6x as fast. - if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(players[i].powers[pw_shield] & SH_PROTECTWATER)) + if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(players[i].powers[pw_shield] & ((players[i].mo->eflags & MFE_TOUCHLAVA) ? SH_PROTECTFIRE : SH_PROTECTWATER))) players[i].nightstime -= 5; if (--players[i].nightstime > 6) { @@ -659,16 +659,16 @@ void P_Ticker(boolean run) } } - ps_lua_mobjhooks = 0; - ps_checkposition_calls = 0; + ps_lua_mobjhooks.value.i = 0; + ps_checkposition_calls.value.i = 0; LUA_HOOK(PreThinkFrame); - ps_playerthink_time = I_GetPreciseTime(); + PS_START_TIMING(ps_playerthink_time); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerThink(&players[i]); - ps_playerthink_time = I_GetPreciseTime() - ps_playerthink_time; + PS_STOP_TIMING(ps_playerthink_time); } // Keep track of how long they've been playing! @@ -683,18 +683,18 @@ void P_Ticker(boolean run) if (run) { - ps_thinkertime = I_GetPreciseTime(); + PS_START_TIMING(ps_thinkertime); P_RunThinkers(); - ps_thinkertime = I_GetPreciseTime() - ps_thinkertime; + PS_STOP_TIMING(ps_thinkertime); // Run any "after all the other thinkers" stuff for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerAfterThink(&players[i]); - ps_lua_thinkframe_time = I_GetPreciseTime(); + PS_START_TIMING(ps_lua_thinkframe_time); LUA_HookThinkFrame(); - ps_lua_thinkframe_time = I_GetPreciseTime() - ps_lua_thinkframe_time; + PS_STOP_TIMING(ps_lua_thinkframe_time); } // Run shield positioning diff --git a/src/p_user.c b/src/p_user.c index 9f3737501..9921ed078 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -777,7 +777,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) UINT8 oldmare, oldmarelap, oldmarebonuslap; // Bots can't be NiGHTSerized, silly!1 :P - if (player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) + if (player->bot) return; if (player->powers[pw_carry] != CR_NIGHTSMODE) @@ -969,9 +969,6 @@ pflags_t P_GetJumpFlags(player_t *player) // boolean P_PlayerInPain(player_t *player) { - // If the player doesn't have a mobj, it can't be in pain. - if (!player->mo) - return false; // no silly, sliding isn't pain if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing]) return true; @@ -1191,9 +1188,9 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings) { if (!player) return; - - if ((player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) && player->botleader) - player = player->botleader; + + if (player->bot) + player = &players[consoleplayer]; if (!player->mo) return; @@ -1237,8 +1234,8 @@ void P_GivePlayerSpheres(player_t *player, INT32 num_spheres) if (!player) return; - if ((player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) && player->botleader) - player = player->botleader; + if (player->bot) + player = &players[consoleplayer]; if (!player->mo) return; @@ -1264,8 +1261,8 @@ void P_GivePlayerLives(player_t *player, INT32 numlives) if (!player) return; - if ((player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) && player->botleader) - player = player->botleader; + if (player->bot) + player = &players[consoleplayer]; if (gamestate == GS_LEVEL) { @@ -2659,7 +2656,7 @@ static void P_CheckBustableBlocks(player_t *player) } // Height checks - if (rover->specialflags & FS_ONLYBOTTOM) + if (rover->bustflags & FB_ONLYBOTTOM) { if (player->mo->z + player->mo->momz + player->mo->height < bottomheight) continue; @@ -2713,7 +2710,7 @@ static void P_CheckBustableBlocks(player_t *player) EV_CrumbleChain(NULL, rover); // node->m_sector // Run a linedef executor?? - if (rover->specialflags & FS_EXECUTOR) + if (rover->bustflags & FB_EXECUTOR) P_LinedefExecute(rover->busttag, player->mo, node->m_sector); goto bustupdone; @@ -2769,10 +2766,6 @@ static void P_CheckBouncySectors(player_t *player) { rover->flags |= FF_BOUNCY; rover->bouncestrength = P_AproxDistance(rover->master->dx, rover->master->dy)/100; - if (rover->master->flags & ML_BOUNCY) - rover->specialflags |= FS_DAMPEN; - else - rover->specialflags &= ~FS_DAMPEN; } if (!(rover->flags & FF_BOUNCY)) @@ -2792,17 +2785,9 @@ static void P_CheckBouncySectors(player_t *player) { player->mo->momx = -FixedMul(player->mo->momx,rover->bouncestrength); player->mo->momy = -FixedMul(player->mo->momy,rover->bouncestrength); - - if (player->pflags & PF_SPINNING) - { - player->pflags &= ~PF_SPINNING; - player->pflags |= P_GetJumpFlags(player); - player->pflags |= PF_THOKKED; - } } else { - fixed_t newmom; pslope_t *slope = (abs(oldz - topheight) < abs(oldz + player->mo->height - bottomheight)) ? *rover->t_slope : *rover->b_slope; momentum.x = player->mo->momx; @@ -2812,53 +2797,28 @@ static void P_CheckBouncySectors(player_t *player) if (slope) P_ReverseQuantizeMomentumToSlope(&momentum, slope); - newmom = momentum.z = -FixedMul(momentum.z,rover->bouncestrength)/2; + momentum.z = -FixedMul(momentum.z,rover->bouncestrength)/2; - if (abs(newmom) < (rover->bouncestrength*2)) + if (abs(momentum.z) < (rover->bouncestrength*2)) goto bouncydone; - if (!(rover->specialflags & FS_DAMPEN)) - { - if (newmom > 0) - { - if (newmom < 8*FRACUNIT) - newmom = 8*FRACUNIT; - } - else if (newmom < 0) - { - if (newmom > -8*FRACUNIT) - newmom = -8*FRACUNIT; - } - } - - if (newmom > P_GetPlayerHeight(player)/2) - newmom = P_GetPlayerHeight(player)/2; - else if (newmom < -P_GetPlayerHeight(player)/2) - newmom = -P_GetPlayerHeight(player)/2; - - momentum.z = newmom*2; + if (momentum.z > FixedMul(24*FRACUNIT, player->mo->scale)) //half of the default player height + momentum.z = FixedMul(24*FRACUNIT, player->mo->scale); + else if (momentum.z < -FixedMul(24*FRACUNIT, player->mo->scale)) + momentum.z = -FixedMul(24*FRACUNIT, player->mo->scale); if (slope) P_QuantizeMomentumToSlope(&momentum, slope); player->mo->momx = momentum.x; player->mo->momy = momentum.y; - player->mo->momz = momentum.z/2; + player->mo->momz = momentum.z; if (player->pflags & PF_SPINNING) { - player->pflags &= ~PF_SPINNING; - player->pflags |= P_GetJumpFlags(player); player->pflags |= PF_THOKKED; } } - - if ((player->pflags & PF_SPINNING) && player->speed < FixedMul(1<mo->scale) && player->mo->momz) - { - player->pflags &= ~PF_SPINNING; - player->pflags |= P_GetJumpFlags(player); - } - goto bouncydone; } } diff --git a/src/r_bsp.c b/src/r_bsp.c index 360c17be3..91b1b091a 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -808,7 +808,7 @@ static void R_AddPolyObjects(subsector_t *sub) } // for render stats - ps_numpolyobjects += numpolys; + ps_numpolyobjects.value.i += numpolys; // sort polyobjects R_SortPolyObjects(sub); @@ -1243,7 +1243,7 @@ void R_RenderBSPNode(INT32 bspnum) node_t *bsp; INT32 side; - ps_numbspcalls++; + ps_numbspcalls.value.i++; while (!(bspnum & NF_SUBSECTOR)) // Found a subsector? { diff --git a/src/r_defs.h b/src/r_defs.h index 02937fd07..8e17addf5 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -154,12 +154,10 @@ typedef enum typedef enum { - FS_PUSHABLES = 0x1, // FF_BUSTABLE: Bustable by pushables - FS_EXECUTOR = 0x2, // FF_BUSTABLE: Trigger linedef executor - FS_ONLYBOTTOM = 0x4, // FF_BUSTABLE: Only bustable from below - FS_BUSTMASK = 0x7, - FS_DAMPEN = 0x8, // FF_BOUNCY: Dampen bounce -} ffloorspecialflags_e; + FB_PUSHABLES = 0x1, // Bustable by pushables + FB_EXECUTOR = 0x2, // Trigger linedef executor + FB_ONLYBOTTOM = 0x4, // Only bustable from below +} ffloorbustflags_e; typedef enum { @@ -201,10 +199,8 @@ typedef struct ffloor_s INT32 alpha; tic_t norender; // for culling - // Flags that are only relevant for special ffloor types - ffloorspecialflags_e specialflags; - // Only relevant for FF_BUSTUP + ffloorbustflags_e bustflags; UINT8 busttype; INT16 busttag; diff --git a/src/r_draw8_npo2.c b/src/r_draw8_npo2.c index 71ec99948..2433cb402 100644 --- a/src/r_draw8_npo2.c +++ b/src/r_draw8_npo2.c @@ -666,7 +666,6 @@ void R_DrawTiltedSplat_NPO2_8(void) for (; width != 0; width--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; // Lactozilla: Non-powers-of-two { fixed_t x = (((fixed_t)u) >> FRACBITS); diff --git a/src/r_main.c b/src/r_main.c index 17e124cb9..8729b5dcb 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -101,21 +101,22 @@ extracolormap_t *extra_colormaps = NULL; // Render stats precise_t ps_prevframetime = 0; -precise_t ps_rendercalltime = 0; -precise_t ps_uitime = 0; -precise_t ps_swaptime = 0; +ps_metric_t ps_rendercalltime = {0}; +ps_metric_t ps_otherrendertime = {0}; +ps_metric_t ps_uitime = {0}; +ps_metric_t ps_swaptime = {0}; -precise_t ps_bsptime = 0; +ps_metric_t ps_bsptime = {0}; -precise_t ps_sw_spritecliptime = 0; -precise_t ps_sw_portaltime = 0; -precise_t ps_sw_planetime = 0; -precise_t ps_sw_maskedtime = 0; +ps_metric_t ps_sw_spritecliptime = {0}; +ps_metric_t ps_sw_portaltime = {0}; +ps_metric_t ps_sw_planetime = {0}; +ps_metric_t ps_sw_maskedtime = {0}; -int ps_numbspcalls = 0; -int ps_numsprites = 0; -int ps_numdrawnodes = 0; -int ps_numpolyobjects = 0; +ps_metric_t ps_numbspcalls = {0}; +ps_metric_t ps_numsprites = {0}; +ps_metric_t ps_numdrawnodes = {0}; +ps_metric_t ps_numpolyobjects = {0}; static CV_PossibleValue_t drawdist_cons_t[] = { {256, "256"}, {512, "512"}, {768, "768"}, @@ -1496,11 +1497,11 @@ void R_RenderPlayerView(player_t *player) mytotal = 0; ProfZeroTimer(); #endif - ps_numbspcalls = ps_numpolyobjects = ps_numdrawnodes = 0; - ps_bsptime = I_GetPreciseTime(); + ps_numbspcalls.value.i = ps_numpolyobjects.value.i = ps_numdrawnodes.value.i = 0; + PS_START_TIMING(ps_bsptime); R_RenderBSPNode((INT32)numnodes - 1); - ps_bsptime = I_GetPreciseTime() - ps_bsptime; - ps_numsprites = visspritecount; + PS_STOP_TIMING(ps_bsptime); + ps_numsprites.value.i = visspritecount; #ifdef TIMING RDMSR(0x10, &mycount); mytotal += mycount; // 64bit add @@ -1510,9 +1511,9 @@ void R_RenderPlayerView(player_t *player) //profile stuff --------------------------------------------------------- Mask_Post(&masks[nummasks - 1]); - ps_sw_spritecliptime = I_GetPreciseTime(); + PS_START_TIMING(ps_sw_spritecliptime); R_ClipSprites(drawsegs, NULL); - ps_sw_spritecliptime = I_GetPreciseTime() - ps_sw_spritecliptime; + PS_STOP_TIMING(ps_sw_spritecliptime); // Add skybox portals caused by sky visplanes. @@ -1520,7 +1521,7 @@ void R_RenderPlayerView(player_t *player) Portal_AddSkyboxPortals(); // Portal rendering. Hijacks the BSP traversal. - ps_sw_portaltime = I_GetPreciseTime(); + PS_START_TIMING(ps_sw_portaltime); if (portal_base) { portal_t *portal; @@ -1560,17 +1561,17 @@ void R_RenderPlayerView(player_t *player) Portal_Remove(portal); } } - ps_sw_portaltime = I_GetPreciseTime() - ps_sw_portaltime; + PS_STOP_TIMING(ps_sw_portaltime); - ps_sw_planetime = I_GetPreciseTime(); + PS_START_TIMING(ps_sw_planetime); R_DrawPlanes(); - ps_sw_planetime = I_GetPreciseTime() - ps_sw_planetime; + PS_STOP_TIMING(ps_sw_planetime); // draw mid texture and sprite // And now 3D floors/sides! - ps_sw_maskedtime = I_GetPreciseTime(); + PS_START_TIMING(ps_sw_maskedtime); R_DrawMasked(masks, nummasks); - ps_sw_maskedtime = I_GetPreciseTime() - ps_sw_maskedtime; + PS_STOP_TIMING(ps_sw_maskedtime); free(masks); } diff --git a/src/r_main.h b/src/r_main.h index f81447c45..5f3bed980 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -17,6 +17,7 @@ #include "d_player.h" #include "r_data.h" #include "r_textures.h" +#include "m_perfstats.h" // ps_metric_t // // POV related. @@ -79,21 +80,22 @@ boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixe // Render stats extern precise_t ps_prevframetime;// time when previous frame was rendered -extern precise_t ps_rendercalltime; -extern precise_t ps_uitime; -extern precise_t ps_swaptime; +extern ps_metric_t ps_rendercalltime; +extern ps_metric_t ps_otherrendertime; +extern ps_metric_t ps_uitime; +extern ps_metric_t ps_swaptime; -extern precise_t ps_bsptime; +extern ps_metric_t ps_bsptime; -extern precise_t ps_sw_spritecliptime; -extern precise_t ps_sw_portaltime; -extern precise_t ps_sw_planetime; -extern precise_t ps_sw_maskedtime; +extern ps_metric_t ps_sw_spritecliptime; +extern ps_metric_t ps_sw_portaltime; +extern ps_metric_t ps_sw_planetime; +extern ps_metric_t ps_sw_maskedtime; -extern int ps_numbspcalls; -extern int ps_numsprites; -extern int ps_numdrawnodes; -extern int ps_numpolyobjects; +extern ps_metric_t ps_numbspcalls; +extern ps_metric_t ps_numsprites; +extern ps_metric_t ps_numdrawnodes; +extern ps_metric_t ps_numpolyobjects; // // REFRESH - the actual rendering functions. diff --git a/src/r_patchrotation.c b/src/r_patchrotation.c index a9b4a2b8f..dae3a7b53 100644 --- a/src/r_patchrotation.c +++ b/src/r_patchrotation.c @@ -227,8 +227,8 @@ void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle ox = (newwidth / 2) + (leftoffset - xpivot); oy = (newheight / 2) + (patch->topoffset - ypivot); - width = (maxx - minx); - height = (maxy - miny); + width = (maxx+1 - minx); + height = (maxy+1 - miny); if ((unsigned)(width * height) != size) { diff --git a/src/r_plane.c b/src/r_plane.c index 50b76abde..88abed44a 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -318,7 +318,7 @@ static visplane_t *new_visplane(unsigned hash) visplane_t *check = freetail; if (!check) { - check = calloc(2, sizeof (*check)); + check = malloc(sizeof (*check)); if (check == NULL) I_Error("%s: Out of memory", "new_visplane"); // FIXME: ugly } else diff --git a/src/r_things.c b/src/r_things.c index ea57e4086..bed71a6d7 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2745,7 +2745,7 @@ static drawnode_t *R_CreateDrawNode(drawnode_t *link) node->ffloor = NULL; node->sprite = NULL; - ps_numdrawnodes++; + ps_numdrawnodes.value.i++; return node; } diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 2ec28ebc8..ccec37093 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2163,7 +2163,13 @@ precise_t I_GetPreciseTime(void) int I_PreciseToMicros(precise_t d) { - return (int)(d / (timer_frequency / 1000000.0)); + // d is going to be converted into a double. So remove the highest bits + // to avoid loss of precision in the lower bits, for the (probably rare) case + // that the higher bits are actually used. + d &= ((precise_t)1 << 53) - 1; // The mantissa of a double can handle 53 bits at most. + // The resulting double from the calculation is converted first to UINT64 to avoid overflow, + // which is undefined behaviour when converting floating point values to integers. + return (int)(UINT64)(d / (timer_frequency / 1000000.0)); } // diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 97e4a7214..ed766ff23 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -409,11 +409,6 @@ void I_UpdateMouseGrab(void) SDLdoGrabMouse(); } -boolean I_GetMouseGrab(void) -{ - return (boolean)SDL_GetWindowGrab(window); -} - void I_SetMouseGrab(boolean grab) { if (grab) diff --git a/src/st_stuff.c b/src/st_stuff.c index 784666ad4..a328d669e 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2037,9 +2037,8 @@ static void ST_drawNiGHTSHUD(void) else numbersize = 48/2; - if ((oldspecialstage && leveltime & 2) - && (stplyr->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)) - && !(stplyr->powers[pw_shield] & SH_PROTECTWATER)) + if ((oldspecialstage && leveltime & 2) && + (stplyr->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(stplyr->powers[pw_shield] & ((stplyr->mo->eflags & MFE_TOUCHLAVA) ? SH_PROTECTFIRE : SH_PROTECTWATER)))) col = SKINCOLOR_ORANGE; ST_DrawNightsOverlayNum((160 + numbersize)<ammoremoval); V_DrawString(offset + 8 + stplyr->ammoremovalweapon * 20, y, - V_REDMAP|V_SNAPTOBOTTOM, penaltystr); + V_REDMAP|V_SNAPTOBOTTOM|V_PERPLAYER, penaltystr); } } 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) diff --git a/src/y_inter.c b/src/y_inter.c index afc75c8b1..f24436d40 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -239,12 +239,12 @@ void Y_LoadIntermissionData(void) } data.coop.ptotal = W_CachePatchName("YB_TOTAL", PU_PATCH); - // get background patches - bgpatch = W_CachePatchName("INTERSCR", PU_PATCH); // grab an interscreen if appropriate if (mapheaderinfo[gamemap-1]->interscreen[0] != '#') interpic = W_CachePatchName(mapheaderinfo[gamemap-1]->interscreen, PU_PATCH); + else // no interscreen? use default background + bgpatch = W_CachePatchName("INTERSCR", PU_PATCH); break; } case int_spec: @@ -255,12 +255,11 @@ void Y_LoadIntermissionData(void) data.spec.pscore = W_CachePatchName("YB_SCORE", PU_PATCH); data.spec.pcontinues = W_CachePatchName("YB_CONTI", PU_PATCH); - // get background tile - bgtile = W_CachePatchName("SPECTILE", PU_PATCH); - // grab an interscreen if appropriate if (mapheaderinfo[gamemap-1]->interscreen[0] != '#') interpic = W_CachePatchName(mapheaderinfo[gamemap-1]->interscreen, PU_PATCH); + else // no interscreen? use default background + bgtile = W_CachePatchName("SPECTILE", PU_PATCH); break; } case int_ctf: diff --git a/src/z_zone.h b/src/z_zone.h index be55bf994..17f572a90 100644 --- a/src/z_zone.h +++ b/src/z_zone.h @@ -39,6 +39,7 @@ enum // Tags < PU_LEVEL are not purged until freed explicitly. PU_STATIC = 1, // static entire execution time PU_LUA = 2, // static entire execution time -- used by lua so it doesn't get caught in loops forever + PU_PERFSTATS = 3, // static between changes to ps_samplesize cvar PU_SOUND = 11, // static while playing PU_MUSIC = 12, // static while playing