Add ensureDeterminism to saves

This commit is contained in:
Tamás Bálint Misius 2023-04-15 19:01:42 +02:00
parent 9c3b966c18
commit a8604ef579
No known key found for this signature in database
GPG Key ID: 5B472A12F6ECA9F2
10 changed files with 64 additions and 50 deletions

View File

@ -539,6 +539,7 @@ void GameSave::readOPS(const std::vector<char> &data)
CheckBsonFieldFloat(iter, "ambientAirTemp", &ambientAirTemp); CheckBsonFieldFloat(iter, "ambientAirTemp", &ambientAirTemp);
CheckBsonFieldInt(iter, "edgeMode", &edgeMode); CheckBsonFieldInt(iter, "edgeMode", &edgeMode);
CheckBsonFieldInt(iter, "pmapbits", &pmapbits); CheckBsonFieldInt(iter, "pmapbits", &pmapbits);
CheckBsonFieldBool(iter, "ensureDeterminism", &ensureDeterminism);
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]));
@ -2546,6 +2547,7 @@ std::pair<bool, std::vector<char>> GameSave::serialiseOPS() const
bson_append_binary(&b, "soapLinks", (char)BSON_BIN_USER, (const char *)&soapLinkData[0], soapLinkDataLen); bson_append_binary(&b, "soapLinks", (char)BSON_BIN_USER, (const char *)&soapLinkData[0], soapLinkDataLen);
if (ensureDeterminism) if (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_long(&b, "rngState0", int64_t(rngState[0]));

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "common/Plane.h" #include "common/Plane.h"
#include "common/String.h" #include "common/String.h"
#include "common/tpt-rand.h"
#include "simulation/Sign.h" #include "simulation/Sign.h"
#include "simulation/Particle.h" #include "simulation/Particle.h"
#include "Misc.h" #include "Misc.h"
@ -95,8 +96,8 @@ public:
bool hasPressure = false; bool hasPressure = false;
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 read by serializeOPS, never written bool ensureDeterminism = false; // only taken seriously by serializeOPS; readOPS may set this even if the save does not have everything required for determinism
std::array<uint64_t, 2> rngState; RNG::State rngState;
uint64_t frameCount = 0; uint64_t frameCount = 0;
//Simulation data //Simulation data

View File

@ -5,8 +5,11 @@
class RNG class RNG
{ {
public:
using State = std::array<uint64_t, 2>;
private: private:
std::array<uint64_t, 2> s; State s;
uint64_t next(); uint64_t next();
public: public:
unsigned int operator()(); unsigned int operator()();
@ -18,12 +21,12 @@ public:
RNG(); RNG();
void seed(unsigned int sd); void seed(unsigned int sd);
void state(std::array<uint64_t, 2> ns) void state(State ns)
{ {
s = ns; s = ns;
} }
std::array<uint64_t, 2> state() const State state() const
{ {
return s; return s;
} }

View File

@ -934,6 +934,31 @@ SaveInfo * GameModel::GetSave()
return currentSave; 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) void GameModel::SetSave(SaveInfo * newSave, bool invertIncludePressure)
{ {
if(currentSave != newSave) if(currentSave != newSave)
@ -947,23 +972,10 @@ void GameModel::SetSave(SaveInfo * newSave, bool invertIncludePressure)
delete currentFile; delete currentFile;
currentFile = NULL; currentFile = NULL;
if(currentSave && currentSave->GetGameSave()) if (newSave && newSave->GetGameSave())
{ {
GameSave * saveData = currentSave->GetGameSave(); GameSave *saveData = newSave->GetGameSave();
SetPaused(saveData->paused | GetPaused()); SaveToSimParameters(saveData);
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();
sim->clear_sim(); sim->clear_sim();
ren->ClearAccumulation(); ren->ClearAccumulation();
if (!sim->Load(saveData, !invertIncludePressure)) if (!sim->Load(saveData, !invertIncludePressure))
@ -1011,27 +1023,10 @@ void GameModel::SetSaveFile(SaveFile * newSave, bool invertIncludePressure)
delete currentSave; delete currentSave;
currentSave = NULL; currentSave = NULL;
if(newSave && newSave->GetGameSave()) if (newSave && newSave->GetGameSave())
{ {
GameSave * saveData = newSave->GetGameSave(); GameSave *saveData = newSave->GetGameSave();
SetPaused(saveData->paused | GetPaused()); SaveToSimParameters(saveData);
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->clear_sim(); sim->clear_sim();
ren->ClearAccumulation(); ren->ClearAccumulation();
if (!sim->Load(saveData, !invertIncludePressure)) if (!sim->Load(saveData, !invertIncludePressure))

View File

@ -114,6 +114,9 @@ private:
void notifyToolTipChanged(); void notifyToolTipChanged();
void notifyQuickOptionsChanged(); void notifyQuickOptionsChanged();
void notifyLastToolChanged(); void notifyLastToolChanged();
void SaveToSimParameters(const GameSave *saveData);
public: public:
GameModel(); GameModel();
~GameModel(); ~GameModel();

View File

@ -214,6 +214,17 @@ static int simHash(lua_State *l)
return 1; 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): LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
TPTScriptInterface(c, m), TPTScriptInterface(c, m),
luacon_mousex(0), luacon_mousex(0),
@ -1003,6 +1014,7 @@ void LuaScriptInterface::initSimulationAPI()
{"temperatureScale", simulation_temperatureScale}, {"temperatureScale", simulation_temperatureScale},
{"randomseed", simRandomseed}, {"randomseed", simRandomseed},
{"hash", simHash}, {"hash", simHash},
{"ensureDeterminism", simEnsureDeterminism},
{NULL, NULL} {NULL, NULL}
}; };
luaL_register(l, "simulation", simulationAPIMethods); luaL_register(l, "simulation", simulationAPIMethods);

View File

@ -64,8 +64,6 @@ int Simulation::Load(const GameSave * originalSave, bool includePressure, int fu
} }
RecalcFreeParticles(false); RecalcFreeParticles(false);
frameCount = save->frameCount;
rng.state(save->rngState);
auto &possiblyCarriesType = Particle::PossiblyCarriesType(); auto &possiblyCarriesType = Particle::PossiblyCarriesType();
auto &properties = Particle::GetProperties(); 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->hasPressure = true;
newSave->hasAmbientHeat = true; newSave->hasAmbientHeat = true;
} }
if (true) // TODO: tie to an option maybe? newSave->ensureDeterminism = ensureDeterminism;
{
newSave->ensureDeterminism = true;
}
newSave->stkm.rocketBoots1 = player.rocketBoots; newSave->stkm.rocketBoots1 = player.rocketBoots;
newSave->stkm.rocketBoots2 = player2.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) void Simulation::clear_sim(void)
{ {
ensureDeterminism = false;
frameCount = 0; frameCount = 0;
debug_nextToUpdate = 0; debug_nextToUpdate = 0;
debug_mostRecentlyUpdated = -1; debug_mostRecentlyUpdated = -1;

View File

@ -119,6 +119,7 @@ public:
int sandcolour_frame; int sandcolour_frame;
int deco_space; int deco_space;
uint64_t frameCount; uint64_t frameCount;
bool ensureDeterminism;
int Load(const GameSave * save, bool includePressure); int Load(const GameSave * save, bool includePressure);
int Load(const GameSave * save, bool includePressure, int x, int y); int Load(const GameSave * save, bool includePressure, int x, int y);

View File

@ -2,6 +2,7 @@
#include "Particle.h" #include "Particle.h"
#include "Sign.h" #include "Sign.h"
#include "Stickman.h" #include "Stickman.h"
#include "common/tpt-rand.h"
#include <vector> #include <vector>
#include <array> #include <array>
#include <json/json.h> #include <json/json.h>
@ -36,7 +37,7 @@ public:
std::vector<sign> signs; std::vector<sign> signs;
uint64_t FrameCount; uint64_t FrameCount;
std::array<uint64_t, 2> RngState; RNG::State RngState;
uint32_t Hash() const; uint32_t Hash() const;

View File

@ -68,7 +68,7 @@ struct SnapshotDelta
HunkVector<uint32_t> stickmen; HunkVector<uint32_t> stickmen;
SingleDiff<std::vector<sign>> signs; SingleDiff<std::vector<sign>> signs;
SingleDiff<uint64_t> FrameCount; SingleDiff<uint64_t> FrameCount;
SingleDiff<std::array<uint64_t, 2>> RngState; SingleDiff<RNG::State> RngState;
SingleDiff<Json::Value> Authors; SingleDiff<Json::Value> Authors;