diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 340bab98f..b8b084c07 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -383,11 +383,13 @@ static UINT8* D_GetTextcmd(tic_t tic, INT32 playernum) return textcmdplayer->cmd; } -static void ExtraDataTicker(void) +static boolean ExtraDataTicker(void) { + boolean anyNetCmd = false; INT32 i; for (i = 0; i < MAXPLAYERS; i++) + { if (playeringame[i] || i == 0) { UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i); @@ -407,6 +409,7 @@ static void ExtraDataTicker(void) DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i)); (listnetxcmd[id])(&curpos, i); DEBFILE("done\n"); + anyNetCmd = true; } else { @@ -421,12 +424,17 @@ static void ExtraDataTicker(void) } } } + } // If you are a client, you can safely forget the net commands for this tic // If you are the server, you need to remember them until every client has been acknowledged, // because if you need to resend a PT_SERVERTICS packet, you will need to put the commands in it if (client) + { D_FreeTextcmd(gametic); + } + + return anyNetCmd; } static void D_Clearticcmd(tic_t tic) @@ -5002,7 +5010,7 @@ static void GetPackets(void) if (netbuffer->packettype == PT_CLIENTJOIN && server) { - if (!levelloading) // Otherwise just ignore + if (levelloading == false) // Otherwise just ignore { HandleConnect(node); } @@ -5585,35 +5593,55 @@ boolean TryRunTics(tic_t realtics) if (ticking) { + // run the count * tics + while (neededtic > gametic) { - // run the count * tics - while (neededtic > gametic) + boolean dontRun = false; + + DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic)); + + ps_tictime = I_GetPreciseTime(); + + dontRun = ExtraDataTicker(); + + if (levelloading == false + || gametic > levelstarttic + 5) // Don't lock-up if a malicious client is sending tons of netxcmds { - DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic)); + // During level load, we want to pause + // execution until we've finished loading + // all of the netxcmds in our buffer. + dontRun = false; + } - ps_tictime = I_GetPreciseTime(); - - G_Ticker((gametic % NEWTICRATERATIO) == 0); - if (Playing() && netgame && (gametic % TICRATE == 0)) + if (dontRun == false) + { + if (levelloading == true) { - Schedule_Run(); - - if (cv_livestudioaudience.value) - { - LiveStudioAudience(); - } + P_PostLoadLevel(); } - ExtraDataTicker(); + G_Ticker((gametic % NEWTICRATERATIO) == 0); + } - gametic++; - consistancy[gametic%BACKUPTICS] = Consistancy(); + if (Playing() && netgame && (gametic % TICRATE == 0)) + { + Schedule_Run(); - ps_tictime = I_GetPreciseTime() - ps_tictime; + if (cv_livestudioaudience.value) + { + LiveStudioAudience(); + } + } - // Leave a certain amount of tics present in the net buffer as long as we've ran at least one tic this frame. - if (client && gamestate == GS_LEVEL && leveltime > 3 && neededtic <= gametic + cv_netticbuffer.value) - break; + gametic++; + consistancy[gametic % BACKUPTICS] = Consistancy(); + + ps_tictime = I_GetPreciseTime() - ps_tictime; + + // Leave a certain amount of tics present in the net buffer as long as we've ran at least one tic this frame. + if (client && gamestate == GS_LEVEL && leveltime > 1 && neededtic <= gametic + cv_netticbuffer.value) + { + break; } } } diff --git a/src/g_game.c b/src/g_game.c index b2d7b933c..c8281bf52 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1589,30 +1589,30 @@ void G_StartTitleCard(void) void G_PreLevelTitleCard(void) { #ifndef NOWIPE - tic_t strtime = I_GetTime(); - tic_t endtime = strtime + (PRELEVELTIME*NEWTICRATERATIO); - tic_t nowtime = strtime; - tic_t lasttime = strtime; - while (nowtime < endtime) - { - // draw loop - ST_runTitleCard(); - ST_preLevelTitleCardDrawer(); - I_FinishUpdate(); // page flip or blit buffer + tic_t strtime = I_GetTime(); + tic_t endtime = strtime + (PRELEVELTIME*NEWTICRATERATIO); + tic_t nowtime = strtime; + tic_t lasttime = strtime; + while (nowtime < endtime) + { + // draw loop + ST_runTitleCard(); + ST_preLevelTitleCardDrawer(); + I_FinishUpdate(); // page flip or blit buffer NetKeepAlive(); // Prevent timeouts #ifdef HWRENDER - if (moviemode && rendermode == render_opengl) - M_LegacySaveFrame(); + if (moviemode && rendermode == render_opengl) + M_LegacySaveFrame(); #endif - while (!((nowtime = I_GetTime()) - lasttime)) - { + while (!((nowtime = I_GetTime()) - lasttime)) + { I_Sleep(cv_sleep.value); I_UpdateTime(cv_timescale.value); } - lasttime = nowtime; - } + lasttime = nowtime; + } #endif } diff --git a/src/k_kart.c b/src/k_kart.c index 6d49e468c..0161c5b90 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -96,7 +96,7 @@ static void K_SpawnDuelOnlyItems(void) void K_TimerReset(void) { - starttime = introtime = 3; + starttime = introtime = 0; numbulbs = 1; inDuel = rainbowstartavailable = false; timelimitintics = extratimeintics = secretextratime = 0; diff --git a/src/lua_hook.h b/src/lua_hook.h index 7088e53c8..4990fe4fb 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -118,7 +118,6 @@ ENUM (STRING_HOOK); //#define LUA_HUDHOOK(type) LUA_HookHUD(HUD_HOOK(type)) extern boolean hook_cmd_running; -extern int hook_defrosting; void LUA_HookVoid(int hook); void LUA_HookHUD(huddrawlist_h, int hook); diff --git a/src/lua_script.c b/src/lua_script.c index f2642e516..631ef3d28 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -39,8 +39,6 @@ lua_State *gL = NULL; -int hook_defrosting; - // List of internal libraries to load from SRB2 static lua_CFunction liblist[] = { LUA_EnumLib, // global metatable for enums @@ -288,9 +286,6 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"starttime")) { lua_pushinteger(L, starttime); return 1; - } else if (fastcmp(word,"defrosting")) { - lua_pushinteger(L, hook_defrosting); - return 1; } else if (fastcmp(word,"curWeather")) { lua_pushinteger(L, curWeather); return 1; diff --git a/src/p_mobj.c b/src/p_mobj.c index b910f4a3d..fcadcf349 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10938,7 +10938,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // Call action functions when the state is set if (st->action.acp1 && (mobj->flags & MF_RUNSPAWNFUNC)) { - if (levelloading) + if (levelloading == true) { // Cache actions in a linked list // with function pointer, and diff --git a/src/p_setup.c b/src/p_setup.c index 7e95d7455..efeb55f9b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7064,6 +7064,8 @@ static void P_InitLevelSettings(void) leveltime = 0; modulothing = 0; + K_TimerReset(); + // special stage tokens, emeralds, and ring total runemeraldmanager = false; emeraldspawndelay = 60*TICRATE; @@ -7618,8 +7620,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) sector_t *ss; virtlump_t *encoreLump = NULL; - K_TimerReset(); - levelloading = true; // This is needed. Don't touch. @@ -7999,10 +7999,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) G_AddMapToBuffer(gamemap-1); - levelloading = false; - - P_RunCachedActions(); - P_MapEnd(); // tm.thing is no longer needed from this point onwards // Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap... @@ -8012,56 +8008,84 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) { // I'd love to do this in the menu code instead of here, but everything's a mess and I can't guarantee saving proper player struct info before the first act's started. You could probably refactor it, but it'd be a lot of effort. Easier to just work off known good code. ~toast 22/06/2020 if (!(ultimatemode || netgame || multiplayer || demo.playback || demo.recording || metalrecording || modeattacking || marathonmode) - && !usedCheats && cursaveslot > 0) + && !usedCheats && cursaveslot > 0) + { G_SaveGame((UINT32)cursaveslot, gamemap); + } // If you're looking for saving sp file progression (distinct from G_SaveGameOver), check G_DoCompleted. } lastmaploaded = gamemap; // HAS to be set after saving!! } - if (!fromnetsave) // uglier hack - { // to make a newly loaded level start on the second frame. + if (!fromnetsave) + { INT32 buf = gametic % BACKUPTICS; for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) + { G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1); + } } - P_PreTicker(2); + for (i = 0; i <= r_splitscreen; i++) + { + postimgtype[i] = postimg_none; + } + + if (marathonmode & MA_INGAME) + { + marathonmode |= MA_INIT; + } P_MapStart(); // just in case MapLoad modifies tm.thing + ACS_RunLevelStartScripts(); LUA_HookInt(gamemap, HOOK(MapLoad)); + P_MapEnd(); // just in case MapLoad modifies tm.thing } + else + { + // Don't run P_PostLoadLevel when loading netgames. + levelloading = false; + } - // No render mode or reloading gamestate, stop here. - if (rendermode == render_none || reloadinggamestate) - return true; + if (rendermode != render_none && reloadinggamestate == false) + { + R_ResetViewInterpolation(0); + R_ResetViewInterpolation(0); + R_UpdateMobjInterpolators(); - R_ResetViewInterpolation(0); - R_ResetViewInterpolation(0); - R_UpdateMobjInterpolators(); + // Title card! + G_StartTitleCard(); - // Title card! - G_StartTitleCard(); - - // Can the title card actually run, though? - if (!WipeStageTitle) - return true; - if (ranspecialwipe == 2) - return true; - - // If so... - // but not if joining because the fade may time us out - if (!fromnetsave) - G_PreLevelTitleCard(); + // Can the title card actually run, though? + if (WipeStageTitle && ranspecialwipe != 2 && fromnetsave == false) + { + G_PreLevelTitleCard(); + } + } return true; } +void P_PostLoadLevel(void) +{ + K_TimerInit(); + + P_RunCachedActions(); + + if (marathonmode & MA_INGAME) + { + marathonmode &= ~MA_INIT; + } + + // We're now done loading the level. + levelloading = false; +} + // // P_RunSOC // diff --git a/src/p_setup.h b/src/p_setup.h index f203c00de..c743460ce 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -103,6 +103,7 @@ extern mapthing_t *mapthings; void P_SetupLevelSky(const char *skytexname, boolean global); void P_RespawnThings(void); boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate); +void P_PostLoadLevel(void); #ifdef HWRENDER void HWR_LoadLevel(void); #endif diff --git a/src/p_tick.c b/src/p_tick.c index 4ed8fd83a..8187044c6 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -832,86 +832,9 @@ void P_Ticker(boolean run) if (demo.playback) G_StoreRewindInfo(); - if (leveltime == 2) - { - // The values needed to set this properly are not correct at map load, - // so we have to do it at the second tick instead... - K_TimerInit(); - } - for (i = 0; i < MAXPLAYERS; i++) { G_CopyTiccmd(&players[i].oldcmd, &players[i].cmd, 1); } - // Z_CheckMemCleanup(); } - -// Abbreviated ticker for pre-loading, calls thinkers and assorted things -void P_PreTicker(INT32 frames) -{ - INT32 i; - ticcmd_t temptic; - - for (i = 0; i <= r_splitscreen; i++) - postimgtype[i] = postimg_none; - - if (marathonmode & MA_INGAME) - marathonmode |= MA_INIT; - - hook_defrosting = frames; - - while (hook_defrosting) - { - P_MapStart(); - - R_UpdateMobjInterpolators(); - - LUA_HOOK(PreThinkFrame); - - K_UpdateAllPlayerPositions(); - - // OK! Now that we got all of that sorted, players can think! - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) - { - // stupid fucking cmd hack - // if it isn't for this, players can move in preticker time - // (and disrupt demo recording and other things !!) - memcpy(&temptic, &players[i].cmd, sizeof(ticcmd_t)); - memset(&players[i].cmd, 0, sizeof(ticcmd_t)); - - P_PlayerThink(&players[i]); - - memcpy(&players[i].cmd, &temptic, sizeof(ticcmd_t)); - } - - P_RunThinkers(); - - // Run any "after all the other thinkers" stuff - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) - P_PlayerAfterThink(&players[i]); - - LUA_HOOK(ThinkFrame); - - // Run shield positioning - P_RunOverlays(); - - P_UpdateSpecials(); - P_RespawnSpecials(); - - LUA_HOOK(PostThinkFrame); - - R_UpdateLevelInterpolators(); - R_UpdateViewInterpolation(); - R_ResetViewInterpolation(0); - - P_MapEnd(); - - hook_defrosting--; - } - - if (marathonmode & MA_INGAME) - marathonmode &= ~MA_INIT; -}