diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index 135be5978..02641a47b 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -539,6 +539,7 @@ void GameSave::readOPS(const std::vector &data) CheckBsonFieldFloat(iter, "ambientAirTemp", &ambientAirTemp); CheckBsonFieldInt(iter, "edgeMode", &edgeMode); CheckBsonFieldInt(iter, "pmapbits", &pmapbits); + CheckBsonFieldBool(iter, "ensureDeterminism", &ensureDeterminism); CheckBsonFieldLong(iter, "frameCount", reinterpret_cast(&frameCount)); CheckBsonFieldLong(iter, "rngState0", reinterpret_cast(&rngState[0])); CheckBsonFieldLong(iter, "rngState1", reinterpret_cast(&rngState[1])); @@ -2546,6 +2547,7 @@ std::pair> GameSave::serialiseOPS() const bson_append_binary(&b, "soapLinks", (char)BSON_BIN_USER, (const char *)&soapLinkData[0], soapLinkDataLen); if (ensureDeterminism) { + 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])); diff --git a/src/client/GameSave.h b/src/client/GameSave.h index 5fd7b310f..bf94529b9 100644 --- a/src/client/GameSave.h +++ b/src/client/GameSave.h @@ -1,6 +1,7 @@ #pragma once #include "common/Plane.h" #include "common/String.h" +#include "common/tpt-rand.h" #include "simulation/Sign.h" #include "simulation/Particle.h" #include "Misc.h" @@ -95,8 +96,8 @@ public: bool hasPressure = false; bool hasAmbientHeat = false; bool hasBlockAirMaps = false; // only written by readOPS, never read - bool ensureDeterminism = false; // only read by serializeOPS, never written - std::array rngState; + bool ensureDeterminism = false; // only taken seriously by serializeOPS; readOPS may set this even if the save does not have everything required for determinism + RNG::State rngState; uint64_t frameCount = 0; //Simulation data diff --git a/src/common/tpt-rand.h b/src/common/tpt-rand.h index cc2b15da1..9eb4ed29a 100644 --- a/src/common/tpt-rand.h +++ b/src/common/tpt-rand.h @@ -5,8 +5,11 @@ class RNG { +public: + using State = std::array; + private: - std::array s; + State s; uint64_t next(); public: unsigned int operator()(); @@ -18,12 +21,12 @@ public: RNG(); void seed(unsigned int sd); - void state(std::array ns) + void state(State ns) { s = ns; } - std::array state() const + State state() const { return s; } diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index d8a56f114..0e8f11ade 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -934,6 +934,31 @@ SaveInfo * GameModel::GetSave() return currentSave; } +void GameModel::SaveToSimParameters(const GameSave *saveData) +{ + SetPaused(saveData->paused | GetPaused()); + sim->gravityMode = saveData->gravityMode; + sim->customGravityX = saveData->customGravityX; + sim->customGravityY = saveData->customGravityY; + sim->air->airMode = saveData->airMode; + sim->air->ambientAirTemp = saveData->ambientAirTemp; + sim->edgeMode = saveData->edgeMode; + sim->legacy_enable = saveData->legacyEnable; + sim->water_equal_test = saveData->waterEEnabled; + sim->aheat_enable = saveData->aheatEnable; + if (saveData->gravityEnable && !sim->grav->IsEnabled()) + { + sim->grav->start_grav_async(); + } + else if (!saveData->gravityEnable && sim->grav->IsEnabled()) + { + sim->grav->stop_grav_async(); + } + sim->frameCount = saveData->frameCount; + sim->rng.state(saveData->rngState); + sim->ensureDeterminism = saveData->ensureDeterminism; +} + void GameModel::SetSave(SaveInfo * newSave, bool invertIncludePressure) { if(currentSave != newSave) @@ -947,23 +972,10 @@ void GameModel::SetSave(SaveInfo * newSave, bool invertIncludePressure) delete currentFile; currentFile = NULL; - if(currentSave && currentSave->GetGameSave()) + if (newSave && newSave->GetGameSave()) { - GameSave * saveData = currentSave->GetGameSave(); - SetPaused(saveData->paused | GetPaused()); - sim->gravityMode = saveData->gravityMode; - sim->customGravityX = saveData->customGravityX; - sim->customGravityY = saveData->customGravityY; - sim->air->airMode = saveData->airMode; - sim->air->ambientAirTemp = saveData->ambientAirTemp; - sim->edgeMode = saveData->edgeMode; - sim->legacy_enable = saveData->legacyEnable; - sim->water_equal_test = saveData->waterEEnabled; - sim->aheat_enable = saveData->aheatEnable; - if(saveData->gravityEnable) - sim->grav->start_grav_async(); - else - sim->grav->stop_grav_async(); + GameSave *saveData = newSave->GetGameSave(); + SaveToSimParameters(saveData); sim->clear_sim(); ren->ClearAccumulation(); if (!sim->Load(saveData, !invertIncludePressure)) @@ -1011,27 +1023,10 @@ void GameModel::SetSaveFile(SaveFile * newSave, bool invertIncludePressure) delete currentSave; currentSave = NULL; - if(newSave && newSave->GetGameSave()) + if (newSave && newSave->GetGameSave()) { - GameSave * saveData = newSave->GetGameSave(); - SetPaused(saveData->paused | GetPaused()); - sim->gravityMode = saveData->gravityMode; - sim->customGravityX = saveData->customGravityX; - sim->customGravityY = saveData->customGravityY; - sim->air->airMode = saveData->airMode; - sim->air->ambientAirTemp = saveData->ambientAirTemp; - sim->edgeMode = saveData->edgeMode; - sim->legacy_enable = saveData->legacyEnable; - sim->water_equal_test = saveData->waterEEnabled; - sim->aheat_enable = saveData->aheatEnable; - if(saveData->gravityEnable && !sim->grav->IsEnabled()) - { - sim->grav->start_grav_async(); - } - else if(!saveData->gravityEnable && sim->grav->IsEnabled()) - { - sim->grav->stop_grav_async(); - } + GameSave *saveData = newSave->GetGameSave(); + SaveToSimParameters(saveData); sim->clear_sim(); ren->ClearAccumulation(); if (!sim->Load(saveData, !invertIncludePressure)) diff --git a/src/gui/game/GameModel.h b/src/gui/game/GameModel.h index 17a3135e1..726d39b9b 100644 --- a/src/gui/game/GameModel.h +++ b/src/gui/game/GameModel.h @@ -114,6 +114,9 @@ private: void notifyToolTipChanged(); void notifyQuickOptionsChanged(); void notifyLastToolChanged(); + + void SaveToSimParameters(const GameSave *saveData); + public: GameModel(); ~GameModel(); diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index d0c829952..178d5d209 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -214,6 +214,17 @@ static int simHash(lua_State *l) return 1; } +static int simEnsureDeterminism(lua_State *l) +{ + if (lua_gettop(l)) + { + luacon_sim->ensureDeterminism = lua_toboolean(l, 1); + return 0; + } + lua_pushboolean(l, luacon_sim->ensureDeterminism); + return 1; +} + LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m): TPTScriptInterface(c, m), luacon_mousex(0), @@ -1003,6 +1014,7 @@ void LuaScriptInterface::initSimulationAPI() {"temperatureScale", simulation_temperatureScale}, {"randomseed", simRandomseed}, {"hash", simHash}, + {"ensureDeterminism", simEnsureDeterminism}, {NULL, NULL} }; luaL_register(l, "simulation", simulationAPIMethods); diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 0d980e88b..44a429321 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -64,8 +64,6 @@ int Simulation::Load(const GameSave * originalSave, bool includePressure, int fu } RecalcFreeParticles(false); - frameCount = save->frameCount; - rng.state(save->rngState); auto &possiblyCarriesType = Particle::PossiblyCarriesType(); auto &properties = Particle::GetProperties(); @@ -490,15 +488,12 @@ GameSave * Simulation::Save(bool includePressure, int fullX, int fullY, int full } } } - if (includePressure) + if (includePressure || ensureDeterminism) { newSave->hasPressure = true; newSave->hasAmbientHeat = true; } - if (true) // TODO: tie to an option maybe? - { - newSave->ensureDeterminism = true; - } + newSave->ensureDeterminism = ensureDeterminism; newSave->stkm.rocketBoots1 = player.rocketBoots; newSave->stkm.rocketBoots2 = player2.rocketBoots; @@ -1092,6 +1087,7 @@ int Simulation::parts_avg(int ci, int ni,int t) void Simulation::clear_sim(void) { + ensureDeterminism = false; frameCount = 0; debug_nextToUpdate = 0; debug_mostRecentlyUpdated = -1; diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index 5f275b7c7..4bdfee02a 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -119,6 +119,7 @@ public: int sandcolour_frame; int deco_space; uint64_t frameCount; + bool ensureDeterminism; int Load(const GameSave * save, bool includePressure); int Load(const GameSave * save, bool includePressure, int x, int y); diff --git a/src/simulation/Snapshot.h b/src/simulation/Snapshot.h index f42d958f3..e9fb52be9 100644 --- a/src/simulation/Snapshot.h +++ b/src/simulation/Snapshot.h @@ -2,6 +2,7 @@ #include "Particle.h" #include "Sign.h" #include "Stickman.h" +#include "common/tpt-rand.h" #include #include #include @@ -36,7 +37,7 @@ public: std::vector signs; uint64_t FrameCount; - std::array RngState; + RNG::State RngState; uint32_t Hash() const; diff --git a/src/simulation/SnapshotDelta.h b/src/simulation/SnapshotDelta.h index 16d28cad1..dfc004846 100644 --- a/src/simulation/SnapshotDelta.h +++ b/src/simulation/SnapshotDelta.h @@ -68,7 +68,7 @@ struct SnapshotDelta HunkVector stickmen; SingleDiff> signs; SingleDiff FrameCount; - SingleDiff> RngState; + SingleDiff RngState; SingleDiff Authors;