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.
This commit is contained in:
Tamás Bálint Misius
2023-04-15 23:03:54 +02:00
parent a8604ef579
commit 34e4d90dac
3 changed files with 23 additions and 6 deletions

View File

@@ -25,13 +25,11 @@ static void CheckBsonFieldFloat(bson_iterator iter, const char *field, float *se
GameSave::GameSave(int width, int height) GameSave::GameSave(int width, int height)
{ {
rngState = RNG().state(); // initialize it with something sane
setSize(width, height); setSize(width, height);
} }
GameSave::GameSave(const std::vector<char> &data, bool newWantAuthors) GameSave::GameSave(const std::vector<char> &data, bool newWantAuthors)
{ {
rngState = RNG().state(); // initialize it with something sane
wantAuthors = newWantAuthors; wantAuthors = newWantAuthors;
blockWidth = 0; blockWidth = 0;
blockHeight = 0; blockHeight = 0;
@@ -543,7 +541,19 @@ void GameSave::readOPS(const std::vector<char> &data)
CheckBsonFieldLong(iter, "frameCount", reinterpret_cast<int64_t *>(&frameCount)); CheckBsonFieldLong(iter, "frameCount", reinterpret_cast<int64_t *>(&frameCount));
CheckBsonFieldLong(iter, "rngState0", reinterpret_cast<int64_t *>(&rngState[0])); CheckBsonFieldLong(iter, "rngState0", reinterpret_cast<int64_t *>(&rngState[0]));
CheckBsonFieldLong(iter, "rngState1", reinterpret_cast<int64_t *>(&rngState[1])); CheckBsonFieldLong(iter, "rngState1", reinterpret_cast<int64_t *>(&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) if (bson_iterator_type(&iter)==BSON_ARRAY)
{ {
@@ -2550,8 +2560,7 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
bson_append_bool(&b, "ensureDeterminism", ensureDeterminism); bson_append_bool(&b, "ensureDeterminism", ensureDeterminism);
bson_append_binary(&b, "blockAir", (char)BSON_BIN_USER, (const char *)&blockAirData[0], blockAirDataLen); 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, "frameCount", int64_t(frameCount));
bson_append_long(&b, "rngState0", int64_t(rngState[0])); bson_append_binary(&b, "rngState", (char)BSON_BIN_USER, (const char *)&rngState, sizeof(rngState));
bson_append_long(&b, "rngState1", int64_t(rngState[1]));
RESTRICTVERSION(98, 0); RESTRICTVERSION(98, 0);
} }
unsigned int signsCount = 0; unsigned int signsCount = 0;

View File

@@ -97,6 +97,7 @@ public:
bool hasAmbientHeat = false; bool hasAmbientHeat = false;
bool hasBlockAirMaps = false; // only written by readOPS, never read 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 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; RNG::State rngState;
uint64_t frameCount = 0; uint64_t frameCount = 0;

View File

@@ -955,7 +955,14 @@ void GameModel::SaveToSimParameters(const GameSave *saveData)
sim->grav->stop_grav_async(); sim->grav->stop_grav_async();
} }
sim->frameCount = saveData->frameCount; sim->frameCount = saveData->frameCount;
if (saveData->hasRngState)
{
sim->rng.state(saveData->rngState); sim->rng.state(saveData->rngState);
}
else
{
sim->rng = RNG();
}
sim->ensureDeterminism = saveData->ensureDeterminism; sim->ensureDeterminism = saveData->ensureDeterminism;
} }