diff --git a/src/d_clisrv.c b/src/d_clisrv.c index b33149803..91fd6def8 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5590,7 +5590,7 @@ static INT16 Consistancy(void) // Coop desynching enemies is painful if (gamestate == GS_LEVEL) { - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { if (i & 1) { diff --git a/src/d_main.cpp b/src/d_main.cpp index 7df05d12f..29bb57091 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -853,8 +853,6 @@ void D_SRB2Loop(void) realtics = entertic - oldentertics; oldentertics = entertic; - refreshdirmenu = 0; // not sure where to put this, here as good as any? - if (demo.playback && gamestate == GS_LEVEL) { // Nicer place to put this. @@ -870,8 +868,16 @@ void D_SRB2Loop(void) interp = R_UsingFrameInterpolation() && !dedicated; doDisplay = false; - if (realtics > 0 || singletics) + renderisnewtic = (realtics > 0 || singletics); + + bool timeisprogressing = (!(paused || P_AutoPause()) && !hu_stopped); + + if (renderisnewtic) { + refreshdirmenu = 0; + + P_ResetInterpHudRandSeed(timeisprogressing); + // don't skip more than 10 frames at a time // (fadein / fadeout cause massive frame skip!) if (realtics > 8) @@ -906,19 +912,13 @@ void D_SRB2Loop(void) doDisplay = true; } - - renderisnewtic = true; - } - else - { - renderisnewtic = false; } if (interp) { renderdeltatics = FLOAT_TO_FIXED(deltatics); - if (!(paused || P_AutoPause()) && !hu_stopped) + if (timeisprogressing) { rendertimefrac = g_time.timefrac; } @@ -938,6 +938,9 @@ void D_SRB2Loop(void) if ((interp || doDisplay) && !frameskip) { + if (!renderisnewtic) + P_ResetInterpHudRandSeed(false); + ranwipe = D_Display(); } diff --git a/src/g_demo.c b/src/g_demo.c index bedbf1e41..a16e5fc4a 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -364,7 +364,7 @@ void G_ReadDemoExtraData(void) switch (p) { case DW_RNG: - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { rng = READUINT32(demobuf.p); @@ -507,7 +507,7 @@ void G_WriteDemoExtraData(void) timeout = 16; WRITEUINT8(demobuf.p, DW_RNG); - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { WRITEUINT32(demobuf.p, P_GetRandSeed(i)); } @@ -1202,7 +1202,7 @@ void G_GhostTicker(void) else if (ziptic == DW_RNG) { INT32 i; - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { g->p += 4; // RNG seed } @@ -2435,7 +2435,7 @@ void G_BeginRecording(void) demotime_p = NULL; } - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { WRITEUINT32(demobuf.p, P_GetInitSeed(i)); } @@ -2899,7 +2899,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo) goto badreplay; } - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { info.p += 4; // RNG seed } @@ -3028,7 +3028,7 @@ void G_DoPlayDemo(const char *defdemoname) char *pdemoname; UINT8 availabilities[MAXPLAYERS][MAXAVAILABILITY]; UINT8 version,subversion; - UINT32 randseed[PRNUMCLASS]; + UINT32 randseed[PRNUMSYNCED]; char msg[1024]; boolean spectator, bot; @@ -3308,7 +3308,7 @@ void G_DoPlayDemo(const char *defdemoname) hu_demolap = READUINT32(demobuf.p); // Random seed - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { randseed[i] = READUINT32(demobuf.p); } @@ -3530,7 +3530,7 @@ void G_DoPlayDemo(const char *defdemoname) R_ExecuteSetViewSize(); - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { P_SetRandSeed(i, randseed[i]); } @@ -3667,7 +3667,7 @@ void G_AddGhost(savebuffer_t *buffer, char *defdemoname) if (flags & ATTACKING_LAP) p += 4; - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { p += 4; // random seed } @@ -3876,7 +3876,7 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer) if (flags & ATTACKING_LAP) temp.lap = READUINT32(p); - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { p += 4; // random seed } diff --git a/src/k_hud.c b/src/k_hud.c index af5a5f725..3378f7cf5 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2422,8 +2422,8 @@ static void K_drawBossHealthBar(void) randtemp = bossinfo.visualbar-(bossinfo.visualdiv/(2*FRACUNIT)); if (randtemp > 0) - randlen = M_RandomKey(randtemp)+1; - randsign = M_RandomChance(FRACUNIT/2); + randlen = P_RandomKey(PR_INTERPHUDRANDOM, randtemp)+1; + randsign = P_RandomChance(PR_INTERPHUDRANDOM, FRACUNIT/2); // Right wing. V_DrawScaledPatch(startx-1, starty, V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_FLIP, kp_bossbar[0]); @@ -2439,10 +2439,10 @@ static void K_drawBossHealthBar(void) { randtemp = bossinfo.visualbar-(bossinfo.visualdiv/(2*FRACUNIT)); if (randtemp > 0) - randlen = M_RandomKey(randtemp)+1; + randlen = P_RandomKey(PR_INTERPHUDRANDOM, randtemp)+1; if (barstatus > 1) { - rolrand = M_RandomKey(barstatus)+1; + rolrand = P_RandomKey(PR_INTERPHUDRANDOM, barstatus)+1; } else { diff --git a/src/m_random.c b/src/m_random.c index 9401bb341..0d490bb5b 100644 --- a/src/m_random.c +++ b/src/m_random.c @@ -342,6 +342,37 @@ void P_SetRandSeedNetD(const char *rfile, INT32 rline, pr_class_t pr_class, UINT rng.seed[pr_class] = seed; } +/** Change PR_INTERPHUDRANDOM state. + * Used for interp-safe HUD randomisation. + * + * \sa P_SetRandSeed + */ +#ifndef DEBUGRANDOM +void P_ResetInterpHudRandSeed(boolean newframe) +{ +#else +void P_ResetInterpHudRandSeedD(const char *rfile, INT32 rline, boolean newframe) +{ + CONS_Printf("P_ResetInterpHudRandSeed(%c) at: %sp %d\n", (newframe ? 'T' : 'F'), rfile, rline); +#endif + + if (newframe == true) + { + // Advance the initialisation to the current seed. + rng.init[PR_INTERPHUDRANDOM] = rng.seed[PR_INTERPHUDRANDOM]; + } + else + { + // Rewind the seed to the last initialisation. + rng.seed[PR_INTERPHUDRANDOM] = rng.init[PR_INTERPHUDRANDOM]; + } + + // xorshift requires a nonzero seed + // this should never happen, but just in case it DOES, we check + if (!rng.seed[PR_INTERPHUDRANDOM]) + rng.seed[PR_INTERPHUDRANDOM] = rng.init[PR_INTERPHUDRANDOM] = DEFAULT_SEED; +} + /** Initializes random seeds for all classes. * Used at the beginning of a game. * @@ -354,7 +385,7 @@ void P_ClearRandom(UINT32 seed) if (!seed) seed = DEFAULT_SEED; - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { P_SetRandSeed(i, seed); diff --git a/src/m_random.h b/src/m_random.h index 479ea24ef..77a3f33ce 100644 --- a/src/m_random.h +++ b/src/m_random.h @@ -83,6 +83,10 @@ typedef enum PR_FUZZ, // Stability testing + PRNUMSYNCED, + + PR_INTERPHUDRANDOM = PRNUMSYNCED, // Interpolation-accomodating HUD randomisation + PRNUMCLASS } pr_class_t; @@ -132,15 +136,18 @@ UINT32 P_RandomPeek(pr_class_t pr_class); #define P_GetInitSeed(pr) P_GetInitSeedD(__FILE__, __LINE__, pr) #define P_SetRandSeed(pr, s) P_SetRandSeedD(__FILE__, __LINE__, pr, s) #define P_SetRandSeedNet(pr, i, s) P_SetRandSeedD(__FILE__, __LINE__, pr, i, s) +#define P_ResetInterpHudRandSeed(newframe) P_ResetInterpHudRandSeedD(__FILE__, __LINE__, newframe) UINT32 P_GetRandSeedD(const char *rfile, INT32 rline, pr_class_t pr_class); UINT32 P_GetInitSeedD(const char *rfile, INT32 rline, pr_class_t pr_class); void P_SetRandSeedD(const char *rfile, INT32 rline, pr_class_t pr_class, UINT32 seed); void P_SetRandSeedNetD(const char *rfile, INT32 rline, pr_class_t pr_class, UINT32 init, UINT32 seed); +void P_ResetInterpHudRandSeedD(const char *rfile, INT32 rline, boolean newframe); #else UINT32 P_GetRandSeed(pr_class_t pr_class); UINT32 P_GetInitSeed(pr_class_t pr_class); void P_SetRandSeed(pr_class_t pr_class, UINT32 seed); void P_SetRandSeedNet(pr_class_t pr_class, UINT32 init, UINT32 seed); +void P_ResetInterpHudRandSeed(boolean newframe); #endif void P_ClearRandom(UINT32 seed); diff --git a/src/p_saveg.c b/src/p_saveg.c index 53e18051d..064d8fdc4 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -6354,7 +6354,7 @@ static void P_NetArchiveRNG(savebuffer_t *save) WRITEUINT32(save->p, ARCHIVEBLOCK_RNG); - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { WRITEUINT32(save->p, P_GetInitSeed(i)); WRITEUINT32(save->p, P_GetRandSeed(i)); @@ -6368,7 +6368,7 @@ static inline void P_NetUnArchiveRNG(savebuffer_t *save) if (READUINT32(save->p) != ARCHIVEBLOCK_RNG) I_Error("Bad $$$.sav at archive block RNG"); - for (i = 0; i < PRNUMCLASS; i++) + for (i = 0; i < PRNUMSYNCED; i++) { UINT32 init = READUINT32(save->p); UINT32 seed = READUINT32(save->p);