diff --git a/src/common/engine/m_random.cpp b/src/common/engine/m_random.cpp index df4d532176..ee29a80554 100644 --- a/src/common/engine/m_random.cpp +++ b/src/common/engine/m_random.cpp @@ -388,6 +388,21 @@ FRandom *FRandom::StaticFindRNG (const char *name, bool client) return probe; } +void FRandom::SaveRNGState(TArray& backups) +{ + for (auto cur = RNGList; cur != nullptr; cur = cur->Next) + backups.Push(*cur); +} + +void FRandom::RestoreRNGState(TArray& backups) +{ + unsigned int i = 0u; + for (auto cur = RNGList; cur != nullptr; cur = cur->Next) + *cur = backups[i++]; + + backups.Clear(); +} + //========================================================================== // // FRandom :: StaticPrintSeeds diff --git a/src/g_levellocals.h b/src/g_levellocals.h index 719427d263..c02a6bd016 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -199,7 +199,7 @@ public: void ClearDynamic3DFloorData(); void WorldDone(void); void AirControlChanged(); - AActor *SelectTeleDest(int tid, int tag, bool norandom); + AActor *SelectTeleDest(int tid, int tag, bool norandom, bool isPlayer); bool AlignFlat(int linenum, int side, int fc); void ReplaceTextures(const char *fromname, const char *toname, int flags); diff --git a/src/playsim/p_teleport.cpp b/src/playsim/p_teleport.cpp index c39c6df1dc..be398205cc 100644 --- a/src/playsim/p_teleport.cpp +++ b/src/playsim/p_teleport.cpp @@ -272,7 +272,7 @@ DEFINE_ACTION_FUNCTION(AActor, Teleport) // //----------------------------------------------------------------------------- -AActor *FLevelLocals::SelectTeleDest (int tid, int tag, bool norandom) +AActor *FLevelLocals::SelectTeleDest (int tid, int tag, bool norandom, bool isPlayer) { AActor *searcher; @@ -324,7 +324,8 @@ AActor *FLevelLocals::SelectTeleDest (int tid, int tag, bool norandom) { if (count != 1 && !norandom) { - count = 1 + (pr_teleport() % count); + // Players get their own RNG seed to reduce likelihood of breaking prediction. + count = 1 + ((isPlayer ? pr_playerteleport() : pr_teleport()) % count); } searcher = NULL; while (count > 0) @@ -395,7 +396,7 @@ bool FLevelLocals::EV_Teleport (int tid, int tag, line_t *line, int side, AActor { // Don't teleport if hit back of line, so you can get out of teleporter. return 0; } - searcher = SelectTeleDest(tid, tag, predicting); + searcher = SelectTeleDest(tid, tag, false, thing->player != nullptr && thing->player->mo == thing); if (searcher == NULL) { return false; diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index 463d8f6e31..bdc9e9caa4 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -144,6 +144,8 @@ static DVector3 LastPredictedPosition; static int LastPredictedPortalGroup; static int LastPredictedTic; +static TArray PredictionRNG; + static player_t PredictionPlayerBackup; static AActor *PredictionActor; static TArray PredictionActorBackupArray; @@ -1461,6 +1463,8 @@ void P_PredictPlayer (player_t *player) return; } + FRandom::SaveRNGState(PredictionRNG); + // Save original values for restoration later PredictionPlayerBackup.CopyFrom(*player, false); @@ -1600,6 +1604,8 @@ void P_UnPredictPlayer () // Q: Can this happen? If yes, can we continue? } + FRandom::RestoreRNGState(PredictionRNG); + AActor *savedcamera = player->camera; auto &actInvSel = act->PointerVar(NAME_InvSel);