From 014b93406ed2a605027466f9f3e3815c19e5d77a Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Fri, 31 Jan 2020 15:29:22 +0100 Subject: [PATCH 01/53] Store most data in gamestate instead of server config packet --- src/d_clisrv.c | 82 +------------------------------------------------- src/d_clisrv.h | 8 ----- src/p_saveg.c | 19 ++++++++++-- 3 files changed, 17 insertions(+), 92 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index ee4e62b91..694240579 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1117,40 +1117,6 @@ static void GetPackets(void); static cl_mode_t cl_mode = CL_SEARCHING; -// Player name send/load - -static void CV_SavePlayerNames(UINT8 **p) -{ - INT32 i = 0; - // Players in game only. - for (; i < MAXPLAYERS; ++i) - { - if (!playeringame[i]) - { - WRITEUINT8(*p, 0); - continue; - } - WRITESTRING(*p, player_names[i]); - } -} - -static void CV_LoadPlayerNames(UINT8 **p) -{ - INT32 i = 0; - char tmp_name[MAXPLAYERNAME+1]; - tmp_name[MAXPLAYERNAME] = 0; - - for (; i < MAXPLAYERS; ++i) - { - READSTRING(*p, tmp_name); - if (tmp_name[0] == 0) - continue; - if (tmp_name[MAXPLAYERNAME]) // overflow detected - I_Error("Received bad server config packet when trying to join"); - memcpy(player_names[i], tmp_name, MAXPLAYERNAME+1); - } -} - #ifdef CLIENT_LOADINGSCREEN // // CL_DrawConnectionStatus @@ -1412,8 +1378,6 @@ static void SV_SendPlayerInfo(INT32 node) */ static boolean SV_SendServerConfig(INT32 node) { - INT32 i; - UINT8 *p, *op; boolean waspacketsent; netbuffer->packettype = PT_SERVERCFG; @@ -1429,32 +1393,10 @@ static boolean SV_SendServerConfig(INT32 node) netbuffer->u.servercfg.gametype = (UINT8)gametype; netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame; - // we fill these structs with FFs so that any players not in game get sent as 0xFFFF - // which is nice and easy for us to detect - memset(netbuffer->u.servercfg.playerskins, 0xFF, sizeof(netbuffer->u.servercfg.playerskins)); - memset(netbuffer->u.servercfg.playercolor, 0xFF, sizeof(netbuffer->u.servercfg.playercolor)); - memset(netbuffer->u.servercfg.playeravailabilities, 0xFF, sizeof(netbuffer->u.servercfg.playeravailabilities)); - - memset(netbuffer->u.servercfg.adminplayers, -1, sizeof(netbuffer->u.servercfg.adminplayers)); - - for (i = 0; i < MAXPLAYERS; i++) - { - netbuffer->u.servercfg.adminplayers[i] = (SINT8)adminplayers[i]; - - if (!playeringame[i]) - continue; - netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin; - netbuffer->u.servercfg.playercolor[i] = (UINT8)players[i].skincolor; - netbuffer->u.servercfg.playeravailabilities[i] = (UINT32)LONG(players[i].availabilities); - } - memcpy(netbuffer->u.servercfg.server_context, server_context, 8); - op = p = netbuffer->u.servercfg.varlengthinputs; - CV_SavePlayerNames(&p); - CV_SaveNetVars(&p); { - const size_t len = sizeof (serverconfig_pak) + (size_t)(p - op); + const size_t len = sizeof (serverconfig_pak); #ifdef DEBUGFILE if (debugfile) @@ -3813,9 +3755,6 @@ static void HandlePacketFromAwayNode(SINT8 node) case PT_SERVERCFG: // Positive response of client join request { - INT32 j; - UINT8 *scp; - if (server && serverrunning && node != servernode) { // but wait I thought I'm the server? Net_CloseConnection(node); @@ -3831,8 +3770,6 @@ static void HandlePacketFromAwayNode(SINT8 node) maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); G_SetGametype(netbuffer->u.servercfg.gametype); modifiedgame = netbuffer->u.servercfg.modifiedgame; - for (j = 0; j < MAXPLAYERS; j++) - adminplayers[j] = netbuffer->u.servercfg.adminplayers[j]; memcpy(server_context, netbuffer->u.servercfg.server_context, 8); } @@ -3851,23 +3788,6 @@ static void HandlePacketFromAwayNode(SINT8 node) #endif DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); - memset(playeringame, 0, sizeof(playeringame)); - for (j = 0; j < MAXPLAYERS; j++) - { - if (netbuffer->u.servercfg.playerskins[j] == 0xFF - && netbuffer->u.servercfg.playercolor[j] == 0xFF - && netbuffer->u.servercfg.playeravailabilities[j] == 0xFFFFFFFF) - continue; // not in game - - playeringame[j] = true; - players[j].availabilities = (UINT32)LONG(netbuffer->u.servercfg.playeravailabilities[j]); - SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]); - players[j].skincolor = netbuffer->u.servercfg.playercolor[j]; - } - - scp = netbuffer->u.servercfg.varlengthinputs; - CV_LoadPlayerNames(&scp); - CV_LoadNetVars(&scp); #ifdef JOININGAME /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? /// Shouldn't them be downloaded even at intermission time? diff --git a/src/d_clisrv.h b/src/d_clisrv.h index df93fe31d..a48ab91a9 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -305,18 +305,10 @@ typedef struct UINT8 clientnode; UINT8 gamestate; - // 0xFF == not in game; else player skin num - UINT8 playerskins[MAXPLAYERS]; - UINT8 playercolor[MAXPLAYERS]; - UINT32 playeravailabilities[MAXPLAYERS]; - UINT8 gametype; UINT8 modifiedgame; - SINT8 adminplayers[MAXPLAYERS]; // Needs to be signed char server_context[8]; // Unique context id, generated at server startup. - - UINT8 varlengthinputs[0]; // Playernames and netvars } ATTRPACK serverconfig_pak; typedef struct { diff --git a/src/p_saveg.c b/src/p_saveg.c index 853856880..19c5b532e 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -107,13 +107,16 @@ static void P_NetArchivePlayers(void) for (i = 0; i < MAXPLAYERS; i++) { + WRITESINT8(save_p, (SINT8)adminplayers[i]); + if (!playeringame[i]) continue; flags = 0; - // no longer send ticcmds, player name, skin, or color + // no longer send ticcmds + WRITESTRINGN(save_p, player_names[i], MAXPLAYERNAME); WRITEANGLE(save_p, players[i].aiming); WRITEANGLE(save_p, players[i].drawangle); WRITEANGLE(save_p, players[i].awayviewaiming); @@ -140,6 +143,9 @@ static void P_NetArchivePlayers(void) WRITEUINT16(save_p, players[i].flashpal); WRITEUINT16(save_p, players[i].flashcount); + WRITEUINT8(save_p, players[i].skincolor); + WRITEINT32(save_p, players[i].skin); + WRITEUINT32(save_p, players[i].availabilities); WRITEUINT32(save_p, players[i].score); WRITEFIXED(save_p, players[i].dashspeed); WRITESINT8(save_p, players[i].lives); @@ -314,6 +320,8 @@ static void P_NetUnArchivePlayers(void) for (i = 0; i < MAXPLAYERS; i++) { + adminplayers[i] = (INT32)READSINT8(save_p); + // Do NOT memset player struct to 0 // other areas may initialize data elsewhere //memset(&players[i], 0, sizeof (player_t)); @@ -321,9 +329,8 @@ static void P_NetUnArchivePlayers(void) continue; // NOTE: sending tics should (hopefully) no longer be necessary - // sending player names, skin and color should not be necessary at all! - // (that data is handled in the server config now) + READSTRINGN(save_p, player_names[i], MAXPLAYERNAME); players[i].aiming = READANGLE(save_p); players[i].drawangle = READANGLE(save_p); players[i].awayviewaiming = READANGLE(save_p); @@ -350,6 +357,9 @@ static void P_NetUnArchivePlayers(void) players[i].flashpal = READUINT16(save_p); players[i].flashcount = READUINT16(save_p); + players[i].skincolor = READUINT8(save_p); + players[i].skin = READINT32(save_p); + players[i].availabilities = READUINT32(save_p); players[i].score = READUINT32(save_p); players[i].dashspeed = READFIXED(save_p); // dashing speed players[i].lives = READSINT8(save_p); @@ -3983,6 +3993,7 @@ static void P_NetArchiveMisc(void) WRITEINT16(save_p, gamemap); WRITEINT16(save_p, gamestate); + WRITEINT16(save_p, gametype); { UINT32 pig = 0; @@ -4065,6 +4076,8 @@ static inline boolean P_NetUnArchiveMisc(void) G_SetGamestate(READINT16(save_p)); + gametype = READINT16(save_p); + { UINT32 pig = READUINT32(save_p); for (i = 0; i < MAXPLAYERS; i++) From d02c4c0cc7e0d9e9bc776ecf5f89d58191cb697f Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Fri, 31 Jan 2020 15:57:04 +0100 Subject: [PATCH 02/53] Add "resendgamestate" command --- src/d_clisrv.c | 120 +++++++++++++++++++++++++++++++++++++++++++++---- src/d_clisrv.h | 3 ++ src/d_main.c | 2 +- src/d_net.c | 3 ++ src/g_game.c | 2 +- src/p_saveg.c | 19 +++++--- src/p_saveg.h | 4 +- src/p_setup.c | 27 +++++++---- src/p_setup.h | 2 +- 9 files changed, 153 insertions(+), 29 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 694240579..c1703b82d 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -121,6 +121,7 @@ static ticcmd_t localcmds2; static boolean cl_packetmissed; // here it is for the secondary local player (splitscreen) static UINT8 mynode; // my address pointofview server +static boolean cl_redownloadinggamestate = false; static UINT8 localtextcmd[MAXTEXTCMD]; static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen @@ -1429,7 +1430,7 @@ static boolean SV_SendServerConfig(INT32 node) #ifdef JOININGAME #define SAVEGAMESIZE (768*1024) -static void SV_SendSaveGame(INT32 node) +static void SV_SendSaveGame(INT32 node, boolean resending) { size_t length, compressedlen; UINT8 *savebuffer; @@ -1447,7 +1448,7 @@ static void SV_SendSaveGame(INT32 node) // Leave room for the uncompressed length. save_p = savebuffer + sizeof(UINT32); - P_SaveNetGame(); + P_SaveNetGame(resending); length = save_p - savebuffer; if (length > SAVEGAMESIZE) @@ -1520,7 +1521,7 @@ static void SV_SavedGame(void) return; } - P_SaveNetGame(); + P_SaveNetGame(false); length = save_p - savebuffer; if (length > SAVEGAMESIZE) @@ -1543,7 +1544,7 @@ static void SV_SavedGame(void) #define TMPSAVENAME "$$$.sav" -static void CL_LoadReceivedSavegame(void) +static void CL_LoadReceivedSavegame(boolean reloading) { UINT8 *savebuffer = NULL; size_t length, decompressedlen; @@ -1579,7 +1580,7 @@ static void CL_LoadReceivedSavegame(void) automapactive = false; // load a base level - if (P_LoadNetGame()) + if (P_LoadNetGame(reloading)) { const INT32 actnum = mapheaderinfo[gamemap-1]->actnum; CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)); @@ -1611,6 +1612,32 @@ static void CL_LoadReceivedSavegame(void) consistancy[gametic%BACKUPTICS] = Consistancy(); CON_ToggleOff(); } + +static void CL_ReloadReceivedSavegame(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + { +#ifdef HAVE_BLUA + LUA_InvalidatePlayer(&players[i]); +#endif + sprintf(player_names[i], "Player %d", i + 1); + } + + CL_LoadReceivedSavegame(true); + + if (neededtic < gametic) + neededtic = gametic; + maketic = neededtic; + + camera.subsector = R_PointInSubsector(camera.x, camera.y); + camera2.subsector = R_PointInSubsector(camera2.x, camera2.y); + + cl_redownloadinggamestate = false; + + CONS_Printf(M_GetText("Game state reloaded\n")); +} #endif #ifndef NONET @@ -1950,7 +1977,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic if (fileneeded[0].status == FS_FOUND) { // Gamestate is now handled within CL_LoadReceivedSavegame() - CL_LoadReceivedSavegame(); + CL_LoadReceivedSavegame(false); cl_mode = CL_CONNECTED; } // don't break case continue to CL_CONNECTED else @@ -2974,6 +3001,32 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) CL_RemovePlayer(pnum, kickreason); } +static void Command_ResendGamestate(void) +{ + 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; + } + + const SINT8 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; + } +} + consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; consvar_t cv_joinnextround = {"joinnextround", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}}; @@ -3012,6 +3065,7 @@ void D_ClientServerInit(void) COM_AddCommand("reloadbans", Command_ReloadBan); COM_AddCommand("connect", Command_connect); COM_AddCommand("nodes", Command_Nodes); + COM_AddCommand("resendgamestate", Command_ResendGamestate); #ifdef PACKETDROP COM_AddCommand("drop", Command_Drop); COM_AddCommand("droprate", Command_Droprate); @@ -3082,6 +3136,7 @@ void SV_ResetServer(void) mynode = 0; cl_packetmissed = false; + cl_redownloadinggamestate = false; if (dedicated) { @@ -3598,7 +3653,7 @@ static void HandleConnect(SINT8 node) { if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) && newnode) { - SV_SendSaveGame(node); // send a complete game state + SV_SendSaveGame(node, false); // send a complete game state DEBFILE("send savegame\n"); } SV_AddWaitingPlayers(names[0], names[1]); @@ -3665,6 +3720,42 @@ static void HandleServerInfo(SINT8 node) } #endif +static void PT_WillResendGamestate(void) +{ + char tmpsave[256]; + + if (server || cl_redownloadinggamestate) + return; + + // Send back a PT_CANRESENDGAMESTATE packet to the server + // so they know they can start sending the game state + netbuffer->packettype = PT_CANRESENDGAMESTATE; + if (!HSendPacket(servernode, true, 0, 0)) + return; + + CONS_Printf(M_GetText("Reloading game state...\n")); + + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + // Don't get a corrupt savegame error because tmpsave already exists + if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) + I_Error("Can't delete %s\n", tmpsave); + + CL_PrepareDownloadSaveGame(tmpsave); + + cl_redownloadinggamestate = true; +} + +static void PT_CanResendGamestate(SINT8 node) +{ + if (client || sendingsavegame[node]) + return; + + CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[nodetoplayer[node]]); + + SV_SendSaveGame(node, true); // Resend a complete game state +} + /** Handles a packet received from a node that isn't in game * * \param node The packet sender @@ -4107,6 +4198,9 @@ static void HandlePacketFromPlayer(SINT8 node) Net_CloseConnection(node); nodeingame[node] = false; break; + case PT_CANRESENDGAMESTATE: + PT_CanResendGamestate(node); + break; // -------------------------------------------- CLIENT RECEIVE ---------- case PT_RESYNCHEND: // Only accept PT_RESYNCHEND from the server. @@ -4136,6 +4230,9 @@ static void HandlePacketFromPlayer(SINT8 node) break; } + if (cl_redownloadinggamestate) + break; + realstart = ExpandTics(netbuffer->u.serverpak.starttic); realend = realstart + netbuffer->u.serverpak.numtics; @@ -4234,6 +4331,9 @@ static void HandlePacketFromPlayer(SINT8 node) if (client) Got_Filetxpak(); break; + case PT_WILLRESENDGAMESTATE: + PT_WillResendGamestate(); + break; default: DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n", netbuffer->packettype, node)); @@ -4876,7 +4976,11 @@ void NetUpdate(void) if (client) { - if (!resynch_local_inprogress) + // If the client just finished redownloading the game state, load it + if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND) + CL_ReloadReceivedSavegame(); + + if (!(resynch_local_inprogress || cl_redownloadinggamestate)) CL_SendClientCmd(); // Send tic cmd hu_resynching = resynch_local_inprogress; } diff --git a/src/d_clisrv.h b/src/d_clisrv.h index a48ab91a9..6761b47cc 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -67,6 +67,9 @@ typedef enum PT_RESYNCHEND, // Player is now resynched and is being requested to remake the gametic PT_RESYNCHGET, // Player got resynch packet + PT_WILLRESENDGAMESTATE, // Hey Client, I am about to resend you the gamestate! + PT_CANRESENDGAMESTATE, // Okay Server, I'm ready to receive it, you can go ahead. + // Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility. PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL diff --git a/src/d_main.c b/src/d_main.c index 15d3c8041..f70f80b32 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1514,7 +1514,7 @@ void D_SRB2Main(void) { levelstarttic = gametic; G_SetGamestate(GS_LEVEL); - if (!P_LoadLevel(false)) + if (!P_LoadLevel(false, false)) I_Quit(); // fail so reset game stuff } } diff --git a/src/d_net.c b/src/d_net.c index 573c9cfe9..648d5683f 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -799,6 +799,9 @@ static const char *packettypename[NUMPACKETTYPE] = "RESYNCHEND", "RESYNCHGET", + "WILLRESENDGAMESTATE", + "CANRESENDGAMESTATE", + "FILEFRAGMENT", "TEXTCMD", "TEXTCMD2", diff --git a/src/g_game.c b/src/g_game.c index f5d7cd2fb..4f9e7a580 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1839,7 +1839,7 @@ void G_DoLoadLevel(boolean resetplayer) } // Setup the level. - if (!P_LoadLevel(false)) // this never returns false? + if (!P_LoadLevel(false, false)) // this never returns false? { // fail so reset game stuff Command_ExitGame_f(); diff --git a/src/p_saveg.c b/src/p_saveg.c index 19c5b532e..1e65098cf 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3985,12 +3985,14 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) playeringame[consoleplayer] = true; } -static void P_NetArchiveMisc(void) +static void P_NetArchiveMisc(boolean resending) { INT32 i; WRITEUINT32(save_p, ARCHIVEBLOCK_MISC); + if (resending) + WRITEUINT32(save_p, gametic); WRITEINT16(save_p, gamemap); WRITEINT16(save_p, gamestate); WRITEINT16(save_p, gametype); @@ -4056,13 +4058,16 @@ static void P_NetArchiveMisc(void) WRITEUINT8(save_p, 0x2e); } -static inline boolean P_NetUnArchiveMisc(void) +static inline boolean P_NetUnArchiveMisc(boolean reloading) { INT32 i; if (READUINT32(save_p) != ARCHIVEBLOCK_MISC) I_Error("Bad $$$.sav at archive block Misc"); + if (reloading) + gametic = READUINT32(save_p); + gamemap = READINT16(save_p); // gamemap changed; we assume that its map header is always valid, @@ -4091,7 +4096,7 @@ static inline boolean P_NetUnArchiveMisc(void) tokenlist = READUINT32(save_p); - if (!P_LoadLevel(true)) + if (!P_LoadLevel(true, reloading)) return false; // get the time @@ -4192,14 +4197,14 @@ void P_SaveGame(void) P_ArchiveLuabanksAndConsistency(); } -void P_SaveNetGame(void) +void P_SaveNetGame(boolean resending) { thinker_t *th; mobj_t *mobj; INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise CV_SaveNetVars(&save_p); - P_NetArchiveMisc(); + P_NetArchiveMisc(resending); // Assign the mobjnumber for pointer tracking for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) @@ -4250,10 +4255,10 @@ boolean P_LoadGame(INT16 mapoverride) return true; } -boolean P_LoadNetGame(void) +boolean P_LoadNetGame(boolean reloading) { CV_LoadNetVars(&save_p); - if (!P_NetUnArchiveMisc()) + if (!P_NetUnArchiveMisc(reloading)) return false; P_NetUnArchivePlayers(); if (gamestate == GS_LEVEL) diff --git a/src/p_saveg.h b/src/p_saveg.h index 16d47bea8..b75c02117 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -22,9 +22,9 @@ // These are the load / save game routines. void P_SaveGame(void); -void P_SaveNetGame(void); +void P_SaveNetGame(boolean resending); boolean P_LoadGame(INT16 mapoverride); -boolean P_LoadNetGame(void); +boolean P_LoadNetGame(boolean reloading); mobj_t *P_FindNewPosition(UINT32 oldposition); diff --git a/src/p_setup.c b/src/p_setup.c index 729ee00c2..95552a2d0 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2777,8 +2777,6 @@ static void P_InitLevelSettings(void) leveltime = 0; - localaiming = 0; - localaiming2 = 0; modulothing = 0; // special stage tokens, emeralds, and ring total @@ -2893,6 +2891,9 @@ void P_RespawnThings(void) P_InitLevelSettings(); + localaiming = 0; + localaiming2 = 0; + P_SpawnMapThings(true); // restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that @@ -3387,7 +3388,7 @@ static void P_InitGametype(void) * \param fromnetsave If true, skip some stuff because we're loading a netgame snapshot. * \todo Clean up, refactor, split up; get rid of the bloat. */ -boolean P_LoadLevel(boolean fromnetsave) +boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) { // use gamemap to get map number. // 99% of the things already did, so. @@ -3457,7 +3458,10 @@ boolean P_LoadLevel(boolean fromnetsave) players[consoleplayer].viewz = 1; // Cancel all d_main.c fadeouts (keep fade in though). - wipegamestate = FORCEWIPEOFF; + if (reloadinggamestate) + wipegamestate = gamestate; // Don't fade if reloading the gamestate + else + wipegamestate = FORCEWIPEOFF; wipestyleflags = 0; // Special stage fade to white @@ -3491,7 +3495,7 @@ boolean P_LoadLevel(boolean fromnetsave) // Let's fade to black here // But only if we didn't do the special stage wipe - if (rendermode != render_none && !ranspecialwipe) + if (rendermode != render_none && !(ranspecialwipe || reloadinggamestate)) P_RunLevelWipe(); if (!titlemapinaction) @@ -3622,7 +3626,12 @@ boolean P_LoadLevel(boolean fromnetsave) if (!fromnetsave) P_InitGametype(); - P_InitCamera(); + if (!reloadinggamestate) + { + P_InitCamera(); + localaiming = 0; + localaiming2 = 0; + } // clear special respawning que iquehead = iquetail = 0; @@ -3633,7 +3642,7 @@ boolean P_LoadLevel(boolean fromnetsave) P_MapEnd(); // Remove the loading shit from the screen - if (rendermode != render_none && !titlemapinaction) + if (rendermode != render_none && !(titlemapinaction || reloadinggamestate)) F_WipeColorFill(levelfadecol); if (precache || dedicated) @@ -3671,8 +3680,8 @@ boolean P_LoadLevel(boolean fromnetsave) #endif } - // No render mode, stop here. - if (rendermode == render_none) + // No render mode or reloading gamestate, stop here. + if (rendermode == render_none || reloadinggamestate) return true; // Title card! diff --git a/src/p_setup.h b/src/p_setup.h index d7e2d8861..c638bafca 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -97,7 +97,7 @@ void P_SetupLevelSky(INT32 skynum, boolean global); void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); #endif void P_RespawnThings(void); -boolean P_LoadLevel(boolean fromnetsave); +boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate); #ifdef HWRENDER void HWR_SetupLevel(void); #endif From a927d67259c27cf66dffcbdc47df9383bc0b70f9 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Fri, 28 Feb 2020 18:17:37 +0100 Subject: [PATCH 03/53] Fix warning --- src/d_clisrv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index c1703b82d..8eeda23a6 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3003,6 +3003,8 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) static void Command_ResendGamestate(void) { + SINT8 playernum; + if (COM_Argc() == 1) { CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); @@ -3014,7 +3016,7 @@ static void Command_ResendGamestate(void) return; } - const SINT8 playernum = nametonum(COM_Argv(1)); + playernum = nametonum(COM_Argv(1)); if (playernum == -1 || playernum == 0) return; From 4f7591a044d07c89f811bc6b179e90070db226bd Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sat, 29 Feb 2020 13:40:15 +0100 Subject: [PATCH 04/53] Rename packet --- src/d_clisrv.c | 10 +++++----- src/d_clisrv.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 8eeda23a6..42e7b472f 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3729,9 +3729,9 @@ static void PT_WillResendGamestate(void) if (server || cl_redownloadinggamestate) return; - // Send back a PT_CANRESENDGAMESTATE packet to the server + // Send back a PT_CANRECEIVEGAMESTATE packet to the server // so they know they can start sending the game state - netbuffer->packettype = PT_CANRESENDGAMESTATE; + netbuffer->packettype = PT_CANRECEIVEGAMESTATE; if (!HSendPacket(servernode, true, 0, 0)) return; @@ -3748,7 +3748,7 @@ static void PT_WillResendGamestate(void) cl_redownloadinggamestate = true; } -static void PT_CanResendGamestate(SINT8 node) +static void PT_CanReceiveGamestate(SINT8 node) { if (client || sendingsavegame[node]) return; @@ -4200,8 +4200,8 @@ static void HandlePacketFromPlayer(SINT8 node) Net_CloseConnection(node); nodeingame[node] = false; break; - case PT_CANRESENDGAMESTATE: - PT_CanResendGamestate(node); + case PT_CANRECEIVEGAMESTATE: + PT_CanReceiveGamestate(node); break; // -------------------------------------------- CLIENT RECEIVE ---------- case PT_RESYNCHEND: diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 6761b47cc..5b4b7d2d8 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -68,7 +68,7 @@ typedef enum PT_RESYNCHGET, // Player got resynch packet PT_WILLRESENDGAMESTATE, // Hey Client, I am about to resend you the gamestate! - PT_CANRESENDGAMESTATE, // Okay Server, I'm ready to receive it, you can go ahead. + PT_CANRECEIVEGAMESTATE, // Okay Server, I'm ready to receive it, you can go ahead. // Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility. From 846560910d28b7f0766fe4730dd6492bba79008a Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sun, 1 Mar 2020 03:22:47 +0100 Subject: [PATCH 05/53] Obliterate resynch Okay, more precisely this substitutes the old resynch with the newly added gamestate resend code. --- src/d_clisrv.c | 706 ++----------------------------------------------- src/d_clisrv.h | 171 +----------- src/hu_stuff.c | 2 +- 3 files changed, 31 insertions(+), 848 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f04676162..6b68c4a18 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -83,6 +83,7 @@ char playeraddress[MAXPLAYERS][64]; // The actual timeout will be longer depending on the savegame length tic_t jointimeout = (10*TICRATE); static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame? +static boolean resendingsavegame[MAXNETNODES]; // Are we resending the savegame? static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout? UINT16 pingmeasurecount = 1; @@ -102,15 +103,8 @@ static tic_t maketic; static INT16 consistancy[BACKUPTICS]; -// Resynching shit! -static UINT32 resynch_score[MAXNETNODES]; // "score" for kicking -- if this gets too high then cfail kick -static UINT16 resynch_delay[MAXNETNODES]; // delay time before the player can be considered to have desynched -static UINT32 resynch_status[MAXNETNODES]; // 0 bit means synched for that player, 1 means possibly desynched -static UINT8 resynch_sent[MAXNETNODES][MAXPLAYERS]; // what synch packets have we attempted to send to the player -static UINT8 resynch_inprogress[MAXNETNODES]; -static UINT8 resynch_local_inprogress = false; // WE are desynched and getting packets to fix it. static UINT8 player_joining = false; -UINT8 hu_resynching = 0; +UINT8 hu_redownloadinggamestate = 0; UINT8 adminpassmd5[16]; boolean adminpasswordset = false; @@ -504,597 +498,6 @@ void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum) // end extra data function for lmps // ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// resynch player data -// ----------------------------------------------------------------- -static inline void resynch_write_player(resynch_pak *rsp, const size_t i) -{ - size_t j; - - rsp->playernum = (UINT8)i; - - // Do not send anything visual related. - // Only send data that we need to know for physics. - rsp->playerstate = (UINT8)players[i].playerstate; //playerstate_t - rsp->pflags = (UINT32)LONG(players[i].pflags); //pflags_t - rsp->panim = (UINT8)players[i].panim; //panim_t - - rsp->aiming = (angle_t)LONG(players[i].aiming); - rsp->currentweapon = LONG(players[i].currentweapon); - rsp->ringweapons = LONG(players[i].ringweapons); - - rsp->ammoremoval = (UINT16)SHORT(players[i].ammoremoval); - rsp->ammoremovaltimer = (tic_t)LONG(players[i].ammoremovaltimer); - rsp->ammoremovalweapon = LONG(players[i].ammoremovalweapon); - - for (j = 0; j < NUMPOWERS; ++j) - rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]); - - // Score is resynched in the rspfirm resync packet - rsp->rings = SHORT(players[i].rings); - rsp->spheres = SHORT(players[i].spheres); - rsp->lives = players[i].lives; - rsp->continues = players[i].continues; - rsp->scoreadd = players[i].scoreadd; - rsp->xtralife = players[i].xtralife; - rsp->pity = players[i].pity; - - rsp->skincolor = players[i].skincolor; - rsp->skin = LONG(players[i].skin); - rsp->availabilities = LONG(players[i].availabilities); - // Just in case Lua does something like - // modify these at runtime - rsp->camerascale = (fixed_t)LONG(players[i].camerascale); - rsp->shieldscale = (fixed_t)LONG(players[i].shieldscale); - rsp->normalspeed = (fixed_t)LONG(players[i].normalspeed); - rsp->runspeed = (fixed_t)LONG(players[i].runspeed); - rsp->thrustfactor = players[i].thrustfactor; - rsp->accelstart = players[i].accelstart; - rsp->acceleration = players[i].acceleration; - rsp->charability = players[i].charability; - rsp->charability2 = players[i].charability2; - rsp->charflags = (UINT32)LONG(players[i].charflags); - rsp->thokitem = (UINT32)LONG(players[i].thokitem); //mobjtype_t - rsp->spinitem = (UINT32)LONG(players[i].spinitem); //mobjtype_t - rsp->revitem = (UINT32)LONG(players[i].revitem); //mobjtype_t - rsp->followitem = (UINT32)LONG(players[i].followitem); //mobjtype_t - rsp->actionspd = (fixed_t)LONG(players[i].actionspd); - rsp->mindash = (fixed_t)LONG(players[i].mindash); - rsp->maxdash = (fixed_t)LONG(players[i].maxdash); - rsp->jumpfactor = (fixed_t)LONG(players[i].jumpfactor); - rsp->playerheight = (fixed_t)LONG(players[i].height); - rsp->playerspinheight = (fixed_t)LONG(players[i].spinheight); - - rsp->speed = (fixed_t)LONG(players[i].speed); - rsp->secondjump = players[i].secondjump; - rsp->fly1 = players[i].fly1; - rsp->glidetime = (tic_t)LONG(players[i].glidetime); - rsp->climbing = players[i].climbing; - rsp->deadtimer = players[i].deadtimer; - rsp->exiting = (tic_t)LONG(players[i].exiting); - rsp->homing = players[i].homing; - rsp->dashmode = (tic_t)LONG(players[i].dashmode); - rsp->skidtime = (tic_t)LONG(players[i].skidtime); - rsp->cmomx = (fixed_t)LONG(players[i].cmomx); - rsp->cmomy = (fixed_t)LONG(players[i].cmomy); - rsp->rmomx = (fixed_t)LONG(players[i].rmomx); - rsp->rmomy = (fixed_t)LONG(players[i].rmomy); - - rsp->weapondelay = LONG(players[i].weapondelay); - rsp->tossdelay = LONG(players[i].tossdelay); - - rsp->starpostx = SHORT(players[i].starpostx); - rsp->starposty = SHORT(players[i].starposty); - rsp->starpostz = SHORT(players[i].starpostz); - rsp->starpostnum = LONG(players[i].starpostnum); - rsp->starposttime = (tic_t)LONG(players[i].starposttime); - rsp->starpostangle = (angle_t)LONG(players[i].starpostangle); - rsp->starpostscale = (fixed_t)LONG(players[i].starpostscale); - - rsp->maxlink = LONG(players[i].maxlink); - rsp->dashspeed = (fixed_t)LONG(players[i].dashspeed); - rsp->angle_pos = (angle_t)LONG(players[i].angle_pos); - rsp->old_angle_pos = (angle_t)LONG(players[i].old_angle_pos); - rsp->bumpertime = (tic_t)LONG(players[i].bumpertime); - rsp->flyangle = LONG(players[i].flyangle); - rsp->drilltimer = (tic_t)LONG(players[i].drilltimer); - rsp->linkcount = LONG(players[i].linkcount); - rsp->linktimer = (tic_t)LONG(players[i].linktimer); - rsp->anotherflyangle = LONG(players[i].anotherflyangle); - rsp->nightstime = (tic_t)LONG(players[i].nightstime); - rsp->drillmeter = LONG(players[i].drillmeter); - rsp->drilldelay = players[i].drilldelay; - rsp->bonustime = players[i].bonustime; - rsp->mare = players[i].mare; - rsp->lastsidehit = SHORT(players[i].lastsidehit); - rsp->lastlinehit = SHORT(players[i].lastlinehit); - - rsp->losstime = (tic_t)LONG(players[i].losstime); - rsp->timeshit = players[i].timeshit; - rsp->onconveyor = LONG(players[i].onconveyor); - - rsp->hasmo = false; - //Transfer important mo information if the player has a body. - //This lets us resync players even if they are dead. - if (!players[i].mo) - return; - rsp->hasmo = true; - - rsp->health = LONG(players[i].mo->health); - rsp->angle = (angle_t)LONG(players[i].mo->angle); - rsp->rollangle = (angle_t)LONG(players[i].mo->rollangle); - rsp->x = LONG(players[i].mo->x); - rsp->y = LONG(players[i].mo->y); - rsp->z = LONG(players[i].mo->z); - rsp->momx = LONG(players[i].mo->momx); - rsp->momy = LONG(players[i].mo->momy); - rsp->momz = LONG(players[i].mo->momz); - rsp->friction = LONG(players[i].mo->friction); - rsp->movefactor = LONG(players[i].mo->movefactor); - - rsp->sprite = (spritenum_t)LONG(players[i].mo->sprite); - rsp->frame = LONG(players[i].mo->frame); - rsp->sprite2 = players[i].mo->sprite2; - rsp->anim_duration = SHORT(players[i].mo->anim_duration); - rsp->tics = LONG(players[i].mo->tics); - rsp->statenum = (statenum_t)LONG(players[i].mo->state-states); // :( - rsp->eflags = (UINT16)SHORT(players[i].mo->eflags); - rsp->flags = LONG(players[i].mo->flags); - rsp->flags2 = LONG(players[i].mo->flags2); - - rsp->radius = LONG(players[i].mo->radius); - rsp->height = LONG(players[i].mo->height); - rsp->scale = LONG(players[i].mo->scale); - rsp->destscale = LONG(players[i].mo->destscale); - rsp->scalespeed = LONG(players[i].mo->scalespeed); -} - -static void resynch_read_player(resynch_pak *rsp) -{ - INT32 i = rsp->playernum, j; - mobj_t *savedmo = players[i].mo; - - // Do not send anything visual related. - // Only send data that we need to know for physics. - players[i].playerstate = (UINT8)rsp->playerstate; //playerstate_t - players[i].pflags = (UINT32)LONG(rsp->pflags); //pflags_t - players[i].panim = (UINT8)rsp->panim; //panim_t - - players[i].aiming = (angle_t)LONG(rsp->aiming); - players[i].currentweapon = LONG(rsp->currentweapon); - players[i].ringweapons = LONG(rsp->ringweapons); - - players[i].ammoremoval = (UINT16)SHORT(rsp->ammoremoval); - players[i].ammoremovaltimer = (tic_t)LONG(rsp->ammoremovaltimer); - players[i].ammoremovalweapon = LONG(rsp->ammoremovalweapon); - - for (j = 0; j < NUMPOWERS; ++j) - players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]); - - // Score is resynched in the rspfirm resync packet - players[i].rings = SHORT(rsp->rings); - players[i].spheres = SHORT(rsp->spheres); - players[i].lives = rsp->lives; - players[i].continues = rsp->continues; - players[i].scoreadd = rsp->scoreadd; - players[i].xtralife = rsp->xtralife; - players[i].pity = rsp->pity; - - players[i].skincolor = rsp->skincolor; - players[i].skin = LONG(rsp->skin); - players[i].availabilities = LONG(rsp->availabilities); - // Just in case Lua does something like - // modify these at runtime - players[i].camerascale = (fixed_t)LONG(rsp->camerascale); - players[i].shieldscale = (fixed_t)LONG(rsp->shieldscale); - players[i].normalspeed = (fixed_t)LONG(rsp->normalspeed); - players[i].runspeed = (fixed_t)LONG(rsp->runspeed); - players[i].thrustfactor = rsp->thrustfactor; - players[i].accelstart = rsp->accelstart; - players[i].acceleration = rsp->acceleration; - players[i].charability = rsp->charability; - players[i].charability2 = rsp->charability2; - players[i].charflags = (UINT32)LONG(rsp->charflags); - players[i].thokitem = (UINT32)LONG(rsp->thokitem); //mobjtype_t - players[i].spinitem = (UINT32)LONG(rsp->spinitem); //mobjtype_t - players[i].revitem = (UINT32)LONG(rsp->revitem); //mobjtype_t - players[i].followitem = (UINT32)LONG(rsp->followitem); //mobjtype_t - players[i].actionspd = (fixed_t)LONG(rsp->actionspd); - players[i].mindash = (fixed_t)LONG(rsp->mindash); - players[i].maxdash = (fixed_t)LONG(rsp->maxdash); - players[i].jumpfactor = (fixed_t)LONG(rsp->jumpfactor); - players[i].height = (fixed_t)LONG(rsp->playerheight); - players[i].spinheight = (fixed_t)LONG(rsp->playerspinheight); - - players[i].speed = (fixed_t)LONG(rsp->speed); - players[i].secondjump = rsp->secondjump; - players[i].fly1 = rsp->fly1; - players[i].glidetime = (tic_t)LONG(rsp->glidetime); - players[i].climbing = rsp->climbing; - players[i].deadtimer = rsp->deadtimer; - players[i].exiting = (tic_t)LONG(rsp->exiting); - players[i].homing = rsp->homing; - players[i].dashmode = (tic_t)LONG(rsp->dashmode); - players[i].skidtime = (tic_t)LONG(rsp->skidtime); - players[i].cmomx = (fixed_t)LONG(rsp->cmomx); - players[i].cmomy = (fixed_t)LONG(rsp->cmomy); - players[i].rmomx = (fixed_t)LONG(rsp->rmomx); - players[i].rmomy = (fixed_t)LONG(rsp->rmomy); - - players[i].weapondelay = LONG(rsp->weapondelay); - players[i].tossdelay = LONG(rsp->tossdelay); - - players[i].starpostx = SHORT(rsp->starpostx); - players[i].starposty = SHORT(rsp->starposty); - players[i].starpostz = SHORT(rsp->starpostz); - players[i].starpostnum = LONG(rsp->starpostnum); - players[i].starposttime = (tic_t)LONG(rsp->starposttime); - players[i].starpostangle = (angle_t)LONG(rsp->starpostangle); - players[i].starpostscale = (fixed_t)LONG(rsp->starpostscale); - - players[i].maxlink = LONG(rsp->maxlink); - players[i].dashspeed = (fixed_t)LONG(rsp->dashspeed); - players[i].angle_pos = (angle_t)LONG(rsp->angle_pos); - players[i].old_angle_pos = (angle_t)LONG(rsp->old_angle_pos); - players[i].bumpertime = (tic_t)LONG(rsp->bumpertime); - players[i].flyangle = LONG(rsp->flyangle); - players[i].drilltimer = (tic_t)LONG(rsp->drilltimer); - players[i].linkcount = LONG(rsp->linkcount); - players[i].linktimer = (tic_t)LONG(rsp->linktimer); - players[i].anotherflyangle = LONG(rsp->anotherflyangle); - players[i].nightstime = (tic_t)LONG(rsp->nightstime); - players[i].drillmeter = LONG(rsp->drillmeter); - players[i].drilldelay = rsp->drilldelay; - players[i].bonustime = rsp->bonustime; - players[i].mare = rsp->mare; - players[i].lastsidehit = SHORT(rsp->lastsidehit); - players[i].lastlinehit = SHORT(rsp->lastlinehit); - - players[i].losstime = (tic_t)LONG(rsp->losstime); - players[i].timeshit = rsp->timeshit; - players[i].onconveyor = LONG(rsp->onconveyor); - - //We get a packet for each player in game. - if (!playeringame[i]) - return; - - //...but keep old mo even if it is corrupt or null! - players[i].mo = savedmo; - - //Transfer important mo information if they have a valid mo. - if (!rsp->hasmo) - return; - - //server thinks player has a body. - //Give them a new body that can be then manipulated by the server's info. - if (!players[i].mo) //client thinks it has no body. - P_SpawnPlayer(i); - - //At this point, the player should have a body, whether they were respawned or not. - P_UnsetThingPosition(players[i].mo); - players[i].mo->angle = (angle_t)LONG(rsp->angle); - players[i].mo->rollangle = (angle_t)LONG(rsp->rollangle); - players[i].mo->eflags = (UINT16)SHORT(rsp->eflags); - players[i].mo->flags = LONG(rsp->flags); - players[i].mo->flags2 = LONG(rsp->flags2); - players[i].mo->friction = LONG(rsp->friction); - players[i].mo->health = LONG(rsp->health); - players[i].mo->momx = LONG(rsp->momx); - players[i].mo->momy = LONG(rsp->momy); - players[i].mo->momz = LONG(rsp->momz); - players[i].mo->movefactor = LONG(rsp->movefactor); - - // Don't use P_SetMobjStateNF to restore state, write/read all the values manually! - // This should stop those stupid console errors, hopefully. - // -- Monster Iestyn - players[i].mo->sprite = (spritenum_t)LONG(rsp->sprite); - players[i].mo->frame = LONG(rsp->frame); - players[i].mo->sprite2 = rsp->sprite2; - players[i].mo->anim_duration = SHORT(rsp->anim_duration); - players[i].mo->tics = LONG(rsp->tics); - players[i].mo->state = &states[LONG(rsp->statenum)]; - - players[i].mo->x = LONG(rsp->x); - players[i].mo->y = LONG(rsp->y); - players[i].mo->z = LONG(rsp->z); - players[i].mo->radius = LONG(rsp->radius); - players[i].mo->height = LONG(rsp->height); - // P_SetScale is redundant for this, as all related variables are already restored properly. - players[i].mo->scale = LONG(rsp->scale); - players[i].mo->destscale = LONG(rsp->destscale); - players[i].mo->scalespeed = LONG(rsp->scalespeed); - - // And finally, SET THE MOBJ SKIN damn it. - if ((players[i].powers[pw_carry] == CR_NIGHTSMODE) && (skins[players[i].skin].sprites[SPR2_NFLY].numframes == 0)) - { - players[i].mo->skin = &skins[DEFAULTNIGHTSSKIN]; - players[i].mo->color = skins[DEFAULTNIGHTSSKIN].prefcolor; // this will be corrected by thinker to super flash - } - else - { - players[i].mo->skin = &skins[players[i].skin]; - players[i].mo->color = players[i].skincolor; // this will be corrected by thinker to super flash/mario star - } - - P_SetThingPosition(players[i].mo); -} - -static inline void resynch_write_ctf(resynchend_pak *rst) -{ - mobj_t *mflag; - UINT8 i, j; - - for (i = 0, mflag = redflag; i < 2; ++i, mflag = blueflag) - { - rst->flagx[i] = rst->flagy[i] = rst->flagz[i] = 0; - rst->flagloose[i] = rst->flagflags[i] = 0; - rst->flagplayer[i] = -1; - - if (!mflag) - { - // Should be held by a player - for (j = 0; j < MAXPLAYERS; ++j) - { - // GF_REDFLAG is 1, GF_BLUEFLAG is 2 - // redflag handling is i=0, blueflag is i=1 - // so check for gotflag == (i+1) - if (!playeringame[j] || players[j].gotflag != (i+1)) - continue; - rst->flagplayer[i] = (SINT8)j; - break; - } - if (j == MAXPLAYERS) // fine, no I_Error - { - CONS_Alert(CONS_ERROR, "One of the flags has gone completely missing...\n"); - rst->flagplayer[i] = -2; - } - continue; - } - - rst->flagx[i] = (fixed_t)LONG(mflag->x); - rst->flagy[i] = (fixed_t)LONG(mflag->y); - rst->flagz[i] = (fixed_t)LONG(mflag->z); - rst->flagflags[i] = LONG(mflag->flags2); - rst->flagloose[i] = LONG(mflag->fuse); // Dropped or not? - } -} - -static inline void resynch_read_ctf(resynchend_pak *p) -{ - UINT8 i; - - for (i = 0; i < MAXPLAYERS; ++i) - players[i].gotflag = 0; - - // Red flag - if (p->flagplayer[0] == -2) - ; // The server doesn't even know what happened to it... - else if (p->flagplayer[0] != -1) // Held by a player - { - if (!playeringame[p->flagplayer[0]]) - I_Error("Invalid red flag player %d who isn't in the game!", (INT32)p->flagplayer[0]); - players[p->flagplayer[0]].gotflag = GF_REDFLAG; - if (redflag) - { - P_RemoveMobj(redflag); - redflag = NULL; - } - } - else - { - if (!redflag) - redflag = P_SpawnMobj(0,0,0,MT_REDFLAG); - - P_UnsetThingPosition(redflag); - redflag->x = (fixed_t)LONG(p->flagx[0]); - redflag->y = (fixed_t)LONG(p->flagy[0]); - redflag->z = (fixed_t)LONG(p->flagz[0]); - redflag->flags2 = LONG(p->flagflags[0]); - redflag->fuse = LONG(p->flagloose[0]); - P_SetThingPosition(redflag); - } - - // Blue flag - if (p->flagplayer[1] == -2) - ; // The server doesn't even know what happened to it... - else if (p->flagplayer[1] != -1) // Held by a player - { - if (!playeringame[p->flagplayer[1]]) - I_Error("Invalid blue flag player %d who isn't in the game!", (INT32)p->flagplayer[1]); - players[p->flagplayer[1]].gotflag = GF_BLUEFLAG; - if (blueflag) - { - P_RemoveMobj(blueflag); - blueflag = NULL; - } - } - else - { - if (!blueflag) - blueflag = P_SpawnMobj(0,0,0,MT_BLUEFLAG); - - P_UnsetThingPosition(blueflag); - blueflag->x = (fixed_t)LONG(p->flagx[1]); - blueflag->y = (fixed_t)LONG(p->flagy[1]); - blueflag->z = (fixed_t)LONG(p->flagz[1]); - blueflag->flags2 = LONG(p->flagflags[1]); - blueflag->fuse = LONG(p->flagloose[1]); - P_SetThingPosition(blueflag); - } -} - -static inline void resynch_write_others(resynchend_pak *rst) -{ - UINT8 i; - - rst->ingame = 0; - rst->outofcoop = 0; - - for (i = 0; i < MAXPLAYERS; ++i) - { - if (!playeringame[i]) - { - rst->ctfteam[i] = 0; - rst->score[i] = 0; - rst->numboxes[i] = 0; - rst->totalring[i] = 0; - rst->realtime[i] = 0; - rst->laps[i] = 0; - continue; - } - - if (!players[i].spectator) - rst->ingame |= (1<outofcoop |= (1<ctfteam[i] = (INT32)LONG(players[i].ctfteam); - rst->score[i] = (UINT32)LONG(players[i].score); - rst->numboxes[i] = SHORT(players[i].numboxes); - rst->totalring[i] = SHORT(players[i].totalring); - rst->realtime[i] = (tic_t)LONG(players[i].realtime); - rst->laps[i] = players[i].laps; - } - - // endian safeness - rst->ingame = (UINT32)LONG(rst->ingame); -} - -static inline void resynch_read_others(resynchend_pak *p) -{ - UINT8 i; - UINT32 loc_ingame = (UINT32)LONG(p->ingame); - UINT32 loc_outofcoop = (UINT32)LONG(p->outofcoop); - - for (i = 0; i < MAXPLAYERS; ++i) - { - // We don't care if they're in the game or not, just write all the data. - players[i].spectator = !(loc_ingame & (1<ctfteam[i]); // no, 0 does not mean spectator, at least not in Match - players[i].score = (UINT32)LONG(p->score[i]); - players[i].numboxes = SHORT(p->numboxes[i]); - players[i].totalring = SHORT(p->totalring[i]); - players[i].realtime = (tic_t)LONG(p->realtime[i]); - players[i].laps = p->laps[i]; - } -} - -static void SV_InitResynchVars(INT32 node) -{ - resynch_delay[node] = TICRATE; // initial one second delay - resynch_score[node] = 0; // clean slate - resynch_status[node] = 0x00; - resynch_inprogress[node] = false; - memset(resynch_sent[node], 0, MAXPLAYERS); -} - -static void SV_RequireResynch(INT32 node) -{ - INT32 i; - - resynch_delay[node] = 10; // Delay before you can fail sync again - resynch_score[node] += 200; // Add score for initial desynch - resynch_status[node] = 0xFFFFFFFF; // No players assumed synched - resynch_inprogress[node] = true; // so we know to send a PT_RESYNCHEND after sync - - // Initial setup - memset(resynch_sent[node], 0, MAXPLAYERS); - for (i = 0; i < MAXPLAYERS; ++i) - { - if (!playeringame[i]) // Player not in game so just drop it from required synch - resynch_status[node] &= ~(1<>1)+1; - } -} - -static void SV_SendResynch(INT32 node) -{ - INT32 i, j; - - if (!nodeingame[node]) - { - // player left during resynch - // so obviously we don't need to do any of this anymore - resynch_inprogress[node] = false; - return; - } - - // resynched? - if (!resynch_status[node]) - { - // you are now synched - resynch_inprogress[node] = false; - - netbuffer->packettype = PT_RESYNCHEND; - - netbuffer->u.resynchend.randomseed = P_GetRandSeed(); - if (gametyperules & GTR_TEAMFLAGS) - resynch_write_ctf(&netbuffer->u.resynchend); - resynch_write_others(&netbuffer->u.resynchend); - - HSendPacket(node, true, 0, (sizeof(resynchend_pak))); - return; - } - - netbuffer->packettype = PT_RESYNCHING; - for (i = 0, j = 0; i < MAXPLAYERS; ++i) - { - // if already synched don't bother - if (!(resynch_status[node] & 1<u.resynchpak, i); - HSendPacket(node, false, 0, (sizeof(resynch_pak))); - - resynch_sent[node][i] = TICRATE; - resynch_score[node] += 2; // penalty for send - - if (++j > 3) - break; - } - - if (resynch_score[node] > (unsigned)cv_resynchattempts.value*250) - { - SendKick(nodetoplayer[node], KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - resynch_score[node] = 0; - } -} - -static void CL_AcknowledgeResynch(resynch_pak *rsp) -{ - resynch_read_player(rsp); - - netbuffer->packettype = PT_RESYNCHGET; - netbuffer->u.resynchgot = rsp->playernum; - HSendPacket(servernode, true, 0, sizeof(UINT8)); -} - -static void SV_AcknowledgeResynchAck(INT32 node, UINT8 rsg) -{ - if (rsg >= MAXPLAYERS) - resynch_score[node] += 16384; // lol. - else - { - resynch_status[node] &= ~(1<packettype = PT_RECEIVEDGAMESTATE; + HSendPacket(servernode, true, 0, 0); } static void CL_ReloadReceivedSavegame(void) @@ -2535,7 +1943,6 @@ void CL_Reset(void) multiplayer = false; servernode = 0; server = true; - resynch_local_inprogress = false; doomcom->numnodes = 1; doomcom->numslots = 1; SV_StopServer(); @@ -3112,7 +2519,7 @@ static void ResetNode(INT32 node) nodewaiting[node] = 0; playerpernode[node] = 0; sendingsavegame[node] = false; - SV_InitResynchVars(node); + resendingsavegame[node] = false; } void SV_ResetServer(void) @@ -3634,12 +3041,6 @@ static void HandleConnect(SINT8 node) #endif SV_AddNode(node); - /// \note Wait what??? - /// What if the gamestate takes more than one second to get downloaded? - /// Or if a lagspike happens? - // you get a free second before desynch checks. use it wisely. - SV_InitResynchVars(node); - if (cv_joinnextround.value && gameaction == ga_nothing) G_SetGamestate(GS_WAITINGPLAYERS); if (!SV_SendServerConfig(node)) @@ -3762,6 +3163,7 @@ static void PT_CanReceiveGamestate(SINT8 node) CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[nodetoplayer[node]]); SV_SendSaveGame(node, true); // Resend a complete game state + resendingsavegame[node] = true; } /** Handles a packet received from a node that isn't in game @@ -3976,11 +3378,6 @@ static void HandlePacketFromPlayer(SINT8 node) switch (netbuffer->packettype) { // -------------------------------------------- SERVER RECEIVE ---------- - case PT_RESYNCHGET: - if (client) - break; - SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot); - break; case PT_CLIENTCMD: case PT_CLIENT2CMD: case PT_CLIENTMIS: @@ -3990,10 +3387,6 @@ static void HandlePacketFromPlayer(SINT8 node) if (client) break; - // Ignore tics from those not synched - if (resynch_inprogress[node] && nettics[node] == gametic) - break; - // To save bytes, only the low byte of tic numbers are sent // Use ExpandTics to figure out what the rest of the bytes are realstart = ExpandTics(netbuffer->u.clientpak.client_tic); @@ -4020,9 +3413,6 @@ static void HandlePacketFromPlayer(SINT8 node) || netbuffer->packettype == PT_NODEKEEPALIVEMIS) break; - // If a client sends a ticcmd it should mean they are done receiving the savegame - sendingsavegame[node] = false; - // As long as clients send valid ticcmds, the server can keep running, so reset the timeout /// \todo Use a separate cvar for that kind of timeout? freezetimeout[node] = I_GetTime() + connectiontimeout; @@ -4047,21 +3437,19 @@ static void HandlePacketFromPlayer(SINT8 node) G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], &netbuffer->u.client2pak.cmd2, 1); - // A delay before we check resynching - // Used on join or just after a synch fail - if (resynch_delay[node]) - { - --resynch_delay[node]; - break; - } // Check player consistancy during the level if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 && gamestate == GS_LEVEL - && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy)) + && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) + && !resendingsavegame[node]) { - SV_RequireResynch(node); - - if (cv_resynchattempts.value && resynch_score[node] <= (unsigned)cv_resynchattempts.value*250) + if (cv_resynchattempts.value) { + // Tell the client we are about to resend them the gamestate + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + HSendPacket(node, true, 0, 0); + + resendingsavegame[node] = true; + if (cv_blamecfail.value) CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), netconsole+1, player_names[netconsole], @@ -4081,8 +3469,6 @@ static void HandlePacketFromPlayer(SINT8 node) break; } } - else if (resynch_score[node]) - --resynch_score[node]; break; case PT_TEXTCMD2: // splitscreen special netconsole = nodetoplayer2[node]; @@ -4211,25 +3597,11 @@ static void HandlePacketFromPlayer(SINT8 node) case PT_CANRECEIVEGAMESTATE: PT_CanReceiveGamestate(node); break; -// -------------------------------------------- CLIENT RECEIVE ---------- - case PT_RESYNCHEND: - // Only accept PT_RESYNCHEND from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHEND", node); - if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - break; - } - resynch_local_inprogress = false; - - P_SetRandSeed(netbuffer->u.resynchend.randomseed); - - if (gametyperules & GTR_TEAMFLAGS) - resynch_read_ctf(&netbuffer->u.resynchend); - resynch_read_others(&netbuffer->u.resynchend); - + case PT_RECEIVEDGAMESTATE: + sendingsavegame[node] = false; + resendingsavegame[node] = false; break; +// -------------------------------------------- CLIENT RECEIVE ---------- case PT_SERVERTICS: // Only accept PT_SERVERTICS from the server. if (node != servernode) @@ -4293,18 +3665,6 @@ static void HandlePacketFromPlayer(SINT8 node) "IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/ } break; - case PT_RESYNCHING: - // Only accept PT_RESYNCHING from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHING", node); - if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - break; - } - resynch_local_inprogress = true; - CL_AcknowledgeResynch(&netbuffer->u.resynchpak); - break; case PT_PING: // Only accept PT_PING from the server. if (node != servernode) @@ -4832,7 +4192,7 @@ void TryRunTics(tic_t realtics) if (player_joining) return; - if (neededtic > gametic && !resynch_local_inprogress) + if (neededtic > gametic) { if (advancedemo) { @@ -4991,9 +4351,9 @@ void NetUpdate(void) if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND) CL_ReloadReceivedSavegame(); - if (!(resynch_local_inprogress || cl_redownloadinggamestate)) + if (!cl_redownloadinggamestate) CL_SendClientCmd(); // Send tic cmd - hu_resynching = resynch_local_inprogress; + hu_redownloadinggamestate = cl_redownloadinggamestate; } else { @@ -5001,7 +4361,7 @@ void NetUpdate(void) { INT32 counts; - hu_resynching = false; + hu_redownloadinggamestate = false; firstticstosend = gametic; for (i = 0; i < MAXNETNODES; i++) @@ -5011,18 +4371,6 @@ void NetUpdate(void) // Don't erase tics not acknowledged counts = realtics; - for (i = 0; i < MAXNETNODES; ++i) - if (resynch_inprogress[i]) - { - if (!nodeingame[i] || nettics[i] == gametic) - { - SV_SendResynch(i); - counts = -666; - } - else - counts = 0; // Let the client catch up with the server - } - // Do not make tics while resynching if (counts != -666) { @@ -5040,7 +4388,7 @@ void NetUpdate(void) neededtic = maketic; // The server is a client too } else - hu_resynching = true; + hu_redownloadinggamestate = true; } } Net_AckTicker(); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 0f1998d51..81ea17638 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -64,11 +64,10 @@ typedef enum PT_REQUESTFILE, // Client requests a file transfer PT_ASKINFOVIAMS, // Packet from the MS requesting info be sent to new client. // If this ID changes, update masterserver definition. - PT_RESYNCHEND, // Player is now resynched and is being requested to remake the gametic - PT_RESYNCHGET, // Player got resynch packet PT_WILLRESENDGAMESTATE, // Hey Client, I am about to resend you the gamestate! - PT_CANRECEIVEGAMESTATE, // Okay Server, I'm ready to receive it, you can go ahead. + PT_CANRECEIVEGAMESTATE, // Okay Server, I'm ready to receive it, you can go ahead. + PT_RECEIVEDGAMESTATE, // Thank you Server, I am ready to play again! // Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility. @@ -82,8 +81,6 @@ typedef enum PT_TEXTCMD2, // Splitscreen text commands. PT_CLIENTJOIN, // Client wants to join; used in start game. PT_NODETIMEOUT, // Packet sent to self if the connection times out. - PT_RESYNCHING, // Packet sent to resync players. - // Blocks game advance until synched. PT_LOGIN, // Login attempt from the client. @@ -136,165 +133,6 @@ typedef struct ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large } ATTRPACK servertics_pak; -// Sent to client when all consistency data -// for players has been restored -typedef struct -{ - UINT32 randomseed; - - // CTF flag stuff - SINT8 flagplayer[2]; - INT32 flagloose[2]; - INT32 flagflags[2]; - fixed_t flagx[2]; - fixed_t flagy[2]; - fixed_t flagz[2]; - - UINT32 ingame; // Spectator bit for each player - UINT32 outofcoop; // outofcoop bit for each player - INT32 ctfteam[MAXPLAYERS]; // Which team? (can't be 1 bit, since in regular Match there are no teams) - - // Resynch game scores and the like all at once - UINT32 score[MAXPLAYERS]; // Everyone's score - INT16 numboxes[MAXPLAYERS]; - INT16 totalring[MAXPLAYERS]; - tic_t realtime[MAXPLAYERS]; - UINT8 laps[MAXPLAYERS]; -} ATTRPACK resynchend_pak; - -typedef struct -{ - // Player stuff - UINT8 playernum; - - // Do not send anything visual related. - // Only send data that we need to know for physics. - UINT8 playerstate; // playerstate_t - UINT32 pflags; // pflags_t - UINT8 panim; // panim_t - - angle_t aiming; - INT32 currentweapon; - INT32 ringweapons; - UINT16 ammoremoval; - tic_t ammoremovaltimer; - INT32 ammoremovalweapon; - UINT16 powers[NUMPOWERS]; - - // Score is resynched in the confirm resync packet - INT16 rings; - INT16 spheres; - SINT8 lives; - SINT8 continues; - UINT8 scoreadd; - SINT8 xtralife; - SINT8 pity; - - UINT8 skincolor; - INT32 skin; - UINT32 availabilities; - // Just in case Lua does something like - // modify these at runtime - fixed_t camerascale; - fixed_t shieldscale; - fixed_t normalspeed; - fixed_t runspeed; - UINT8 thrustfactor; - UINT8 accelstart; - UINT8 acceleration; - UINT8 charability; - UINT8 charability2; - UINT32 charflags; - UINT32 thokitem; // mobjtype_t - UINT32 spinitem; // mobjtype_t - UINT32 revitem; // mobjtype_t - UINT32 followitem; // mobjtype_t - fixed_t actionspd; - fixed_t mindash; - fixed_t maxdash; - fixed_t jumpfactor; - fixed_t playerheight; - fixed_t playerspinheight; - - fixed_t speed; - UINT8 secondjump; - UINT8 fly1; - tic_t glidetime; - UINT8 climbing; - INT32 deadtimer; - tic_t exiting; - UINT8 homing; - tic_t dashmode; - tic_t skidtime; - fixed_t cmomx; - fixed_t cmomy; - fixed_t rmomx; - fixed_t rmomy; - - INT32 weapondelay; - INT32 tossdelay; - - INT16 starpostx; - INT16 starposty; - INT16 starpostz; - INT32 starpostnum; - tic_t starposttime; - angle_t starpostangle; - fixed_t starpostscale; - - INT32 maxlink; - fixed_t dashspeed; - angle_t angle_pos; - angle_t old_angle_pos; - tic_t bumpertime; - INT32 flyangle; - tic_t drilltimer; - INT32 linkcount; - tic_t linktimer; - INT32 anotherflyangle; - tic_t nightstime; - INT32 drillmeter; - UINT8 drilldelay; - UINT8 bonustime; - UINT8 mare; - INT16 lastsidehit, lastlinehit; - - tic_t losstime; - UINT8 timeshit; - INT32 onconveyor; - - //player->mo stuff - UINT8 hasmo; // Boolean - - INT32 health; - angle_t angle; - angle_t rollangle; - fixed_t x; - fixed_t y; - fixed_t z; - fixed_t momx; - fixed_t momy; - fixed_t momz; - fixed_t friction; - fixed_t movefactor; - - spritenum_t sprite; - UINT32 frame; - UINT8 sprite2; - UINT16 anim_duration; - INT32 tics; - statenum_t statenum; - UINT32 flags; - UINT32 flags2; - UINT16 eflags; - - fixed_t radius; - fixed_t height; - fixed_t scale; - fixed_t destscale; - fixed_t scalespeed; -} ATTRPACK resynch_pak; - typedef struct { UINT8 version; // Different versions don't work @@ -430,9 +268,6 @@ typedef struct client2cmd_pak client2pak; // 200 bytes servertics_pak serverpak; // 132495 bytes (more around 360, no?) serverconfig_pak servercfg; // 773 bytes - resynchend_pak resynchend; // - resynch_pak resynchpak; // - UINT8 resynchgot; // UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...) filetx_pak filetxpak; // 139 bytes clientconfig_pak clientcfg; // 136 bytes @@ -567,7 +402,7 @@ UINT8 GetFreeXCmdSize(void); void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest); -extern UINT8 hu_resynching; +extern UINT8 hu_redownloadinggamestate; extern UINT8 adminpassmd5[16]; extern boolean adminpasswordset; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 98f3ca5a9..561c04677 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2206,7 +2206,7 @@ void HU_Drawer(void) HU_DrawCrosshair2(); // draw desynch text - if (hu_resynching) + if (hu_redownloadinggamestate) { static UINT32 resynch_ticker = 0; char resynch_text[14]; From 46d8546f49335334092e0a67219bb914866d77b3 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sun, 1 Mar 2020 03:26:15 +0100 Subject: [PATCH 06/53] Update packet names --- src/d_net.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/d_net.c b/src/d_net.c index 140226990..703e9810e 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -796,18 +796,15 @@ static const char *packettypename[NUMPACKETTYPE] = "REQUESTFILE", "ASKINFOVIAMS", - "RESYNCHEND", - "RESYNCHGET", - "WILLRESENDGAMESTATE", - "CANRESENDGAMESTATE", + "CANRECEIVEGAMESTATE", + "RECEIVEDGAMESTATE", "FILEFRAGMENT", "TEXTCMD", "TEXTCMD2", "CLIENTJOIN", "NODETIMEOUT", - "RESYNCHING", "PING" }; From b85ac6537804b7ea38ebb5cba69d3ae33d3ad50b Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sun, 8 Mar 2020 20:04:29 +0100 Subject: [PATCH 07/53] Fix missing break --- src/d_clisrv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index de477c99b..9e0294152 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3604,6 +3604,7 @@ static void HandlePacketFromPlayer(SINT8 node) break; case PT_CANRECEIVEGAMESTATE: PT_CanReceiveGamestate(node); + break; #ifdef HAVE_BLUA case PT_ASKLUAFILE: if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_ASKED) From 121c7da8090b3796c1d74ae196f57236a3c9f8c6 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sat, 3 Oct 2020 16:31:04 +0200 Subject: [PATCH 08/53] Let Lua scripts relink tables to their metatables when unarchiving This is done through the new "registermetatable" function, in a somewhat similar fashion to "freeslot" but for metatables: it must be called at script load to tell SRB2 your metatable can be automatically relinked during the unarchiving process. --- src/lua_baselib.c | 28 ++++++++++++++++++++++++++++ src/lua_libs.h | 1 + src/lua_script.c | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 6b25e32ea..6bdc65786 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -238,6 +238,33 @@ static int lib_userdataType(lua_State *L) return luaL_typerror(L, 1, "userdata"); } +// Takes a metatable as first and only argument +// Only callable during script loading +static int lib_registermetatable(lua_State *L) +{ + static UINT32 nextid = 1; + + if (!lua_lumploading) + return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); + luaL_checktype(L, 1, LUA_TTABLE); + + lua_getfield(L, LUA_REGISTRYINDEX, LREG_METATABLES); // 2 + // registry.metatables[metatable] = nextid + lua_pushvalue(L, 1); // 3 + lua_pushnumber(L, nextid); // 4 + lua_settable(L, 2); + + // registry.metatables[nextid] = metatable + lua_pushnumber(L, nextid); // 3 + lua_pushvalue(L, 1); // 4 + lua_settable(L, 2); + lua_pop(L, 1); + + nextid++; + + return 0; +} + static int lib_isPlayerAdmin(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -3433,6 +3460,7 @@ static luaL_Reg lib[] = { {"chatprint", lib_chatprint}, {"chatprintf", lib_chatprintf}, {"userdataType", lib_userdataType}, + {"registermetatable", lib_registermetatable}, {"IsPlayerAdmin", lib_isPlayerAdmin}, {"reserveLuabanks", lib_reserveLuabanks}, diff --git a/src/lua_libs.h b/src/lua_libs.h index f987c79fd..e1b2a2d1c 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -16,6 +16,7 @@ extern lua_State *gL; #define LREG_EXTVARS "LUA_VARS" #define LREG_STATEACTION "STATE_ACTION" #define LREG_ACTIONS "MOBJ_ACTION" +#define LREG_METATABLES "METATABLES" #define META_STATE "STATE_T*" #define META_MOBJINFO "MOBJINFO_T*" diff --git a/src/lua_script.c b/src/lua_script.c index 0260f018a..0edcbe6ba 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -437,6 +437,10 @@ static void LUA_ClearState(void) lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, LREG_VALID); + // make LREG_METATABLES table for all registered metatables + lua_newtable(L); + lua_setfield(L, LUA_REGISTRYINDEX, LREG_METATABLES); + // open srb2 libraries for(i = 0; liblist[i]; i++) { lua_pushcfunction(L, liblist[i]); @@ -1269,8 +1273,22 @@ static void ArchiveTables(void) lua_pop(gL, 1); } - lua_pop(gL, 1); WRITEUINT8(save_p, ARCH_TEND); + + // Write metatable ID + if (lua_getmetatable(gL, -1)) + { + // registry.metatables[metatable] + lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES); + lua_pushvalue(gL, -2); + lua_gettable(gL, -2); + WRITEUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1)); + lua_pop(gL, 3); + } + else + WRITEUINT16(save_p, 0); + + lua_pop(gL, 1); } } @@ -1438,6 +1456,7 @@ static void UnArchiveTables(void) { int TABLESINDEX; UINT16 i, n; + UINT16 metatableid; if (!gL) return; @@ -1462,6 +1481,19 @@ static void UnArchiveTables(void) else lua_rawset(gL, -3); } + + metatableid = READUINT16(save_p); + if (metatableid) + { + // setmetatable(table, registry.metatables[metatableid]) + lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES); + lua_rawgeti(gL, -1, metatableid); + if (lua_isnil(gL, -1)) + I_Error("Unknown metatable ID %d\n", metatableid); + lua_setmetatable(gL, -3); + lua_pop(gL, 1); + } + lua_pop(gL, 1); } } From e49032eaf74331162ad491963fe99ce9d4a979a4 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sat, 3 Oct 2020 18:40:37 +0200 Subject: [PATCH 09/53] Let Lua scripts access userdata metatables --- src/lua_baselib.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 6bdc65786..6f9bcbb23 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -240,7 +240,7 @@ static int lib_userdataType(lua_State *L) // Takes a metatable as first and only argument // Only callable during script loading -static int lib_registermetatable(lua_State *L) +static int lib_registerMetatable(lua_State *L) { static UINT32 nextid = 1; @@ -265,6 +265,16 @@ static int lib_registermetatable(lua_State *L) return 0; } +// Takes a string as only argument and returns the metatable +// associated to the userdata type this string refers to +// Returns nil if the string does not refer to a valid userdata type +static int lib_userdataMetatable(lua_State *L) +{ + const char *udname = luaL_checkstring(L, 1); + luaL_getmetatable(L, udname); + return 1; +} + static int lib_isPlayerAdmin(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -3460,7 +3470,8 @@ static luaL_Reg lib[] = { {"chatprint", lib_chatprint}, {"chatprintf", lib_chatprintf}, {"userdataType", lib_userdataType}, - {"registermetatable", lib_registermetatable}, + {"registerMetatable", lib_registerMetatable}, + {"userdataMetatable", lib_userdataMetatable}, {"IsPlayerAdmin", lib_isPlayerAdmin}, {"reserveLuabanks", lib_reserveLuabanks}, From 0811f60b2a5634c587e39ec22c8408bb948f8e88 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Fri, 9 Oct 2020 02:06:13 -0300 Subject: [PATCH 10/53] Let the server or an admin toggle clients' custom shaders --- src/hardware/hw_defs.h | 10 + src/hardware/hw_drv.h | 2 +- src/hardware/hw_main.c | 41 ++-- src/hardware/hw_main.h | 4 +- src/hardware/r_opengl/r_opengl.c | 371 +++++++++++++++++-------------- src/sdl/ogl_sdl.c | 2 +- src/w_wad.c | 2 + 7 files changed, 250 insertions(+), 182 deletions(-) diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 607d21ef5..644ab0ca2 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -295,6 +295,16 @@ enum hwdsetspecialstate typedef enum hwdsetspecialstate hwdspecialstate_t; +// Lactozilla: Shader options +enum hwdshaderoption +{ + HWD_SHADEROPTION_OFF, + HWD_SHADEROPTION_ON, + HWD_SHADEROPTION_NOCUSTOM, +}; + +typedef enum hwdshaderoption hwdshaderoption_t; + // Lactozilla: Shader info // Generally set at the start of the frame. enum hwdshaderinfo diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index aaa41e86f..266134105 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -70,7 +70,7 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); // jimita EXPORT boolean HWRAPI(CompileShaders) (void); EXPORT void HWRAPI(CleanShaders) (void); -EXPORT void HWRAPI(SetShader) (int shader); +EXPORT void HWRAPI(SetShader) (int type); EXPORT void HWRAPI(UnSetShader) (void); EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a7015b3dc..60ec669e4 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5555,6 +5555,20 @@ static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean trans->anglex = (float)(gl_aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); } +// +// Sets the shader state. +// +static void HWR_SetShaderState(void) +{ + hwdshaderoption_t state = cv_glshaders.value; + + if (!cv_glallowshaders.value) + state = (cv_glshaders.value == HWD_SHADEROPTION_ON ? HWD_SHADEROPTION_NOCUSTOM : cv_glshaders.value); + + HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)state); + HWD.pfnSetShader(SHADER_DEFAULT); +} + // ========================================================================== // Same as rendering the player view, but from the skybox object // ========================================================================== @@ -5673,8 +5687,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) HWD.pfnSetTransform(&atransform); // Reset the shader state. - HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_glshaders.value); - HWD.pfnSetShader(SHADER_DEFAULT); + HWR_SetShaderState(); validcount++; @@ -5886,8 +5899,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) HWD.pfnSetTransform(&atransform); // Reset the shader state. - HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_glshaders.value); - HWD.pfnSetShader(SHADER_DEFAULT); + HWR_SetShaderState(); rs_numbspcalls = 0; rs_numpolyobjects = 0; @@ -5982,9 +5994,10 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) // 3D ENGINE COMMANDS // ========================================================================== -static CV_PossibleValue_t grmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}}; -static CV_PossibleValue_t grfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}}; -static CV_PossibleValue_t grshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}}; +static CV_PossibleValue_t glshaders_cons_t[] = {{HWD_SHADEROPTION_OFF, "Off"}, {HWD_SHADEROPTION_ON, "On"}, {HWD_SHADEROPTION_NOCUSTOM, "Ignore custom shaders"}, {0, NULL}}; +static CV_PossibleValue_t glmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}}; +static CV_PossibleValue_t glfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}}; +static CV_PossibleValue_t glshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}}; static void CV_glfiltermode_OnChange(void); static void CV_glanisotropic_OnChange(void); @@ -5995,9 +6008,10 @@ static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA {HWD_SET_TEXTUREFILTER_MIXED2, "Nearest_Linear"}, {HWD_SET_TEXTUREFILTER_MIXED3, "Nearest_Mipmap"}, {0, NULL}}; -CV_PossibleValue_t granisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}}; +CV_PossibleValue_t glanisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}}; -consvar_t cv_glshaders = {"gr_shaders", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_glshaders = {"gr_shaders", "On", CV_SAVE, glshaders_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_glallowshaders = {"gr_allowshaders", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_fovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; #ifdef ALAM_LIGHTING @@ -6008,18 +6022,18 @@ consvar_t cv_glcoronasize = {"gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0, NULL, 0, #endif consvar_t cv_glmodels = {"gr_models", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_glmodelinterpolation = {"gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_glmodelinterpolation = {"gr_modelinterpolation", "Sometimes", CV_SAVE, glmodelinterpolation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glmodellighting = {"gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_glshearing = {"gr_shearing", "Off", CV_SAVE, grshearing_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_glshearing = {"gr_shearing", "Off", CV_SAVE, glshearing_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_glfakecontrast = {"gr_fakecontrast", "Smooth", CV_SAVE, grfakecontrast_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_glfakecontrast = {"gr_fakecontrast", "Smooth", CV_SAVE, glfakecontrast_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glslopecontrast = {"gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glfiltermode = {"gr_filtermode", "Nearest", CV_SAVE|CV_CALL, glfiltermode_cons_t, CV_glfiltermode_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_glanisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t, +consvar_t cv_glanisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, glanisotropicmode_cons_t, CV_glanisotropic_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -6059,6 +6073,7 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_glfakecontrast); CV_RegisterVar(&cv_glshearing); CV_RegisterVar(&cv_glshaders); + CV_RegisterVar(&cv_glallowshaders); CV_RegisterVar(&cv_glfiltermode); CV_RegisterVar(&cv_glsolvetjoin); diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 9bce49b25..12c6f9fc5 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -78,7 +78,7 @@ const char *HWR_GetShaderName(INT32 shader); extern customshaderxlat_t shaderxlat[]; -extern CV_PossibleValue_t granisotropicmode_cons_t[]; +extern CV_PossibleValue_t glanisotropicmode_cons_t[]; #ifdef ALAM_LIGHTING extern consvar_t cv_gldynamiclighting; @@ -87,7 +87,7 @@ extern consvar_t cv_glcoronas; extern consvar_t cv_glcoronasize; #endif -extern consvar_t cv_glshaders; +extern consvar_t cv_glshaders, cv_glallowshaders; extern consvar_t cv_glmodels; extern consvar_t cv_glmodelinterpolation; extern consvar_t cv_glmodellighting; diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index db3c6a17d..1d2852d91 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -91,13 +91,6 @@ static GLuint startScreenWipe = 0; static GLuint endScreenWipe = 0; static GLuint finalScreenTexture = 0; -// Lactozilla: Shader functions -static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); -static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); -static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum); - -static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; - // shortcut for ((float)1/i) static const GLfloat byte2float[256] = { 0.000000f, 0.003922f, 0.007843f, 0.011765f, 0.015686f, 0.019608f, 0.023529f, 0.027451f, @@ -533,8 +526,8 @@ boolean SetupGLfunc(void) return true; } -static boolean gl_allowshaders = false; static boolean gl_shadersenabled = false; +static hwdshaderoption_t gl_allowshaders = HWD_SHADEROPTION_OFF; #ifdef GL_SHADERS typedef GLuint (APIENTRY *PFNglCreateShader) (GLenum); @@ -544,6 +537,7 @@ typedef void (APIENTRY *PFNglGetShaderiv) (GLuint, GLenum, GLint*); typedef void (APIENTRY *PFNglGetShaderInfoLog) (GLuint, GLsizei, GLsizei*, GLchar*); typedef void (APIENTRY *PFNglDeleteShader) (GLuint); typedef GLuint (APIENTRY *PFNglCreateProgram) (void); +typedef void (APIENTRY *PFNglDeleteProgram) (GLuint); typedef void (APIENTRY *PFNglAttachShader) (GLuint, GLuint); typedef void (APIENTRY *PFNglLinkProgram) (GLuint); typedef void (APIENTRY *PFNglGetProgramiv) (GLuint, GLenum, GLint*); @@ -565,6 +559,7 @@ static PFNglGetShaderiv pglGetShaderiv; static PFNglGetShaderInfoLog pglGetShaderInfoLog; static PFNglDeleteShader pglDeleteShader; static PFNglCreateProgram pglCreateProgram; +static PFNglDeleteProgram pglDeleteProgram; static PFNglAttachShader pglAttachShader; static PFNglLinkProgram pglLinkProgram; static PFNglGetProgramiv pglGetProgramiv; @@ -579,12 +574,6 @@ static PFNglUniform2fv pglUniform2fv; static PFNglUniform3fv pglUniform3fv; static PFNglGetUniformLocation pglGetUniformLocation; -// 18032019 -static GLuint gl_currentshaderprogram = 0; -static boolean gl_shaderprogramchanged = true; - -static shadersource_t gl_customshaders[HWR_MAXSHADERS]; - // 13062019 typedef enum { @@ -602,17 +591,37 @@ typedef enum gluniform_max, } gluniform_t; -typedef struct gl_shaderprogram_s +typedef struct gl_shader_s { GLuint program; - boolean custom; GLint uniforms[gluniform_max+1]; -} gl_shaderprogram_t; -static gl_shaderprogram_t gl_shaderprograms[HWR_MAXSHADERS]; + boolean custom; +} gl_shader_t; + +static gl_shader_t gl_shaders[HWR_MAXSHADERS]; +static gl_shader_t gl_usershaders[HWR_MAXSHADERS]; +static shadersource_t gl_customshaders[HWR_MAXSHADERS]; + +// 09102020 +typedef struct gl_shaderstate_s +{ + gl_shader_t *current; + GLuint type; + GLuint program; + boolean changed; +} gl_shaderstate_t; +static gl_shaderstate_t gl_shaderstate; // Shader info static INT32 shader_leveltime = 0; +// Lactozilla: Shader functions +static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader); +static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum); +static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); + +static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; + // ================ // Vertex shaders // ================ @@ -873,6 +882,7 @@ void SetupGLFunc4(void) pglGetShaderInfoLog = GetGLFunc("glGetShaderInfoLog"); pglDeleteShader = GetGLFunc("glDeleteShader"); pglCreateProgram = GetGLFunc("glCreateProgram"); + pglDeleteProgram = GetGLFunc("glDeleteProgram"); pglAttachShader = GetGLFunc("glAttachShader"); pglLinkProgram = GetGLFunc("glLinkProgram"); pglGetProgramiv = GetGLFunc("glGetProgramiv"); @@ -896,20 +906,40 @@ void SetupGLFunc4(void) EXPORT boolean HWRAPI(CompileShaders) (void) { #ifdef GL_SHADERS - GLuint gl_vertShader, gl_fragShader; - GLint i, result; + GLint i; - if (!pglUseProgram) return false; + if (!pglUseProgram) + return false; - gl_customshaders[0].vertex = NULL; - gl_customshaders[0].fragment = NULL; + gl_customshaders[SHADER_DEFAULT].vertex = NULL; + gl_customshaders[SHADER_DEFAULT].fragment = NULL; for (i = 0; gl_shadersources[i].vertex && gl_shadersources[i].fragment; i++) { - gl_shaderprogram_t *shader; + gl_shader_t *shader, *usershader; const GLchar *vert_shader = gl_shadersources[i].vertex; const GLchar *frag_shader = gl_shadersources[i].fragment; - boolean custom = ((gl_customshaders[i].vertex || gl_customshaders[i].fragment) && (i > 0)); + + if (i >= HWR_MAXSHADERS) + break; + + shader = &gl_shaders[i]; + usershader = &gl_usershaders[i]; + + if (shader->program) + pglDeleteProgram(shader->program); + if (usershader->program) + pglDeleteProgram(usershader->program); + + shader->program = 0; + usershader->program = 0; + + if (!Shader_CompileProgram(shader, i, vert_shader, frag_shader)) + shader->program = 0; + + // Compile custom shader + if ((i == SHADER_DEFAULT) || !(gl_customshaders[i].vertex || gl_customshaders[i].fragment)) + continue; // 18032019 if (gl_customshaders[i].vertex) @@ -917,92 +947,15 @@ EXPORT boolean HWRAPI(CompileShaders) (void) if (gl_customshaders[i].fragment) frag_shader = gl_customshaders[i].fragment; - if (i >= HWR_MAXSHADERS) - break; - - shader = &gl_shaderprograms[i]; - shader->program = 0; - shader->custom = custom; - - // - // Load and compile vertex shader - // - gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); - if (!gl_vertShader) + if (!Shader_CompileProgram(usershader, i, vert_shader, frag_shader)) { - GL_MSG_Error("CompileShaders: Error creating vertex shader %s\n", HWR_GetShaderName(i)); - continue; + GL_MSG_Warning("CompileShaders: Could not compile custom shader program for %s\n", HWR_GetShaderName(i)); + usershader->program = 0; } - - pglShaderSource(gl_vertShader, 1, &vert_shader, NULL); - pglCompileShader(gl_vertShader); - - // check for compile errors - pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); - if (result == GL_FALSE) - { - Shader_CompileError("Error compiling vertex shader", gl_vertShader, i); - continue; - } - - // - // Load and compile fragment shader - // - gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); - if (!gl_fragShader) - { - GL_MSG_Error("CompileShaders: Error creating fragment shader %s\n", HWR_GetShaderName(i)); - continue; - } - - pglShaderSource(gl_fragShader, 1, &frag_shader, NULL); - pglCompileShader(gl_fragShader); - - // check for compile errors - pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); - if (result == GL_FALSE) - { - Shader_CompileError("Error compiling fragment shader", gl_fragShader, i); - continue; - } - - shader->program = pglCreateProgram(); - pglAttachShader(shader->program, gl_vertShader); - pglAttachShader(shader->program, gl_fragShader); - pglLinkProgram(shader->program); - - // check link status - pglGetProgramiv(shader->program, GL_LINK_STATUS, &result); - - // delete the shader objects - pglDeleteShader(gl_vertShader); - pglDeleteShader(gl_fragShader); - - // couldn't link? - if (result != GL_TRUE) - { - shader->program = 0; - shader->custom = false; - GL_MSG_Error("CompileShaders: Error linking shader program %s\n", HWR_GetShaderName(i)); - continue; - } - - // 13062019 -#define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform); - - // lighting - shader->uniforms[gluniform_poly_color] = GETUNI("poly_color"); - shader->uniforms[gluniform_tint_color] = GETUNI("tint_color"); - shader->uniforms[gluniform_fade_color] = GETUNI("fade_color"); - shader->uniforms[gluniform_lighting] = GETUNI("lighting"); - shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); - shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); - - // misc. (custom shaders) - shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); - -#undef GETUNI } + + SetShader(SHADER_DEFAULT); + return true; #else return false; @@ -1070,26 +1023,45 @@ EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boole #endif } -EXPORT void HWRAPI(SetShader) (int shader) +EXPORT void HWRAPI(SetShader) (int type) { #ifdef GL_SHADERS - if (gl_allowshaders) + if (gl_allowshaders != HWD_SHADEROPTION_OFF) { + gl_shader_t *shader = gl_shaderstate.current; + // If using model lighting, set the appropriate shader. // However don't override a custom shader. - if (shader == SHADER_MODEL && model_lighting - && !(gl_shaderprograms[SHADER_MODEL].custom && !gl_shaderprograms[SHADER_MODEL_LIGHTING].custom)) - shader = SHADER_MODEL_LIGHTING; - if ((GLuint)shader != gl_currentshaderprogram) + if (type == SHADER_MODEL && model_lighting + && !(gl_shaders[SHADER_MODEL].custom && !gl_shaders[SHADER_MODEL_LIGHTING].custom)) + type = SHADER_MODEL_LIGHTING; + + if ((shader == NULL) || (GLuint)type != gl_shaderstate.type) { - gl_currentshaderprogram = shader; - gl_shaderprogramchanged = true; + gl_shader_t *baseshader = &gl_shaders[type]; + gl_shader_t *usershader = &gl_usershaders[type]; + + if (usershader->program) + shader = (gl_allowshaders == HWD_SHADEROPTION_NOCUSTOM) ? baseshader : usershader; + else + shader = baseshader; + + gl_shaderstate.current = shader; + gl_shaderstate.type = type; + gl_shaderstate.changed = true; } - gl_shadersenabled = true; + + if (gl_shaderstate.program != shader->program) + { + gl_shaderstate.program = shader->program; + gl_shaderstate.changed = true; + } + + gl_shadersenabled = (shader->program != 0); return; } #else - (void)shader; + (void)type; #endif gl_shadersenabled = false; } @@ -1097,11 +1069,15 @@ EXPORT void HWRAPI(SetShader) (int shader) EXPORT void HWRAPI(UnSetShader) (void) { #ifdef GL_SHADERS - gl_shadersenabled = false; - gl_currentshaderprogram = 0; - if (!pglUseProgram) return; - pglUseProgram(0); + gl_shaderstate.current = NULL; + gl_shaderstate.type = 0; + gl_shaderstate.program = 0; + + if (pglUseProgram) + pglUseProgram(0); #endif + + gl_shadersenabled = false; } EXPORT void HWRAPI(CleanShaders) (void) @@ -1901,42 +1877,24 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) } } -static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade) -{ -#ifdef GL_SHADERS - if (gl_shadersenabled && pglUseProgram) - { - gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; - if (shader->program) - { - if (gl_shaderprogramchanged) - { - pglUseProgram(gl_shaderprograms[gl_currentshaderprogram].program); - gl_shaderprogramchanged = false; - } - Shader_SetUniforms(Surface, poly, tint, fade); - return shader; - } - else - pglUseProgram(0); - } -#else - (void)Surface; - (void)poly; - (void)tint; - (void)fade; -#endif - return NULL; -} - static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade) { #ifdef GL_SHADERS - if (gl_shadersenabled) + gl_shader_t *shader = gl_shaderstate.current; + + if (gl_shadersenabled && (shader != NULL) && pglUseProgram) { - gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; if (!shader->program) + { + pglUseProgram(0); return; + } + + if (gl_shaderstate.changed) + { + pglUseProgram(shader->program); + gl_shaderstate.changed = false; + } // Color uniforms can be left NULL and will be set to white (1.0f, 1.0f, 1.0f, 1.0f) if (poly == NULL) @@ -1989,6 +1947,97 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF #endif } +static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader) +{ + GLuint gl_vertShader, gl_fragShader; + GLint result; + + // + // Load and compile vertex shader + // + gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); + if (!gl_vertShader) + { + GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i)); + return false; + } + + pglShaderSource(gl_vertShader, 1, &vert_shader, NULL); + pglCompileShader(gl_vertShader); + + // check for compile errors + pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + Shader_CompileError("Error compiling vertex shader", gl_vertShader, i); + pglDeleteShader(gl_vertShader); + return false; + } + + // + // Load and compile fragment shader + // + gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); + if (!gl_fragShader) + { + GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i)); + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + return false; + } + + pglShaderSource(gl_fragShader, 1, &frag_shader, NULL); + pglCompileShader(gl_fragShader); + + // check for compile errors + pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + Shader_CompileError("Error compiling fragment shader", gl_fragShader, i); + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + return false; + } + + shader->program = pglCreateProgram(); + pglAttachShader(shader->program, gl_vertShader); + pglAttachShader(shader->program, gl_fragShader); + pglLinkProgram(shader->program); + + // check link status + pglGetProgramiv(shader->program, GL_LINK_STATUS, &result); + + // delete the shader objects + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + + // couldn't link? + if (result != GL_TRUE) + { + GL_MSG_Error("Shader_CompileProgram: Error linking shader program %s\n", HWR_GetShaderName(i)); + pglDeleteProgram(shader->program); + return false; + } + + // 13062019 +#define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform); + + // lighting + shader->uniforms[gluniform_poly_color] = GETUNI("poly_color"); + shader->uniforms[gluniform_tint_color] = GETUNI("tint_color"); + shader->uniforms[gluniform_fade_color] = GETUNI("fade_color"); + shader->uniforms[gluniform_lighting] = GETUNI("lighting"); + shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); + shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); + + // misc. (custom shaders) + shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); + +#undef GETUNI + + return true; +} + static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum) { GLchar *infoLog = NULL; @@ -2002,7 +2051,7 @@ static void Shader_CompileError(const char *message, GLuint program, INT32 shade pglGetShaderInfoLog(program, logLength, NULL, infoLog); } - GL_MSG_Error("CompileShaders: %s (%s)\n%s", message, HWR_GetShaderName(shadernum), (infoLog ? infoLog : "")); + GL_MSG_Error("Shader_CompileProgram: %s (%s)\n%s", message, HWR_GetShaderName(shadernum), (infoLog ? infoLog : "")); if (infoLog) free(infoLog); @@ -2112,7 +2161,7 @@ static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD pglColor4ubv(c); } - Shader_Load(pSurf, &poly, &tint, &fade); + Shader_SetUniforms(pSurf, &poly, &tint, &fade); } // -----------------+ @@ -2158,7 +2207,7 @@ EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky) { int i, j; - Shader_Load(NULL, NULL, NULL, NULL); + Shader_SetUniforms(NULL, NULL, NULL, NULL); // Build the sky dome! Yes! if (sky->rebuild) @@ -2250,15 +2299,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) break; case HWD_SET_SHADERS: - switch (Value) - { - case 1: - gl_allowshaders = true; - break; - default: - gl_allowshaders = false; - break; - } + gl_allowshaders = (hwdshaderoption_t)Value; break; case HWD_SET_TEXTUREFILTERMODE: @@ -2607,7 +2648,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 fade.blue = byte2float[Surface->FadeColor.s.blue]; fade.alpha = byte2float[Surface->FadeColor.s.alpha]; - Shader_Load(Surface, &poly, &tint, &fade); + Shader_SetUniforms(Surface, &poly, &tint, &fade); pglEnable(GL_CULL_FACE); pglEnable(GL_NORMALIZE); diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c index edc69b21d..98f2f4894 100644 --- a/src/sdl/ogl_sdl.c +++ b/src/sdl/ogl_sdl.c @@ -177,7 +177,7 @@ boolean OglSdlSurface(INT32 w, INT32 h) SetupGLFunc4(); - granisotropicmode_cons_t[1].value = maximumAnisotropy; + glanisotropicmode_cons_t[1].value = maximumAnisotropy; SDL_GL_SetSwapInterval(cv_vidwait.value ? 1 : 0); diff --git a/src/w_wad.c b/src/w_wad.c index fd70f8ec3..3bfb52781 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2082,6 +2082,8 @@ int W_VerifyNMUSlumps(const char *filename) {"YB_", 3}, // Intermission graphics, goes with the above {"M_", 2}, // As does menu stuff {"MUSICDEF", 8}, // Song definitions (thanks kart) + {"SHADERS", 7}, // OpenGL shader definitions + {"SH_", 3}, // GLSL shader {NULL, 0}, }; From 4d847f42235e06098cc80e40085ec47af75a21b0 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sat, 10 Oct 2020 14:09:59 -0300 Subject: [PATCH 11/53] Compare the PNG's palette with the game's palette instead of assuming they are the same --- src/r_picformats.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index 95fe23aeb..feec2abf4 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -887,8 +887,24 @@ static png_bytep *PNG_Read( // matches the color count of SRB2's palette: 256 colors. if (png_get_PLTE(png_ptr, png_info_ptr, &palette, &palette_size)) { - if (palette_size == 256) + if (palette_size == 256 && pMasterPalette) + { + png_colorp pal = palette; + INT32 i; + usepal = true; + + for (i = 0; i < 256; i++) + { + UINT32 rgb = R_PutRgbaRGBA(pal->red, pal->green, pal->blue, 0xFF); + if (rgb != pMasterPalette[i].rgba) + { + usepal = false; + break; + } + pal++; + } + } } // If any of the tRNS colors have an alpha lower than 0xFF, and that From 06c0932ab4d3f1984d25ef3de886ec9ad94e2897 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sat, 10 Oct 2020 14:12:22 -0300 Subject: [PATCH 12/53] Only check the tRNS (trans) chunk if the image is still palettized --- src/r_picformats.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index feec2abf4..8d7cf37f2 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -909,20 +909,23 @@ static png_bytep *PNG_Read( // If any of the tRNS colors have an alpha lower than 0xFF, and that // color is present on the image, the palette flag is disabled. - png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values); - - if (trans && trans_num == 256) + if (usepal) { - int i; - for (i = 0; i < trans_num; i++) + png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values); + + if (trans && trans_num == 256) { - // libpng will transform this image into RGB even if - // the transparent index does not exist in the image, - // and there is no way around that. - if (trans[i] < 0xFF) + INT32 i; + for (i = 0; i < trans_num; i++) { - usepal = false; - break; + // libpng will transform this image into RGB even if + // the transparent index does not exist in the image, + // and there is no way around that. + if (trans[i] < 0xFF) + { + usepal = false; + break; + } } } } From da27f720dadd429f748aaefabf062d3979058d10 Mon Sep 17 00:00:00 2001 From: Zippy_Zolton Date: Sun, 11 Oct 2020 23:22:16 -0500 Subject: [PATCH 13/53] Whitelist the "X" shown in the HUD --- src/w_wad.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/w_wad.c b/src/w_wad.c index 11679b8f4..5d10cbd10 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2079,6 +2079,7 @@ int W_VerifyNMUSlumps(const char *filename) {"STCFN", 5}, // Console font changes {"TNYFN", 5}, // Tiny console font changes {"STT", 3}, // Acceptable HUD changes (Score Time Rings) + {"STLIVEX", 7}, // "X" that shows under skin's HUDNAME {"YB_", 3}, // Intermission graphics, goes with the above {"M_", 2}, // As does menu stuff {"MUSICDEF", 8}, // Song definitions (thanks kart) From 2ba1017dab3caaef938450f9af41f6db2af513c1 Mon Sep 17 00:00:00 2001 From: Zippy_Zolton Date: Tue, 13 Oct 2020 02:13:35 -0500 Subject: [PATCH 14/53] More whitelists :D --- src/w_wad.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/w_wad.c b/src/w_wad.c index 5d10cbd10..dd5018cf1 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2074,14 +2074,40 @@ int W_VerifyNMUSlumps(const char *filename) {"CLM", 3}, // Colormap changes {"TRANS", 5}, // Translucency map changes + {"CONSBACK", 8}, // Console Background graphic + {"SAVE", 4}, // Save Select graphics + {"ULTIMATE", 8}, // Ultimate no-save {"LTFNT", 5}, // Level title font changes {"TTL", 3}, // Act number changes {"STCFN", 5}, // Console font changes {"TNYFN", 5}, // Tiny console font changes - {"STT", 3}, // Acceptable HUD changes (Score Time Rings) {"STLIVEX", 7}, // "X" that shows under skin's HUDNAME + {"STT", 3}, // Acceptable HUD changes (Score Time Rings) {"YB_", 3}, // Intermission graphics, goes with the above + {"RESULT", 6}, // Used in intermission for competitive modes, above too :3 + {"RACE", 4}, // Race mode graphics, 321go {"M_", 2}, // As does menu stuff + + {"MINICAPS", 8}, // NiGHTS graphics here and below + {"BLUESTAT", 8}, // Sphere status + {"BYELSTAT", 8}, + {"ORNGSTAT", 8}, + {"REDSTAT", 7}, + {"YELSTAT", 7}, + {"NBRACKET", 8}, + {"NGHTLINK", 8}, + {"NGT", 3}, // Link numbers + {"NARROW", 6}, + {"NREDAR", 6}, + {"NSS", 3}, + {"NBON", 4}, + {"NRNG", 4}, + {"NHUD", 4}, + {"CAPS", 4}, + {"DRILL", 5}, + {"GRADE", 5}, + {"MINUS5", 6}, + {"MUSICDEF", 8}, // Song definitions (thanks kart) {NULL, 0}, From 45b52e372965d8e2eb116e1da7da5ce6be0b50b9 Mon Sep 17 00:00:00 2001 From: Zippy_Zolton Date: Tue, 13 Oct 2020 02:19:20 -0500 Subject: [PATCH 15/53] good night --- src/w_wad.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/w_wad.c b/src/w_wad.c index dd5018cf1..0f0ad97f0 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2075,8 +2075,12 @@ int W_VerifyNMUSlumps(const char *filename) {"TRANS", 5}, // Translucency map changes {"CONSBACK", 8}, // Console Background graphic + {"GAMEQUIT", 8}, {"SAVE", 4}, // Save Select graphics {"ULTIMATE", 8}, // Ultimate no-save + {"CRFNT", 5}, // Sonic 1 font changes + {"NTFNT", 5}, // Character Select font changes + {"NTFNO", 5}, // Character Select font (outline) {"LTFNT", 5}, // Level title font changes {"TTL", 3}, // Act number changes {"STCFN", 5}, // Console font changes From 5d699591c772fea85dba9ef7e1fa3394793bf73f Mon Sep 17 00:00:00 2001 From: Zippy_Zolton Date: Tue, 13 Oct 2020 14:23:56 -0500 Subject: [PATCH 16/53] more!!!!! :3 --- src/w_wad.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index 0f0ad97f0..db87bba94 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2076,8 +2076,14 @@ int W_VerifyNMUSlumps(const char *filename) {"CONSBACK", 8}, // Console Background graphic {"GAMEQUIT", 8}, - {"SAVE", 4}, // Save Select graphics + + {"SAVE", 4}, // Save Select graphics here and below + {"BLACXLVL", 8}, + {"GAMEDONE", 8}, + {"CONT", 4}, // Continue icons on saves (probably not used anymore) + {"STNONEX", 7}, // "X" graphic {"ULTIMATE", 8}, // Ultimate no-save + {"CRFNT", 5}, // Sonic 1 font changes {"NTFNT", 5}, // Character Select font changes {"NTFNO", 5}, // Character Select font (outline) @@ -2085,12 +2091,15 @@ int W_VerifyNMUSlumps(const char *filename) {"TTL", 3}, // Act number changes {"STCFN", 5}, // Console font changes {"TNYFN", 5}, // Tiny console font changes - {"STLIVEX", 7}, // "X" that shows under skin's HUDNAME + + {"STLIVE", 6}, // Life graphics, background and the "X" that shows under skin's HUDNAME + {"CROSSHAI", 8}, // First person crosshairs + {"INTERSC", 7}, // Default intermission backgrounds (co-op) {"STT", 3}, // Acceptable HUD changes (Score Time Rings) {"YB_", 3}, // Intermission graphics, goes with the above {"RESULT", 6}, // Used in intermission for competitive modes, above too :3 {"RACE", 4}, // Race mode graphics, 321go - {"M_", 2}, // As does menu stuff + {"M_", 2}, // Menu stuff {"MINICAPS", 8}, // NiGHTS graphics here and below {"BLUESTAT", 8}, // Sphere status From 6fd226eb29ec32d7e7de7fad14818f4c70b32c53 Mon Sep 17 00:00:00 2001 From: Zippy_Zolton Date: Tue, 13 Oct 2020 16:41:39 -0500 Subject: [PATCH 17/53] Crosshair fix, no GAMEQUIT --- src/w_wad.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index db87bba94..9d8adaabd 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2075,7 +2075,6 @@ int W_VerifyNMUSlumps(const char *filename) {"TRANS", 5}, // Translucency map changes {"CONSBACK", 8}, // Console Background graphic - {"GAMEQUIT", 8}, {"SAVE", 4}, // Save Select graphics here and below {"BLACXLVL", 8}, @@ -2093,7 +2092,7 @@ int W_VerifyNMUSlumps(const char *filename) {"TNYFN", 5}, // Tiny console font changes {"STLIVE", 6}, // Life graphics, background and the "X" that shows under skin's HUDNAME - {"CROSSHAI", 8}, // First person crosshairs + {"CROSHAI", 7}, // First person crosshairs {"INTERSC", 7}, // Default intermission backgrounds (co-op) {"STT", 3}, // Acceptable HUD changes (Score Time Rings) {"YB_", 3}, // Intermission graphics, goes with the above From 00f38d41e5ea67717d8cfcceba52a8ffe6bc8c27 Mon Sep 17 00:00:00 2001 From: GoldenTails Date: Fri, 16 Oct 2020 17:06:13 -0500 Subject: [PATCH 18/53] Give the GIF dynamic delay memory to base future delays off of, instead of calculating for the current frame and being jank --- src/m_anigif.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/m_anigif.c b/src/m_anigif.c index 85118790b..0d3206d11 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -47,7 +47,8 @@ static RGBA_t *gif_framepalette = NULL; static FILE *gif_out = NULL; static INT32 gif_frames = 0; -static UINT32 gif_prevframems = 0; +static UINT32 gif_prevframeus = 0; // "us" is microseconds +static UINT32 gif_delayus = 0; static UINT8 gif_writeover = 0; @@ -594,16 +595,20 @@ static void GIF_framewrite(void) // screen regions are handled in GIF_lzw { - UINT16 delay; + UINT16 delay = 0; INT32 startline; if (gif_dynamicdelay) { // golden's attempt at creating a "dynamic delay" - float delayf = ceil(100.0f/NEWTICRATE); + UINT16 mingifdelay = 10; // minimum gif delay in milliseconds (keep at 10 because gifs can't get more precise). + gif_delayus += (I_GetTimeMicros() - gif_prevframeus); // increase delay by how much time was spent between last measurement - delay = (UINT16)((I_GetTimeMicros() - gif_prevframems)/10/1000); - if (delay < (int)(delayf)) - delay = (int)(delayf); + if (gif_delayus/1000 >= mingifdelay) // delay is big enough to be able to effect gif frame delay? + { + int frames = (gif_delayus/1000) / mingifdelay; // get amount of frames to delay. + delay = frames; // set the delay to delay that amount of frames. + gif_delayus -= frames*(mingifdelay*1000); // remove frames by the amount of milliseconds they take. don't reset to 0, the microseconds help consistency. + } } else { @@ -690,7 +695,7 @@ static void GIF_framewrite(void) } fwrite(gifframe_data, 1, (p - gifframe_data), gif_out); ++gif_frames; - gif_prevframems = I_GetTimeMicros(); + gif_prevframeus = I_GetTimeMicros(); } @@ -718,7 +723,8 @@ INT32 GIF_open(const char *filename) GIF_headwrite(); gif_frames = 0; - gif_prevframems = I_GetTimeMicros(); + gif_prevframeus = I_GetTimeMicros(); + gif_delayus = 0; return 1; } From f602944efd7b789ccb94d5eccaeae287a7e80493 Mon Sep 17 00:00:00 2001 From: Zippy_Zolton Date: Sat, 17 Oct 2020 15:51:22 -0500 Subject: [PATCH 19/53] titlecard --- src/w_wad.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/w_wad.c b/src/w_wad.c index 9d8adaabd..37dcf5847 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2099,6 +2099,7 @@ int W_VerifyNMUSlumps(const char *filename) {"RESULT", 6}, // Used in intermission for competitive modes, above too :3 {"RACE", 4}, // Race mode graphics, 321go {"M_", 2}, // Menu stuff + {"LT", 2}, // Titlecard changes {"MINICAPS", 8}, // NiGHTS graphics here and below {"BLUESTAT", 8}, // Sphere status From d1f16e0f778216b287888401072aa1ae586b1030 Mon Sep 17 00:00:00 2001 From: Zolton Auburn Date: Tue, 20 Oct 2020 15:56:41 -0400 Subject: [PATCH 20/53] Continue --- src/w_wad.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/w_wad.c b/src/w_wad.c index 37dcf5847..6306f998f 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2101,6 +2101,9 @@ int W_VerifyNMUSlumps(const char *filename) {"M_", 2}, // Menu stuff {"LT", 2}, // Titlecard changes + {"SLID", 4}, // Continue + {"CONT", 4}, + {"MINICAPS", 8}, // NiGHTS graphics here and below {"BLUESTAT", 8}, // Sphere status {"BYELSTAT", 8}, From a4459b6693b969088ae307020d664910ae2aee95 Mon Sep 17 00:00:00 2001 From: Zippy_Zolton Date: Fri, 23 Oct 2020 00:47:47 -0500 Subject: [PATCH 21/53] Dash state for Tails overlay --- src/dehacked.c | 1 + src/info.c | 3 +++ src/info.h | 1 + src/p_user.c | 2 ++ 4 files changed, 7 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index ca013a25d..34fe58362 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -5178,6 +5178,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_TAILSOVERLAY_PAIN", "S_TAILSOVERLAY_GASP", "S_TAILSOVERLAY_EDGE", + "S_TAILSOVERLAY_DASH", // [: "S_JETFUMEFLASH", diff --git a/src/info.c b/src/info.c index cb5fb0889..8cdfaa8a0 100644 --- a/src/info.c +++ b/src/info.c @@ -584,6 +584,7 @@ char spr2names[NUMPLAYERSPRITES][5] = "TAL9", "TALA", "TALB", + "TALC", "CNT1", "CNT2", @@ -661,6 +662,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_TAL0, // SPR2_TAL9, SPR2_TAL9, // SPR2_TALA, SPR2_TAL0, // SPR2_TALB, + SPR2_TAL0, // SPR2_TALC, SPR2_WAIT, // SPR2_CNT1, SPR2_FALL, // SPR2_CNT2, @@ -801,6 +803,7 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_TAL9|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PAIN}, // S_TAILSOVERLAY_PAIN {SPR_PLAY, SPR2_TALA|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_GASP}, // S_TAILSOVERLAY_GASP {SPR_PLAY, SPR2_TALB , 35, {NULL}, 0, 0, S_TAILSOVERLAY_EDGE}, // S_TAILSOVERLAY_EDGE + {SPR_PLAY, SPR2_TALC|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_DASH}, // S_TAILSOVERLAY_DASH // [: {SPR_JETF, 3|FF_ANIMATE|FF_FULLBRIGHT, 2, {NULL}, 1, 1, S_JETFUME1}, // S_JETFUMEFLASH diff --git a/src/info.h b/src/info.h index 721ebf7f2..8130cf948 100644 --- a/src/info.h +++ b/src/info.h @@ -997,6 +997,7 @@ typedef enum state S_TAILSOVERLAY_PAIN, S_TAILSOVERLAY_GASP, S_TAILSOVERLAY_EDGE, + S_TAILSOVERLAY_DASH, // [: S_JETFUMEFLASH, diff --git a/src/p_user.c b/src/p_user.c index 0d7331293..da33f1dbb 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -11208,6 +11208,8 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) chosenstate = S_TAILSOVERLAY_EDGE; else if (player->panim == PA_RUN) chosenstate = S_TAILSOVERLAY_RUN; + else if (player->panim == PA_DASH) + chosenstate = S_TAILSOVERLAY_DASH; else if (player->panim == PA_WALK) { if (!smilesonground || player->mo->state-states == S_PLAY_SKID) From c0571b5fbf41918842f8b6fecf5854572ed7635b Mon Sep 17 00:00:00 2001 From: Zippy_Zolton Date: Fri, 23 Oct 2020 01:09:12 -0500 Subject: [PATCH 22/53] g --- src/info.h | 1 + src/p_user.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/info.h b/src/info.h index 8130cf948..d84461617 100644 --- a/src/info.h +++ b/src/info.h @@ -856,6 +856,7 @@ typedef enum playersprite SPR2_TAL9, SPR2_TALA, SPR2_TALB, + SPR2_TALC, SPR2_CNT1, // continue disappointment SPR2_CNT2, // continue lift diff --git a/src/p_user.c b/src/p_user.c index da33f1dbb..051965eb5 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -11206,10 +11206,10 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) chosenstate = S_TAILSOVERLAY_GASP; else if (player->mo->state-states == S_PLAY_EDGE) chosenstate = S_TAILSOVERLAY_EDGE; - else if (player->panim == PA_RUN) - chosenstate = S_TAILSOVERLAY_RUN; else if (player->panim == PA_DASH) chosenstate = S_TAILSOVERLAY_DASH; + else if (player->panim == PA_RUN) + chosenstate = S_TAILSOVERLAY_RUN; else if (player->panim == PA_WALK) { if (!smilesonground || player->mo->state-states == S_PLAY_SKID) From 85692ac4090c68dc4bc519f230b7d69226b47263 Mon Sep 17 00:00:00 2001 From: Zolton Auburn Date: Fri, 23 Oct 2020 14:04:02 -0400 Subject: [PATCH 23/53] Update info.c --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index 8cdfaa8a0..29a79b1d6 100644 --- a/src/info.c +++ b/src/info.c @@ -662,7 +662,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_TAL0, // SPR2_TAL9, SPR2_TAL9, // SPR2_TALA, SPR2_TAL0, // SPR2_TALB, - SPR2_TAL0, // SPR2_TALC, + SPR2_TAL6, // SPR2_TALC, SPR2_WAIT, // SPR2_CNT1, SPR2_FALL, // SPR2_CNT2, From 5d4032fd0067426a6cb7caf1bbeaf4b8ec2ac093 Mon Sep 17 00:00:00 2001 From: Zippy_Zolton Date: Sat, 24 Oct 2020 12:38:30 -0500 Subject: [PATCH 24/53] Ghost mobj matches rollangle --- src/p_user.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_user.c b/src/p_user.c index 0d7331293..02b807bf2 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2029,6 +2029,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->colorized = mobj->colorized; // alternatively, "true" for sonic advance style colourisation ghost->angle = (mobj->player ? mobj->player->drawangle : mobj->angle); + ghost->rollangle = mobj->rollangle; ghost->sprite = mobj->sprite; ghost->sprite2 = mobj->sprite2; ghost->frame = mobj->frame; From 244c76250f1f88e9a4ada14a4671a1770d938d5a Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sat, 24 Oct 2020 20:52:54 +0300 Subject: [PATCH 25/53] Use SSE3 in 32-bit x86 binaries --- src/CMakeLists.txt | 1 + src/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3409c49d3..3514fb477 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -549,6 +549,7 @@ if(${SRB2_CONFIG_USEASM}) endif() set(SRB2_USEASM ON) add_definitions(-DUSEASM) + set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -msse3 -mfpmath=sse) else() set(SRB2_USEASM OFF) add_definitions(-DNONX86 -DNORUSEASM) diff --git a/src/Makefile b/src/Makefile index 2fe0b26cd..5d5db056f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -277,7 +277,7 @@ OPTS += -DCOMPVERSION ifndef NONX86 ifndef GCC29 - ARCHOPTS?=-march=pentium + ARCHOPTS?=-msse3 -mfpmath=sse else ARCHOPTS?=-mpentium endif From 305f58077d13b39ba9e9fca91b69f6aecf6cb8ed Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 24 Oct 2020 15:29:31 -0700 Subject: [PATCH 26/53] Fix objectplace -silent --- src/m_cheat.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/m_cheat.c b/src/m_cheat.c index 349f00c48..88f6aaf4a 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1440,14 +1440,21 @@ void Command_Writethings_f(void) void Command_ObjectPlace_f(void) { + size_t thingarg; + size_t silent; + REQUIRE_INLEVEL; REQUIRE_SINGLEPLAYER; REQUIRE_NOULTIMATE; G_SetGameModified(multiplayer); + silent = COM_CheckParm("-silent"); + + thingarg = 2 - ( silent > 1 ); + // Entering objectplace? - if (!objectplacing || COM_Argc() > 1) + if (!objectplacing || thingarg < COM_Argc()) { if (!objectplacing) { @@ -1456,7 +1463,7 @@ void Command_ObjectPlace_f(void) if (players[0].powers[pw_carry] == CR_NIGHTSMODE) return; - if (!COM_CheckParm("-silent")) + if (! silent) { HU_SetCEchoFlags(V_RETURN8|V_MONOSPACE|V_AUTOFADEOUT); HU_SetCEchoDuration(10); @@ -1507,9 +1514,9 @@ void Command_ObjectPlace_f(void) op_oldstate = (statenum_t)(players[0].mo->state-states); } - if (COM_Argc() > 1) + if (thingarg < COM_Argc()) { - UINT16 mapthingnum = atoi(COM_Argv(1)); + UINT16 mapthingnum = atoi(COM_Argv(thingarg)); mobjtype_t type = P_GetMobjtype(mapthingnum); if (type == MT_UNKNOWN) CONS_Printf(M_GetText("No mobj type delegated to thing type %d.\n"), mapthingnum); From afb8e6e1815c75c089a4bd1c684fc4c6bcc7f2d5 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 24 Oct 2020 20:44:42 -0700 Subject: [PATCH 27/53] Whoops --- src/m_cheat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_cheat.c b/src/m_cheat.c index 88f6aaf4a..8e9cd9f51 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1451,7 +1451,7 @@ void Command_ObjectPlace_f(void) silent = COM_CheckParm("-silent"); - thingarg = 2 - ( silent > 1 ); + thingarg = 2 - ( silent != 1 ); // Entering objectplace? if (!objectplacing || thingarg < COM_Argc()) From 18a2e87093542c95c98ea95b5414f136fce93aee Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 26 Oct 2020 14:00:54 -0700 Subject: [PATCH 28/53] Check maxstep is not disabled before stepping up Fixes infinite step up when it should be no step up. --- src/p_map.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index 0a9107ee5..2715d2377 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2735,7 +2735,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) // Step up if (thing->z < tmfloorz) { - if (tmfloorz - thing->z <= maxstep) + if (maxstep > 0 && tmfloorz - thing->z <= maxstep) { thing->z = thing->floorz = tmfloorz; thing->floorrover = tmfloorrover; @@ -2748,7 +2748,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) } else if (tmceilingz < thingtop) { - if (thingtop - tmceilingz <= maxstep) + if (maxstep > 0 && thingtop - tmceilingz <= maxstep) { thing->z = ( thing->ceilingz = tmceilingz ) - thing->height; thing->ceilingrover = tmceilingrover; From 9f5686ef48956cd64ef92f737e59cbbaa27d8cf9 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 26 Oct 2020 23:15:22 +0100 Subject: [PATCH 29/53] Fix underflow in consistancy checking code --- src/d_clisrv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index cc2715cb1..e671bced6 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -4067,7 +4067,7 @@ static void HandlePacketFromPlayer(SINT8 node) &netbuffer->u.client2pak.cmd2, 1); // Check player consistancy during the level - if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 && gamestate == GS_LEVEL + if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) && !resendingsavegame[node]) { From 7ae53364f2ea73f54bccf317339ac83499049a95 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 27 Oct 2020 01:20:05 +0100 Subject: [PATCH 30/53] Add a 15 seconds cooldown between successive gamestate resends --- src/d_clisrv.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index e671bced6..0823f3c8a 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -85,6 +85,7 @@ char playeraddress[MAXPLAYERS][64]; tic_t jointimeout = (10*TICRATE); static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame? static boolean resendingsavegame[MAXNETNODES]; // Are we resending the savegame? +static tic_t savegameresendcooldown[MAXNETNODES]; // How long before we can resend again? static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout? // Incremented by cv_joindelay when a client joins, decremented each tic. @@ -3149,14 +3150,18 @@ void D_ClientServerInit(void) static void ResetNode(INT32 node) { nodeingame[node] = false; - nodetoplayer[node] = -1; - nodetoplayer2[node] = -1; + nodewaiting[node] = 0; + nettics[node] = gametic; supposedtics[node] = gametic; - nodewaiting[node] = 0; + + nodetoplayer[node] = -1; + nodetoplayer2[node] = -1; playerpernode[node] = 0; + sendingsavegame[node] = false; resendingsavegame[node] = false; + savegameresendcooldown[node] = 0; } void SV_ResetServer(void) @@ -4069,7 +4074,7 @@ 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]) + && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime()) { if (cv_resynchattempts.value) { @@ -4237,6 +4242,7 @@ static void HandlePacketFromPlayer(SINT8 node) case PT_RECEIVEDGAMESTATE: sendingsavegame[node] = false; resendingsavegame[node] = false; + savegameresendcooldown[node] = I_GetTime() + 15 * TICRATE; break; // -------------------------------------------- CLIENT RECEIVE ---------- case PT_SERVERTICS: From 499bb56436c7571d3247a5a813af2a84a58c5913 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 27 Oct 2020 01:22:31 +0100 Subject: [PATCH 31/53] Only resend the gamestate to one client at a time --- src/d_clisrv.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 0823f3c8a..af7907e67 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1391,6 +1391,16 @@ static boolean SV_SendServerConfig(INT32 node) #ifndef NONET #define SAVEGAMESIZE (768*1024) +static boolean SV_ResendingSavegameToAnyone(void) +{ + INT32 i; + + for (i = 0; i < MAXNETNODES; i++) + if (resendingsavegame[i]) + return true; + return false; +} + static void SV_SendSaveGame(INT32 node, boolean resending) { size_t length, compressedlen; @@ -4074,7 +4084,8 @@ 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()) + && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime() + && !SV_ResendingSavegameToAnyone()) { if (cv_resynchattempts.value) { From 5c48b92b2c423b910829521546a01bf7df5fbfd4 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 27 Oct 2020 20:21:56 +0100 Subject: [PATCH 32/53] Fix camera going wild after reloading the gamestate --- src/d_clisrv.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index af7907e67..30c558f2f 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1607,6 +1607,14 @@ static void CL_ReloadReceivedSavegame(void) neededtic = gametic; maketic = neededtic; + ticcmd_oldangleturn[0] = players[consoleplayer].oldrelangleturn; + P_ForceLocalAngle(&players[consoleplayer], (angle_t)(players[consoleplayer].angleturn << 16)); + if (splitscreen) + { + ticcmd_oldangleturn[1] = players[secondarydisplayplayer].oldrelangleturn; + P_ForceLocalAngle(&players[secondarydisplayplayer], (angle_t)(players[secondarydisplayplayer].angleturn << 16)); + } + camera.subsector = R_PointInSubsector(camera.x, camera.y); camera2.subsector = R_PointInSubsector(camera2.x, camera2.y); From 804ad44e89324eb501db9a1278a73af9ae850862 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 27 Oct 2020 20:22:15 +0100 Subject: [PATCH 33/53] Fix music resetting after reloading the gamestate --- src/p_setup.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index d36401ac3..ea4a24f35 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4038,18 +4038,20 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // Fade out music here. Deduct 2 tics so the fade volume actually reaches 0. // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug. - if (!titlemapinaction && (RESETMUSIC || + if (!(reloadinggamestate || titlemapinaction) && (RESETMUSIC || strnicmp(S_MusicName(), (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7))) + { S_FadeMusic(0, FixedMul( FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)); + } // Let's fade to black here // But only if we didn't do the special stage wipe if (rendermode != render_none && !(ranspecialwipe || reloadinggamestate)) P_RunLevelWipe(); - if (!titlemapinaction) + if (!(reloadinggamestate || titlemapinaction)) { if (ranspecialwipe == 2) { From 395d1f1b8f38e0dc8c00cf29318cceffc1b9862b Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 27 Oct 2020 20:23:32 +0100 Subject: [PATCH 34/53] Do not pause the client while redownloading the gamestate --- src/d_clisrv.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 30c558f2f..aa18ee380 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -4274,9 +4274,6 @@ static void HandlePacketFromPlayer(SINT8 node) break; } - if (cl_redownloadinggamestate) - break; - realstart = netbuffer->u.serverpak.starttic; realend = realstart + netbuffer->u.serverpak.numtics; @@ -5001,8 +4998,7 @@ void NetUpdate(void) if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND) CL_ReloadReceivedSavegame(); - if (!cl_redownloadinggamestate) - CL_SendClientCmd(); // Send tic cmd + CL_SendClientCmd(); // Send tic cmd hu_redownloadinggamestate = cl_redownloadinggamestate; } else From e1789663671ca2318f732d3d0b475d9a8778730e Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 27 Oct 2020 20:28:54 +0100 Subject: [PATCH 35/53] Remove useless condition --- src/d_clisrv.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index aa18ee380..a3fbe88d9 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5022,24 +5022,18 @@ void NetUpdate(void) // Don't erase tics not acknowledged counts = realtics; - // Do not make tics while resynching - if (counts != -666) - { - if (maketic + counts >= firstticstosend + BACKUPTICS) - counts = firstticstosend+BACKUPTICS-maketic-1; + if (maketic + counts >= firstticstosend + BACKUPTICS) + counts = firstticstosend+BACKUPTICS-maketic-1; - for (i = 0; i < counts; i++) - SV_Maketic(); // Create missed tics and increment maketic + for (i = 0; i < counts; i++) + SV_Maketic(); // Create missed tics and increment maketic - for (; tictoclear < firstticstosend; tictoclear++) // Clear only when acknowledged - D_Clearticcmd(tictoclear); // Clear the maketic the new tic + for (; tictoclear < firstticstosend; tictoclear++) // Clear only when acknowledged + D_Clearticcmd(tictoclear); // Clear the maketic the new tic - SV_SendTics(); + SV_SendTics(); - neededtic = maketic; // The server is a client too - } - else - hu_redownloadinggamestate = true; + neededtic = maketic; // The server is a client too } } From 5241b83f979da3525c6b6929b0253eceea6fa7ce Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Wed, 28 Oct 2020 19:36:03 +0000 Subject: [PATCH 36/53] Fix seg->length and flength not being set at all for UDMF maps --- src/p_setup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/p_setup.c b/src/p_setup.c index 7747f6462..8e09c34df 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2401,6 +2401,10 @@ static boolean P_LoadExtendedSubsectorsAndSegs(UINT8 **data, nodetype_t nodetype seg->angle = R_PointToAngle2(v1->x, v1->y, v2->x, v2->y); if (seg->linedef) segs[i].offset = FixedHypot(v1->x - seg->linedef->v1->x, v1->y - seg->linedef->v1->y); + seg->length = P_SegLength(seg); +#ifdef HWRENDER + seg->flength = (rendermode == render_opengl) ? P_SegLengthFloat(seg) : 0; +#endif } return true; From c44120eb8756b5acfb6e8b9feb25be89dab3ef43 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Thu, 29 Oct 2020 16:04:25 +0200 Subject: [PATCH 37/53] Fix some copyright statements in new files --- src/hardware/hw_batching.c | 3 +-- src/hardware/hw_batching.h | 3 +-- src/m_perfstats.c | 3 +-- src/m_perfstats.h | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index a63be3a72..5ea9f55d4 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -1,7 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/hardware/hw_batching.h b/src/hardware/hw_batching.h index 7c108a4bd..3d22324ac 100644 --- a/src/hardware/hw_batching.h +++ b/src/hardware/hw_batching.h @@ -1,7 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_perfstats.c b/src/m_perfstats.c index df1e31b5e..085adda80 100644 --- a/src/m_perfstats.c +++ b/src/m_perfstats.c @@ -1,7 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_perfstats.h b/src/m_perfstats.h index 1db46025e..01a818c1c 100644 --- a/src/m_perfstats.h +++ b/src/m_perfstats.h @@ -1,7 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. From 1155d875d50d6cd79c8aaf9228cd652cbda0cf73 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Fri, 30 Oct 2020 15:00:13 +0100 Subject: [PATCH 38/53] Use the same names as userdataType() for userdataMetatable() --- src/lua_baselib.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index e60b20095..468af0aa1 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -278,8 +278,18 @@ static int lib_registerMetatable(lua_State *L) // Returns nil if the string does not refer to a valid userdata type static int lib_userdataMetatable(lua_State *L) { + UINT32 i; const char *udname = luaL_checkstring(L, 1); - luaL_getmetatable(L, udname); + + // Find internal metatable name + for (i = 0; meta2utype[i].meta; i++) + if (!strcmp(udname, meta2utype[i].utype)) + { + luaL_getmetatable(L, meta2utype[i].meta); + return 1; + } + + lua_pushnil(L); return 1; } From d406340b5dd4f2768354aa2833fa613b426c281e Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Fri, 30 Oct 2020 23:37:34 -0400 Subject: [PATCH 39/53] Fix compiling using cmake if internal libs is used --- src/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3409c49d3..4ee586f36 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -230,7 +230,7 @@ set(SRB2_CONFIG_HAVE_GME ON CACHE BOOL set(SRB2_CONFIG_HAVE_OPENMPT ON CACHE BOOL "Enable OpenMPT support.") set(SRB2_CONFIG_HAVE_CURL ON CACHE BOOL - "Enable curl support, used for downloading files via HTTP.") + "Enable curl support.") set(SRB2_CONFIG_HAVE_THREADS ON CACHE BOOL "Enable multithreading support.") if(${CMAKE_SYSTEM} MATCHES Windows) @@ -455,7 +455,7 @@ endif() if(${SRB2_CONFIG_HAVE_CURL}) if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES}) set(CURL_FOUND ON) - set(CURL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/curl) + set(CURL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/curl/include) if(${SRB2_SYSTEM_BITS} EQUAL 64) set(CURL_LIBRARIES "-L${CMAKE_SOURCE_DIR}/libs/curl/lib64 -lcurl") else() # 32-bit From 62b5b86ed449f88659f45424f82f7b158611ae02 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Sat, 31 Oct 2020 00:59:51 -0400 Subject: [PATCH 40/53] CMake: Fix fullscreen toggle not working All because of a typo --- src/sdl/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt index bb5edf817..a7f015c86 100644 --- a/src/sdl/CMakeLists.txt +++ b/src/sdl/CMakeLists.txt @@ -272,7 +272,7 @@ if(${SDL2_FOUND}) endif() target_compile_definitions(SRB2SDL2 PRIVATE - -DDDIRECTFULLSCREEN -DHAVE_SDL + -DDIRECTFULLSCREEN -DHAVE_SDL ) ## strip debug symbols into separate file when using gcc. From bfbcc6910847166b90a8e9f5cc61ec28aee03540 Mon Sep 17 00:00:00 2001 From: lachwright Date: Sat, 31 Oct 2020 18:21:14 +1100 Subject: [PATCH 41/53] Draw save files from outwards in --- src/m_menu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 6e0d520ae..5860f00ca 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -8246,7 +8246,7 @@ static void M_CacheLoadGameData(void) static void M_DrawLoadGameData(void) { - INT32 i, savetodraw, x, y, hsep = 90; + INT32 i, prev_i = 1, savetodraw, x, y, hsep = 90; skin_t *charskin = NULL; if (vid.width != BASEVIDWIDTH*vid.dupx) @@ -8255,8 +8255,9 @@ static void M_DrawLoadGameData(void) if (needpatchrecache) M_CacheLoadGameData(); - for (i = -2; i <= 2; i++) + for (i = 2; prev_i; i = -(i + ((UINT32)i >> 31))) // draws from outwards in; 2, -2, 1, -1, 0 { + prev_i = i; savetodraw = (saveSlotSelected + i + numsaves)%numsaves; x = (BASEVIDWIDTH/2 - 42 + loadgamescroll) + (i*hsep); y = 33 + 9; From 54cc9db7a5de4bda6b0b01883009b8340e8f2d92 Mon Sep 17 00:00:00 2001 From: Hannu Hanhi Date: Sat, 31 Oct 2020 18:04:44 +0200 Subject: [PATCH 42/53] Fix CMake SSE3 flag --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3514fb477..f201e43ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -549,7 +549,7 @@ if(${SRB2_CONFIG_USEASM}) endif() set(SRB2_USEASM ON) add_definitions(-DUSEASM) - set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -msse3 -mfpmath=sse) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse3 -mfpmath=sse") else() set(SRB2_USEASM OFF) add_definitions(-DNONX86 -DNORUSEASM) From 41d8210fd5ff71db25741fc2e481d4a70dd5dcec Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Sat, 31 Oct 2020 16:36:15 -0400 Subject: [PATCH 43/53] Expose gamestate to Lua --- src/dehacked.c | 17 +++++++++++++++++ src/lua_script.c | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index ca013a25d..a3f78edd4 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -38,6 +38,7 @@ #include "lua_script.h" #include "lua_hook.h" #include "d_clisrv.h" +#include "g_state.h" // gamestate_t (for lua) #include "m_cond.h" @@ -10106,6 +10107,22 @@ struct { {"MA_NOCUTSCENES",MA_NOCUTSCENES}, {"MA_INGAME",MA_INGAME}, + // gamestates + {"GS_NULL",GS_NULL}, + {"GS_LEVEL",GS_LEVEL}, + {"GS_INTERMISSION",GS_INTERMISSION}, + {"GS_CONTINUING",GS_CONTINUING}, + {"GS_TITLESCREEN",GS_TITLESCREEN}, + {"GS_TIMEATTACK",GS_TIMEATTACK}, + {"GS_CREDITS",GS_CREDITS}, + {"GS_EVALUATION",GS_EVALUATION}, + {"GS_GAMEEND",GS_GAMEEND}, + {"GS_INTRO",GS_INTRO}, + {"GS_ENDING",GS_ENDING}, + {"GS_CUTSCENE",GS_CUTSCENE}, + {"GS_DEDICATEDSERVER",GS_DEDICATEDSERVER}, + {"GS_WAITINGPLAYERS",GS_WAITINGPLAYERS}, + {NULL,0} }; diff --git a/src/lua_script.c b/src/lua_script.c index ae7f479f6..6e40cb785 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -34,6 +34,7 @@ #include "lua_hook.h" #include "doomstat.h" +#include "g_state.h" lua_State *gL = NULL; @@ -361,6 +362,9 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word, "token")) { lua_pushinteger(L, token); return 1; + } else if (fastcmp(word, "gamestate")) { + lua_pushinteger(L, gamestate); + return 1; } return 0; } From 37931fc2531a83a42366fb219eb98bff8c800249 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 1 Nov 2020 19:31:10 -0800 Subject: [PATCH 44/53] The lump is not needed for P_WriteThings --- src/m_cheat.c | 2 +- src/p_setup.c | 7 +------ src/p_setup.h | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/m_cheat.c b/src/m_cheat.c index 349f00c48..b28524fd3 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1435,7 +1435,7 @@ void Command_Writethings_f(void) REQUIRE_SINGLEPLAYER; REQUIRE_OBJECTPLACE; - P_WriteThings(W_GetNumForName(G_BuildMapName(gamemap)) + ML_THINGS); + P_WriteThings(); } void Command_ObjectPlace_f(void) diff --git a/src/p_setup.c b/src/p_setup.c index 7747f6462..578fb6d53 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -904,16 +904,13 @@ static void P_SpawnMapThings(boolean spawnemblems) } // Experimental groovy write function! -void P_WriteThings(lumpnum_t lumpnum) +void P_WriteThings(void) { size_t i, length; mapthing_t *mt; - UINT8 *data; UINT8 *savebuffer, *savebuf_p; INT16 temp; - data = W_CacheLumpNum(lumpnum, PU_LEVEL); - savebuf_p = savebuffer = (UINT8 *)malloc(nummapthings * sizeof (mapthing_t)); if (!savebuf_p) @@ -935,8 +932,6 @@ void P_WriteThings(lumpnum_t lumpnum) WRITEUINT16(savebuf_p, mt->options); } - Z_Free(data); - length = savebuf_p - savebuffer; FIL_WriteFile(va("newthings%d.lmp", gamemap), savebuffer, length); diff --git a/src/p_setup.h b/src/p_setup.h index ef903e103..f8ff11706 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -105,7 +105,7 @@ boolean P_AddWadFile(const char *wadfilename); boolean P_RunSOC(const char *socfilename); void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num); void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num); -void P_WriteThings(lumpnum_t lump); +void P_WriteThings(void); size_t P_PrecacheLevelFlats(void); void P_AllocMapHeader(INT16 i); From 1f7df8a79098c8cc1e2c8f4dfb9e34ae977b2f3e Mon Sep 17 00:00:00 2001 From: GoldenTails Date: Tue, 3 Nov 2020 20:11:39 -0600 Subject: [PATCH 45/53] Fix hyperwalls --- src/p_map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_map.c b/src/p_map.c index 0a9107ee5..2380a6d52 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -3107,7 +3107,7 @@ static void P_HitSlideLine(line_t *ld) lineangle >>= ANGLETOFINESHIFT; deltaangle >>= ANGLETOFINESHIFT; - movelen = P_AproxDistance(tmxmove, tmymove); + movelen = R_PointToDist2(0, 0, tmxmove, tmymove); newlen = FixedMul(movelen, FINECOSINE(deltaangle)); tmxmove = FixedMul(newlen, FINECOSINE(lineangle)); From e473bfd4cdefd1f109989113bad752d26e2a58e9 Mon Sep 17 00:00:00 2001 From: GoldenTails Date: Sat, 7 Nov 2020 03:01:15 -0600 Subject: [PATCH 46/53] By default use the old gif_dynamicdelay v1 behavior, but keep v2 as an option. --- src/m_anigif.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/m_anigif.c b/src/m_anigif.c index 0d3206d11..372781a97 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -29,15 +29,21 @@ // GIFs are always little-endian #include "byteptr.h" +CV_PossibleValue_t gif_dynamicdelay_cons_t[] = { + {0, "Off"}, + {1, "On"}, + {2, "Accurate, experimental"}, +{0, NULL}}; + consvar_t cv_gif_optimize = CVAR_INIT ("gif_optimize", "On", CV_SAVE, CV_OnOff, NULL); consvar_t cv_gif_downscale = CVAR_INIT ("gif_downscale", "On", CV_SAVE, CV_OnOff, NULL); -consvar_t cv_gif_dynamicdelay = CVAR_INIT ("gif_dynamicdelay", "On", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_gif_dynamicdelay = CVAR_INIT ("gif_dynamicdelay", "On", CV_SAVE, gif_dynamicdelay_cons_t, NULL); consvar_t cv_gif_localcolortable = CVAR_INIT ("gif_localcolortable", "On", CV_SAVE, CV_OnOff, NULL); #ifdef HAVE_ANIGIF static boolean gif_optimize = false; // So nobody can do something dumb static boolean gif_downscale = false; // like changing cvars mid output -static boolean gif_dynamicdelay = false; // and messing something up +static INT32 gif_dynamicdelay = 0; // and messing something up // Palette handling static boolean gif_localcolortable = false; @@ -598,7 +604,8 @@ static void GIF_framewrite(void) UINT16 delay = 0; INT32 startline; - if (gif_dynamicdelay) { + if (gif_dynamicdelay == 2) + { // golden's attempt at creating a "dynamic delay" UINT16 mingifdelay = 10; // minimum gif delay in milliseconds (keep at 10 because gifs can't get more precise). gif_delayus += (I_GetTimeMicros() - gif_prevframeus); // increase delay by how much time was spent between last measurement @@ -610,6 +617,15 @@ static void GIF_framewrite(void) gif_delayus -= frames*(mingifdelay*1000); // remove frames by the amount of milliseconds they take. don't reset to 0, the microseconds help consistency. } } + else if (gif_dynamicdelay == 1) + { + float delayf = ceil(100.0f/NEWTICRATE); + + delay = (UINT16)((I_GetTimeMicros() - gif_prevframeus)/10/1000); + + if (delay < (UINT16)(delayf)) + delay = (UINT16)(delayf); + } else { // the original code @@ -716,7 +732,7 @@ INT32 GIF_open(const char *filename) gif_optimize = (!!cv_gif_optimize.value); gif_downscale = (!!cv_gif_downscale.value); - gif_dynamicdelay = (!!cv_gif_dynamicdelay.value); + memcpy(&gif_dynamicdelay, &cv_gif_dynamicdelay.value, sizeof(gif_dynamicdelay)); //gif_dynamicdelay = (!!cv_gif_dynamicdelay.value); gif_localcolortable = (!!cv_gif_localcolortable.value); gif_colorprofile = (!!cv_screenshot_colorprofile.value); gif_headerpalette = GIF_getpalette(0); From d031bb5357cdfddcdf1dbd01c094fa4761ed7292 Mon Sep 17 00:00:00 2001 From: GoldenTails Date: Sat, 7 Nov 2020 03:43:55 -0600 Subject: [PATCH 47/53] fix dumb memcpy --- src/m_anigif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_anigif.c b/src/m_anigif.c index 372781a97..566f48d50 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -732,7 +732,7 @@ INT32 GIF_open(const char *filename) gif_optimize = (!!cv_gif_optimize.value); gif_downscale = (!!cv_gif_downscale.value); - memcpy(&gif_dynamicdelay, &cv_gif_dynamicdelay.value, sizeof(gif_dynamicdelay)); //gif_dynamicdelay = (!!cv_gif_dynamicdelay.value); + gif_dynamicdelay = cv_gif_dynamicdelay.value; gif_localcolortable = (!!cv_gif_localcolortable.value); gif_colorprofile = (!!cv_screenshot_colorprofile.value); gif_headerpalette = GIF_getpalette(0); From 9d11d8eec952c6cdff67423e3bd0b7ad40f79a8e Mon Sep 17 00:00:00 2001 From: GoldenTails Date: Sat, 7 Nov 2020 03:49:21 -0600 Subject: [PATCH 48/53] Remove 3 wasteful bytes of guaranteed blank memory from some place where it's not gonna matter that much --- src/m_anigif.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/m_anigif.c b/src/m_anigif.c index 566f48d50..dbc8d3422 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -43,7 +43,7 @@ consvar_t cv_gif_localcolortable = CVAR_INIT ("gif_localcolortable", "On", CV_S #ifdef HAVE_ANIGIF static boolean gif_optimize = false; // So nobody can do something dumb static boolean gif_downscale = false; // like changing cvars mid output -static INT32 gif_dynamicdelay = 0; // and messing something up +static UINT8 gif_dynamicdelay = (UINT8)0; // and messing something up // Palette handling static boolean gif_localcolortable = false; @@ -604,7 +604,7 @@ static void GIF_framewrite(void) UINT16 delay = 0; INT32 startline; - if (gif_dynamicdelay == 2) + if (gif_dynamicdelay ==(UINT8) 2) { // golden's attempt at creating a "dynamic delay" UINT16 mingifdelay = 10; // minimum gif delay in milliseconds (keep at 10 because gifs can't get more precise). @@ -617,7 +617,7 @@ static void GIF_framewrite(void) gif_delayus -= frames*(mingifdelay*1000); // remove frames by the amount of milliseconds they take. don't reset to 0, the microseconds help consistency. } } - else if (gif_dynamicdelay == 1) + else if (gif_dynamicdelay ==(UINT8) 1) { float delayf = ceil(100.0f/NEWTICRATE); @@ -732,7 +732,7 @@ INT32 GIF_open(const char *filename) gif_optimize = (!!cv_gif_optimize.value); gif_downscale = (!!cv_gif_downscale.value); - gif_dynamicdelay = cv_gif_dynamicdelay.value; + gif_dynamicdelay = (UINT8)cv_gif_dynamicdelay.value; gif_localcolortable = (!!cv_gif_localcolortable.value); gif_colorprofile = (!!cv_screenshot_colorprofile.value); gif_headerpalette = GIF_getpalette(0); From e52cb7f6fa1dae752c7d30fd8a7240df64985273 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sun, 8 Nov 2020 17:20:25 +0100 Subject: [PATCH 49/53] Throw an error if too many metatables are registered --- src/lua_baselib.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 468af0aa1..ac9b6053d 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -250,12 +250,15 @@ static int lib_userdataType(lua_State *L) // Only callable during script loading static int lib_registerMetatable(lua_State *L) { - static UINT32 nextid = 1; + static UINT16 nextid = 1; if (!lua_lumploading) return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); luaL_checktype(L, 1, LUA_TTABLE); + if (nextid == 0) + luaL_error(L, "Too many metatables registered?! Please consider rewriting your script once you are sober again.\n"); + lua_getfield(L, LUA_REGISTRYINDEX, LREG_METATABLES); // 2 // registry.metatables[metatable] = nextid lua_pushvalue(L, 1); // 3 From 87206a8c2163236fe7da42ab77b230ba5d6d5f1c Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sun, 8 Nov 2020 17:33:49 +0100 Subject: [PATCH 50/53] Show a console error if the gamestate contains too many tables --- src/lua_script.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lua_script.c b/src/lua_script.c index 6bd1a81c5..c504cc6f3 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -980,8 +980,17 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) lua_pop(gL, 1); } if (!found) + { t++; + if (t == 0) + { + CONS_Alert(CONS_ERROR, "Too many tables to archive!\n"); + WRITEUINT8(save_p, ARCH_NULL); + return 0; + } + } + WRITEUINT8(save_p, ARCH_TABLE); WRITEUINT16(save_p, t); From 9f851dc28594ee9a5ef929e32b520bcbfa8a486f Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Mon, 9 Nov 2020 00:16:40 +0100 Subject: [PATCH 51/53] Return explicitly when failing to register a metatable --- src/lua_baselib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index ac9b6053d..3acbd3d0f 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -257,7 +257,7 @@ static int lib_registerMetatable(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); if (nextid == 0) - luaL_error(L, "Too many metatables registered?! Please consider rewriting your script once you are sober again.\n"); + return luaL_error(L, "Too many metatables registered?! Please consider rewriting your script once you are sober again.\n"); lua_getfield(L, LUA_REGISTRYINDEX, LREG_METATABLES); // 2 // registry.metatables[metatable] = nextid From b8f668b2e0765801f4027d451a86faa4890ada5e Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sun, 8 Nov 2020 23:02:05 -0300 Subject: [PATCH 52/53] rename --- src/hardware/hw_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index f3c313d8d..7667b5f4f 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6011,7 +6011,7 @@ static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA CV_PossibleValue_t glanisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}}; consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, glshaders_cons_t, NULL); -consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowshaders", "On", CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowclientshaders", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_fovchange = CVAR_INIT ("gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL); #ifdef ALAM_LIGHTING From fae4709f4b56cc881c6f106239c1060ce7f521ff Mon Sep 17 00:00:00 2001 From: GoldenTails Date: Sun, 8 Nov 2020 23:28:20 -0600 Subject: [PATCH 53/53] Fix stupid divide-by-zero error --- src/d_clisrv.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index a3fbe88d9..b198011a0 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2501,10 +2501,14 @@ static void CL_RemovePlayer(INT32 playernum, kickreason_t reason) } count--; - spheres = players[playernum].spheres; - rings = players[playernum].rings; - sincrement = spheres/count; - rincrement = rings/count; + sincrement = spheres = players[playernum].spheres; + rincrement = rings = players[playernum].rings; + + if (count) + { + sincrement /= count; + rincrement /= count; + } for (i = 0; i < MAXPLAYERS; i++) {