From 34e4d90dacebdec3fa4c77374ff31e2e1067bce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sat, 15 Apr 2023 23:03:54 +0200 Subject: [PATCH] Properly seed rng at load time for saves that don't carry rng state Also save rngState as a user object rather than two separate i64s. --- src/client/GameSave.cpp | 19 ++++++++++++++----- src/client/GameSave.h | 1 + src/gui/game/GameModel.cpp | 9 ++++++++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index 02641a47b..75c8b984c 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -25,13 +25,11 @@ static void CheckBsonFieldFloat(bson_iterator iter, const char *field, float *se GameSave::GameSave(int width, int height) { - rngState = RNG().state(); // initialize it with something sane setSize(width, height); } GameSave::GameSave(const std::vector &data, bool newWantAuthors) { - rngState = RNG().state(); // initialize it with something sane wantAuthors = newWantAuthors; blockWidth = 0; blockHeight = 0; @@ -543,7 +541,19 @@ void GameSave::readOPS(const std::vector &data) CheckBsonFieldLong(iter, "frameCount", reinterpret_cast(&frameCount)); CheckBsonFieldLong(iter, "rngState0", reinterpret_cast(&rngState[0])); CheckBsonFieldLong(iter, "rngState1", reinterpret_cast(&rngState[1])); - if (!strcmp(bson_iterator_key(&iter), "signs")) + if (!strcmp(bson_iterator_key(&iter), "rngState")) + { + if (bson_iterator_type(&iter) == BSON_BINDATA && ((unsigned char)bson_iterator_bin_type(&iter)) == BSON_BIN_USER && bson_iterator_bin_len(&iter) == sizeof(rngState)) + { + memcpy(&rngState, bson_iterator_bin_data(&iter), sizeof(rngState)); + hasRngState = true; + } + else + { + fprintf(stderr, "Invalid datatype for rngState: %d[%d] %d[%d] %d[%d]\n", bson_iterator_type(&iter), bson_iterator_type(&iter)==BSON_BINDATA, (unsigned char)bson_iterator_bin_type(&iter), ((unsigned char)bson_iterator_bin_type(&iter))==BSON_BIN_USER, bson_iterator_bin_len(&iter), bson_iterator_bin_len(&iter)>0); + } + } + else if (!strcmp(bson_iterator_key(&iter), "signs")) { if (bson_iterator_type(&iter)==BSON_ARRAY) { @@ -2550,8 +2560,7 @@ std::pair> GameSave::serialiseOPS() const bson_append_bool(&b, "ensureDeterminism", ensureDeterminism); bson_append_binary(&b, "blockAir", (char)BSON_BIN_USER, (const char *)&blockAirData[0], blockAirDataLen); bson_append_long(&b, "frameCount", int64_t(frameCount)); - bson_append_long(&b, "rngState0", int64_t(rngState[0])); - bson_append_long(&b, "rngState1", int64_t(rngState[1])); + bson_append_binary(&b, "rngState", (char)BSON_BIN_USER, (const char *)&rngState, sizeof(rngState)); RESTRICTVERSION(98, 0); } unsigned int signsCount = 0; diff --git a/src/client/GameSave.h b/src/client/GameSave.h index bf94529b9..21335504c 100644 --- a/src/client/GameSave.h +++ b/src/client/GameSave.h @@ -97,6 +97,7 @@ public: bool hasAmbientHeat = false; bool hasBlockAirMaps = false; // only written by readOPS, never read bool ensureDeterminism = false; // only taken seriously by serializeOPS; readOPS may set this even if the save does not have everything required for determinism + bool hasRngState = false; // only written by readOPS, never read RNG::State rngState; uint64_t frameCount = 0; diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index 0e8f11ade..595f75fcd 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -955,7 +955,14 @@ void GameModel::SaveToSimParameters(const GameSave *saveData) sim->grav->stop_grav_async(); } sim->frameCount = saveData->frameCount; - sim->rng.state(saveData->rngState); + if (saveData->hasRngState) + { + sim->rng.state(saveData->rngState); + } + else + { + sim->rng = RNG(); + } sim->ensureDeterminism = saveData->ensureDeterminism; }