diff --git a/src/Config.template.h b/src/Config.template.h index c7f1fa2fb..fa98ff459 100644 --- a/src/Config.template.h +++ b/src/Config.template.h @@ -33,7 +33,7 @@ constexpr int MINOR_VERSION = 0; constexpr int BUILD_NUM = 352; constexpr int SNAPSHOT_ID = @SNAPSHOT_ID@; constexpr int MOD_ID = @MOD_ID@; -constexpr int FUTURE_SAVE_VERSION = 97; +constexpr int FUTURE_SAVE_VERSION = 98; constexpr int FUTURE_MINOR_VERSION = 0; constexpr char IDENT_RELTYPE = SNAPSHOT ? 'S' : (BETA ? 'B' : 'R'); diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index 7a08040ee..135be5978 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -20,15 +20,18 @@ static void ConvertBsonToJson(bson_iterator *b, Json::Value *j, int depth = 0); static void CheckBsonFieldUser(bson_iterator iter, const char *field, unsigned char **data, unsigned int *fieldLen); static void CheckBsonFieldBool(bson_iterator iter, const char *field, bool *flag); static void CheckBsonFieldInt(bson_iterator iter, const char *field, int *setting); +static void CheckBsonFieldLong(bson_iterator iter, const char *field, int64_t *setting); static void CheckBsonFieldFloat(bson_iterator iter, const char *field, float *setting); 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; @@ -92,6 +95,8 @@ void GameSave::setSize(int newWidth, int newHeight) velocityX = Plane(blockWidth, blockHeight, 0.0f); velocityY = Plane(blockWidth, blockHeight, 0.0f); ambientHeat = Plane(blockWidth, blockHeight, 0.0f); + blockAir = Plane(blockWidth, blockHeight, 0); + blockAirh = Plane(blockWidth, blockHeight, 0); } std::pair> GameSave::Serialise() const @@ -226,6 +231,8 @@ void GameSave::Transform(matrix2d transform, vector2d translate, vector2d transl Plane velocityXNew(newBlockWidth, newBlockHeight, 0.0f); Plane velocityYNew(newBlockWidth, newBlockHeight, 0.0f); Plane ambientHeatNew(newBlockWidth, newBlockHeight, 0.0f); + Plane blockAirNew(newBlockWidth, newBlockHeight, 0); + Plane blockAirhNew(newBlockWidth, newBlockHeight, 0); // Match these up with the matrices provided in GameView::OnKeyPress. bool patchPipeR = transform.a == 0 && transform.b == 1 && transform.c == -1 && transform.d == 0; @@ -324,6 +331,8 @@ void GameSave::Transform(matrix2d transform, vector2d translate, vector2d transl velocityXNew[ny][nx] = velocityX[y][x]; velocityYNew[ny][nx] = velocityY[y][x]; ambientHeatNew[ny][nx] = ambientHeat[y][x]; + blockAirNew[ny][nx] = blockAir[y][x]; + blockAirhNew[ny][nx] = blockAirh[y][x]; } translated = v2d_add(m2d_multiply_v2d(transform, translated), translateReal); @@ -337,6 +346,8 @@ void GameSave::Transform(matrix2d transform, vector2d translate, vector2d transl velocityX = velocityXNew; velocityY = velocityYNew; ambientHeat = ambientHeatNew; + blockAir = blockAirNew; + blockAirh = blockAirhNew; } static void CheckBsonFieldUser(bson_iterator iter, const char *field, unsigned char **data, unsigned int *fieldLen) @@ -384,6 +395,21 @@ static void CheckBsonFieldInt(bson_iterator iter, const char *field, int *settin } } +static void CheckBsonFieldLong(bson_iterator iter, const char *field, int64_t *setting) +{ + if (!strcmp(bson_iterator_key(&iter), field)) + { + if (bson_iterator_type(&iter) == BSON_LONG) + { + *setting = bson_iterator_long(&iter); + } + else + { + fprintf(stderr, "Wrong type for %s\n", bson_iterator_key(&iter)); + } + } +} + static void CheckBsonFieldFloat(bson_iterator iter, const char *field, float *setting) { if (!strcmp(bson_iterator_key(&iter), field)) @@ -404,9 +430,9 @@ void GameSave::readOPS(const std::vector &data) Renderer::PopulateTables(); unsigned char *inputData = (unsigned char*)&data[0], *partsData = NULL, *partsPosData = NULL, *fanData = NULL, *wallData = NULL, *soapLinkData = NULL; - unsigned char *pressData = NULL, *vxData = NULL, *vyData = NULL, *ambientData = NULL; + unsigned char *pressData = NULL, *vxData = NULL, *vyData = NULL, *ambientData = NULL, *blockAirData = nullptr; unsigned int inputDataLen = data.size(), bsonDataLen = 0, partsDataLen, partsPosDataLen, fanDataLen, wallDataLen, soapLinkDataLen; - unsigned int pressDataLen, vxDataLen, vyDataLen, ambientDataLen; + unsigned int pressDataLen, vxDataLen, vyDataLen, ambientDataLen, blockAirDataLen; unsigned partsCount = 0; unsigned int blockX, blockY, blockW, blockH, fullX, fullY, fullW, fullH; int savedVersion = inputData[4]; @@ -498,6 +524,7 @@ void GameSave::readOPS(const std::vector &data) CheckBsonFieldUser(iter, "vxMap", &vxData, &vxDataLen); CheckBsonFieldUser(iter, "vyMap", &vyData, &vyDataLen); CheckBsonFieldUser(iter, "ambientMap", &ambientData, &ambientDataLen); + CheckBsonFieldUser(iter, "blockAir", &blockAirData, &blockAirDataLen); CheckBsonFieldUser(iter, "fanMap", &fanData, &fanDataLen); CheckBsonFieldUser(iter, "soapLinks", &soapLinkData, &soapLinkDataLen); CheckBsonFieldBool(iter, "legacyEnable", &legacyEnable); @@ -512,6 +539,9 @@ void GameSave::readOPS(const std::vector &data) CheckBsonFieldFloat(iter, "ambientAirTemp", &ambientAirTemp); CheckBsonFieldInt(iter, "edgeMode", &edgeMode); CheckBsonFieldInt(iter, "pmapbits", &pmapbits); + 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 (bson_iterator_type(&iter)==BSON_ARRAY) @@ -840,6 +870,22 @@ void GameSave::readOPS(const std::vector &data) hasAmbientHeat = true; } + if (blockAirData) + { + if (blockW * blockH * 2 > blockAirDataLen) + throw ParseException(ParseException::Corrupt, "Not enough block air data"); + auto blockAirhData = blockAirData + blockW * blockH; + for (unsigned int x = 0; x < blockW; x++) + { + for (unsigned int y = 0; y < blockH; y++) + { + blockAir[blockY + y][blockX + x] = blockAirData[y * blockW + x]; + blockAirh[blockY + y][blockX + x] = blockAirhData[y * blockW + x]; + } + } + hasBlockAirMaps = true; + } + //Read particle data if (partsData && partsPosData) { @@ -1933,13 +1979,16 @@ std::pair> GameSave::serialiseOPS() const std::vector vxData(blockWidth*blockHeight*2); std::vector vyData(blockWidth*blockHeight*2); std::vector ambientData(blockWidth*blockHeight*2, 0); + std::vector blockAirData(blockWidth * blockHeight * 2); + auto *blockAirhData = &blockAirData[blockWidth * blockHeight]; unsigned int wallDataLen = blockWidth*blockHeight, fanDataLen = 0, pressDataLen = 0, vxDataLen = 0, vyDataLen = 0, ambientDataLen = 0; for (x = blockX; x < blockX+blockW; x++) { for (y = blockY; y < blockY+blockH; y++) { - wallData[(y-blockY)*blockW+(x-blockX)] = blockMap[y][x]; + auto rowMajorIndex = (y - blockY) * blockW + (x - blockX); + wallData[rowMajorIndex] = blockMap[y][x]; if (blockMap[y][x]) hasWallData = true; @@ -1957,6 +2006,9 @@ std::pair> GameSave::serialiseOPS() const vyData[vyDataLen++] = (unsigned char)((int)(velY*128)&0xFF); vyData[vyDataLen++] = (unsigned char)((int)(velY*128)>>8); + + blockAirData[rowMajorIndex] = blockAir[y][x]; + blockAirhData[rowMajorIndex] = blockAirh[y][x]; } if (hasAmbientHeat) @@ -1983,6 +2035,7 @@ std::pair> GameSave::serialiseOPS() const } } } + auto blockAirDataLen = blockAirData.size(); //Index positions of all particles, using linked lists //partsPosFirstMap is pmap for the first particle in each position @@ -2491,6 +2544,14 @@ std::pair> GameSave::serialiseOPS() const bson_append_binary(&b, "ambientMap", (char)BSON_BIN_USER, (const char*)&ambientData[0], ambientDataLen); if (soapLinkDataLen) bson_append_binary(&b, "soapLinks", (char)BSON_BIN_USER, (const char *)&soapLinkData[0], soapLinkDataLen); + if (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])); + RESTRICTVERSION(98, 0); + } unsigned int signsCount = 0; for (size_t i = 0; i < signs.size(); i++) { diff --git a/src/client/GameSave.h b/src/client/GameSave.h index 7f60154b5..5fd7b310f 100644 --- a/src/client/GameSave.h +++ b/src/client/GameSave.h @@ -6,6 +6,7 @@ #include "Misc.h" #include "SimulationConfig.h" #include +#include #include struct sign; @@ -93,6 +94,10 @@ public: int minorVersion = 0; 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; + uint64_t frameCount = 0; //Simulation data int particlesCount = 0; @@ -104,6 +109,8 @@ public: Plane velocityX; Plane velocityY; Plane ambientHeat; + Plane blockAir; + Plane blockAirh; //Simulation Options bool waterEEnabled = false; diff --git a/src/common/tpt-rand.h b/src/common/tpt-rand.h index 508521def..cc2b15da1 100644 --- a/src/common/tpt-rand.h +++ b/src/common/tpt-rand.h @@ -17,6 +17,16 @@ public: RNG(); void seed(unsigned int sd); + + void state(std::array ns) + { + s = ns; + } + + std::array state() const + { + return s; + } }; // Please only use this on the main thread and never for simulation stuff. diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index 8d0b365c5..01af521a9 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -35,6 +35,7 @@ #include "simulation/Simulation.h" #include "simulation/ToolClasses.h" #include "simulation/SaveRenderer.h" +#include "simulation/Snapshot.h" #include "gui/interface/Window.h" #include "gui/interface/Engine.h" diff --git a/src/simulation/Air.cpp b/src/simulation/Air.cpp index 13409f1e0..30d55d468 100644 --- a/src/simulation/Air.cpp +++ b/src/simulation/Air.cpp @@ -356,7 +356,7 @@ void Air::Invert() } // called when loading saves / stamps to ensure nothing "leaks" the first frame -void Air::RecalculateBlockAirMaps() +void Air::ApproximateBlockAirMaps() { for (int i = 0; i <= sim.parts_lastActiveIndex; i++) { diff --git a/src/simulation/Air.h b/src/simulation/Air.h index 79f626f8d..be1f02fab 100644 --- a/src/simulation/Air.h +++ b/src/simulation/Air.h @@ -32,6 +32,6 @@ public: void Clear(); void ClearAirH(); void Invert(); - void RecalculateBlockAirMaps(); + void ApproximateBlockAirMaps(); Air(Simulation & sim); }; diff --git a/src/simulation/Editing.cpp b/src/simulation/Editing.cpp index c8c343b86..6a3be9e0f 100644 --- a/src/simulation/Editing.cpp +++ b/src/simulation/Editing.cpp @@ -22,6 +22,8 @@ std::unique_ptr Simulation::CreateSnapshot() snap->AmbientHeat .insert (snap->AmbientHeat .begin(), &hv [0][0] , &hv [0][0] + NCELL); snap->BlockMap .insert (snap->BlockMap .begin(), &bmap[0][0] , &bmap[0][0] + NCELL); snap->ElecMap .insert (snap->ElecMap .begin(), &emap[0][0] , &emap[0][0] + NCELL); + snap->BlockAir .insert (snap->BlockAir .begin(), &air->bmap_blockair[0][0] , &air->bmap_blockair[0][0] + NCELL); + snap->BlockAirH .insert (snap->BlockAirH .begin(), &air->bmap_blockairh[0][0], &air->bmap_blockairh[0][0] + NCELL); snap->FanVelocityX .insert (snap->FanVelocityX .begin(), &fvx [0][0] , &fvx [0][0] + NCELL); snap->FanVelocityY .insert (snap->FanVelocityY .begin(), &fvy [0][0] , &fvy [0][0] + NCELL); snap->GravVelocityX .insert (snap->GravVelocityX .begin(), &gravx [0] , &gravx [0] + NCELL); @@ -35,6 +37,8 @@ std::unique_ptr Simulation::CreateSnapshot() snap->stickmen .push_back(player2); snap->stickmen .push_back(player); snap->signs = signs; + snap->FrameCount = frameCount; + snap->RngState = rng.state(); return snap; } @@ -53,6 +57,8 @@ void Simulation::Restore(const Snapshot &snap) std::copy(snap.AmbientHeat .begin(), snap.AmbientHeat .end(), &hv[0][0] ); std::copy(snap.BlockMap .begin(), snap.BlockMap .end(), &bmap[0][0] ); std::copy(snap.ElecMap .begin(), snap.ElecMap .end(), &emap[0][0] ); + std::copy(snap.BlockAir .begin(), snap.BlockAir .end(), &air->bmap_blockair[0][0] ); + std::copy(snap.BlockAirH .begin(), snap.BlockAirH .end(), &air->bmap_blockairh[0][0]); std::copy(snap.FanVelocityX .begin(), snap.FanVelocityX .end(), &fvx[0][0] ); std::copy(snap.FanVelocityY .begin(), snap.FanVelocityY .end(), &fvy[0][0] ); if (grav->IsEnabled()) @@ -70,8 +76,9 @@ void Simulation::Restore(const Snapshot &snap) player = snap.stickmen[snap.stickmen.size() - 1]; player2 = snap.stickmen[snap.stickmen.size() - 2]; signs = snap.signs; + frameCount = snap.FrameCount; + rng.state(snap.RngState); parts_lastActiveIndex = NPART - 1; - air->RecalculateBlockAirMaps(); RecalcFreeParticles(false); gravWallChanged = true; } diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 70a013eba..0d980e88b 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -64,6 +64,8 @@ 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(); @@ -325,12 +327,20 @@ int Simulation::Load(const GameSave * originalSave, bool includePressure, int fu } if (save->hasAmbientHeat) hv[saveBlockY+blockY][saveBlockX+blockX] = save->ambientHeat[saveBlockY][saveBlockX]; + if (save->hasBlockAirMaps) + { + air->bmap_blockair[saveBlockY+blockY][saveBlockX+blockX] = save->blockAir[saveBlockY][saveBlockX]; + air->bmap_blockairh[saveBlockY+blockY][saveBlockX+blockX] = save->blockAirh[saveBlockY][saveBlockX]; + } } } } gravWallChanged = true; - air->RecalculateBlockAirMaps(); + if (!save->hasBlockAirMaps) + { + air->ApproximateBlockAirMaps(); + } return 0; } @@ -371,6 +381,8 @@ GameSave * Simulation::Save(bool includePressure, int fullX, int fullY, int full GameSave * newSave = new GameSave(blockW, blockH); auto &possiblyCarriesType = Particle::PossiblyCarriesType(); auto &properties = Particle::GetProperties(); + newSave->frameCount = frameCount; + newSave->rngState = rng.state(); int storedParts = 0; int elementCount[PT_NUM]; @@ -473,6 +485,8 @@ GameSave * Simulation::Save(bool includePressure, int fullX, int fullY, int full newSave->velocityX[saveBlockY][saveBlockX] = vx[saveBlockY+blockY][saveBlockX+blockX]; newSave->velocityY[saveBlockY][saveBlockX] = vy[saveBlockY+blockY][saveBlockX+blockX]; newSave->ambientHeat[saveBlockY][saveBlockX] = hv[saveBlockY+blockY][saveBlockX+blockX]; + newSave->blockAir[saveBlockY][saveBlockX] = air->bmap_blockair[saveBlockY+blockY][saveBlockX+blockX]; + newSave->blockAirh[saveBlockY][saveBlockX] = air->bmap_blockairh[saveBlockY+blockY][saveBlockX+blockX]; } } } @@ -481,6 +495,10 @@ GameSave * Simulation::Save(bool includePressure, int fullX, int fullY, int full newSave->hasPressure = true; newSave->hasAmbientHeat = true; } + if (true) // TODO: tie to an option maybe? + { + newSave->ensureDeterminism = true; + } newSave->stkm.rocketBoots1 = player.rocketBoots; newSave->stkm.rocketBoots2 = player2.rocketBoots; @@ -1074,6 +1092,7 @@ int Simulation::parts_avg(int ci, int ni,int t) void Simulation::clear_sim(void) { + frameCount = 0; debug_nextToUpdate = 0; debug_mostRecentlyUpdated = -1; emp_decor = 0; @@ -2124,9 +2143,10 @@ int Simulation::create_part(int p, int x, int y, int t, int v) if((elements[t].Properties & TYPE_PART) && pretty_powder) { int colr, colg, colb; - colr = PIXR(elements[t].Colour) + int(sandcolour * 1.3) + rng.between(-20, 20) + rng.between(-15, 15); - colg = PIXG(elements[t].Colour) + int(sandcolour * 1.3) + rng.between(-20, 20) + rng.between(-15, 15); - colb = PIXB(elements[t].Colour) + int(sandcolour * 1.3) + rng.between(-20, 20) + rng.between(-15, 15); + auto sandcolourToUse = p == -2 ? sandcolour_interface : sandcolour; + colr = PIXR(elements[t].Colour) + int(sandcolourToUse * 1.3) + rng.between(-20, 20) + rng.between(-15, 15); + colg = PIXG(elements[t].Colour) + int(sandcolourToUse * 1.3) + rng.between(-20, 20) + rng.between(-15, 15); + colb = PIXB(elements[t].Colour) + int(sandcolourToUse * 1.3) + rng.between(-20, 20) + rng.between(-15, 15); colr = colr>255 ? 255 : (colr<0 ? 0 : colr); colg = colg>255 ? 255 : (colg<0 ? 0 : colg); colb = colb>255 ? 255 : (colb<0 ? 0 : colb); @@ -3818,8 +3838,9 @@ void Simulation::BeforeSim() if (elementRecount) std::fill(elementCount, elementCount+PT_NUM, 0); } - sandcolour = (int)(20.0f*sin((float)sandcolour_frame*(TPT_PI_FLT/180.0f))); + sandcolour_interface = (int)(20.0f*sin((float)sandcolour_frame*(TPT_PI_FLT/180.0f))); sandcolour_frame = (sandcolour_frame+1)%360; + sandcolour = (int)(20.0f*sin((float)(frameCount)*(TPT_PI_FLT/180.0f))); if (gravWallChanged) { @@ -3990,6 +4011,8 @@ void Simulation::AfterSim() Element_EMP_Trigger(this, emp_trigger_count); emp_trigger_count = 0; } + + frameCount += 1; } Simulation::~Simulation() diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index 98944b97d..5f275b7c7 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -115,8 +115,10 @@ public: int framerender; int pretty_powder; int sandcolour; + int sandcolour_interface; int sandcolour_frame; int deco_space; + uint64_t frameCount; int Load(const GameSave * save, bool includePressure); int Load(const GameSave * save, bool includePressure, int x, int y); diff --git a/src/simulation/Snapshot.cpp b/src/simulation/Snapshot.cpp new file mode 100644 index 000000000..d4d70c72a --- /dev/null +++ b/src/simulation/Snapshot.cpp @@ -0,0 +1,43 @@ +#include "Snapshot.h" + +uint32_t Snapshot::Hash() const +{ + // http://www.isthe.com/chongo/tech/comp/fnv/ + auto hash = UINT32_C(2166136261); + auto take = [&hash](const uint8_t *data, size_t size) { + for (auto i = 0U; i < size; ++i) + { + hash ^= data[i]; + hash *= UINT32_C(16777619); + } + }; + auto takeThing = [&take](auto &thing) { + take(reinterpret_cast(&thing), sizeof(thing)); + }; + auto takeVector = [&take](auto &vec) { + take(reinterpret_cast(vec.data()), vec.size() * sizeof(vec[0])); + }; + takeVector(AirPressure); + takeVector(AirVelocityX); + takeVector(AirVelocityY); + takeVector(AmbientHeat); + takeVector(Particles); + takeVector(GravVelocityX); + takeVector(GravVelocityY); + takeVector(GravValue); + takeVector(GravMap); + takeVector(BlockMap); + takeVector(ElecMap); + takeVector(BlockAir); + takeVector(BlockAirH); + takeVector(FanVelocityX); + takeVector(FanVelocityY); + takeVector(PortalParticles); + takeVector(WirelessData); + takeVector(stickmen); + takeThing(FrameCount); + takeThing(RngState[0]); + takeThing(RngState[1]); + // signs and Authors are excluded on purpose, as they aren't POD and don't have much effect on the simulation. + return hash; +} diff --git a/src/simulation/Snapshot.h b/src/simulation/Snapshot.h index fa716df8f..f42d958f3 100644 --- a/src/simulation/Snapshot.h +++ b/src/simulation/Snapshot.h @@ -3,6 +3,7 @@ #include "Sign.h" #include "Stickman.h" #include +#include #include class Snapshot @@ -22,6 +23,8 @@ public: std::vector BlockMap; std::vector ElecMap; + std::vector BlockAir; + std::vector BlockAirH; std::vector FanVelocityX; std::vector FanVelocityY; @@ -32,32 +35,12 @@ public: std::vector stickmen; std::vector signs; + uint64_t FrameCount; + std::array RngState; + + uint32_t Hash() const; + Json::Value Authors; - Snapshot() : - AirPressure(), - AirVelocityX(), - AirVelocityY(), - AmbientHeat(), - Particles(), - GravVelocityX(), - GravVelocityY(), - GravValue(), - GravMap(), - BlockMap(), - ElecMap(), - FanVelocityX(), - FanVelocityY(), - PortalParticles(), - WirelessData(), - stickmen(), - signs() - { - - } - - virtual ~Snapshot() - { - - } + virtual ~Snapshot() = default; }; diff --git a/src/simulation/SnapshotDelta.cpp b/src/simulation/SnapshotDelta.cpp index 88a5938f5..b1e33c562 100644 --- a/src/simulation/SnapshotDelta.cpp +++ b/src/simulation/SnapshotDelta.cpp @@ -14,7 +14,7 @@ // size" even if their sizes weren't derived from compile-time constants, as they'd still // be the same size throughout the life of a Simulation, and thus any Snapshot created from it. // * Fields of dynamic size, whose sizes may be different between Snapshots. These are, fortunately, -// the minority: Particles, signs and Authors. +// the minority: Particles, signs, etc. // * Each field in Snapshot has a mirror set of fields in SnapshotDelta. Fields of static size // have mirror fields whose type is HunkVector, templated by the item type of the // corresponding field; these fields are handled in a uniform manner. Fields of dynamic size are @@ -34,7 +34,7 @@ // * ApplyHunkVector is the B = A + d operation, which takes a field of a SnapshotDelta and // the corresponding field of an "older" Snapshot, and fills the latter with the "new" values. // * This difference type is intended for fields of static size. This covers all fields in Snapshot -// except for Particles, signs, and Authors. +// except for Particles, signs, Authors, FrameCount, and RngState. // * A SingleDiff is, unsurprisingly enough, a single Diff, with an accompanying bool that signifies // whether the Diff does in fact hold the "old" value of a field in the "old" Snapshot and the "new" // value of the same field in the "new" Snapshot. If this bool is false, the data in the fields @@ -43,7 +43,8 @@ // * FillSingleDiff is the d = B - A operation, while ApplySingleDiff and ApplySingleDiff // are the A = B - d and B = A + d operations. These are self-explanatory. // * This difference type is intended for fields of dynamic size whose data doesn't change often and -// doesn't consume too much memory. This covers the Snapshot fields signs and Authors. +// doesn't consume too much memory. This covers the Snapshot fields signs and Authors, FrameCount, +// and RngState. // * This leaves Snapshot::Particles. This field mirrors Simulation::parts, which is actually also // a field of static size, but since most of the time most of this array is empty, it doesn't make // sense to store all of it in a Snapshot (unlike Air::hv, which can be fairly chaotic (i.e. may have @@ -212,11 +213,15 @@ std::unique_ptr SnapshotDelta::FromSnapshots(const Snapshot &oldS FillHunkVector(oldSnap.GravMap , newSnap.GravMap , delta.GravMap ); FillHunkVector(oldSnap.BlockMap , newSnap.BlockMap , delta.BlockMap ); FillHunkVector(oldSnap.ElecMap , newSnap.ElecMap , delta.ElecMap ); + FillHunkVector(oldSnap.BlockAir , newSnap.BlockAir , delta.BlockAir ); + FillHunkVector(oldSnap.BlockAirH , newSnap.BlockAirH , delta.BlockAirH ); FillHunkVector(oldSnap.FanVelocityX , newSnap.FanVelocityX , delta.FanVelocityX ); FillHunkVector(oldSnap.FanVelocityY , newSnap.FanVelocityY , delta.FanVelocityY ); FillHunkVector(oldSnap.WirelessData , newSnap.WirelessData , delta.WirelessData ); FillSingleDiff(oldSnap.signs , newSnap.signs , delta.signs ); FillSingleDiff(oldSnap.Authors , newSnap.Authors , delta.Authors ); + FillSingleDiff(oldSnap.FrameCount , newSnap.FrameCount , delta.FrameCount ); + FillSingleDiff(oldSnap.RngState , newSnap.RngState , delta.RngState ); FillHunkVectorPtr(reinterpret_cast(&oldSnap.PortalParticles[0]), reinterpret_cast(&newSnap.PortalParticles[0]), delta.PortalParticles, newSnap.PortalParticles.size() * ParticleUint32Count); FillHunkVectorPtr(reinterpret_cast(&oldSnap.stickmen[0]) , reinterpret_cast(&newSnap.stickmen[0] ), delta.stickmen , newSnap.stickmen .size() * playerstUint32Count); @@ -245,11 +250,15 @@ std::unique_ptr SnapshotDelta::Forward(const Snapshot &oldSnap) ApplyHunkVector(GravMap , newSnap.GravMap ); ApplyHunkVector(BlockMap , newSnap.BlockMap ); ApplyHunkVector(ElecMap , newSnap.ElecMap ); + ApplyHunkVector(BlockAir , newSnap.BlockAir ); + ApplyHunkVector(BlockAirH , newSnap.BlockAirH ); ApplyHunkVector(FanVelocityX , newSnap.FanVelocityX ); ApplyHunkVector(FanVelocityY , newSnap.FanVelocityY ); ApplyHunkVector(WirelessData , newSnap.WirelessData ); ApplySingleDiff(signs , newSnap.signs ); ApplySingleDiff(Authors , newSnap.Authors ); + ApplySingleDiff(FrameCount , newSnap.FrameCount ); + ApplySingleDiff(RngState , newSnap.RngState ); ApplyHunkVectorPtr(PortalParticles, reinterpret_cast(&newSnap.PortalParticles[0])); ApplyHunkVectorPtr(stickmen , reinterpret_cast(&newSnap.stickmen[0] )); @@ -276,11 +285,15 @@ std::unique_ptr SnapshotDelta::Restore(const Snapshot &newSnap) ApplyHunkVector(GravMap , oldSnap.GravMap ); ApplyHunkVector(BlockMap , oldSnap.BlockMap ); ApplyHunkVector(ElecMap , oldSnap.ElecMap ); + ApplyHunkVector(BlockAir , oldSnap.BlockAir ); + ApplyHunkVector(BlockAirH , oldSnap.BlockAirH ); ApplyHunkVector(FanVelocityX , oldSnap.FanVelocityX ); ApplyHunkVector(FanVelocityY , oldSnap.FanVelocityY ); ApplyHunkVector(WirelessData , oldSnap.WirelessData ); ApplySingleDiff(signs , oldSnap.signs ); ApplySingleDiff(Authors , oldSnap.Authors ); + ApplySingleDiff(FrameCount , oldSnap.FrameCount ); + ApplySingleDiff(RngState , oldSnap.RngState ); ApplyHunkVectorPtr(PortalParticles, reinterpret_cast(&oldSnap.PortalParticles[0])); ApplyHunkVectorPtr(stickmen , reinterpret_cast(&oldSnap.stickmen[0] )); diff --git a/src/simulation/SnapshotDelta.h b/src/simulation/SnapshotDelta.h index 1ceb9397b..16d28cad1 100644 --- a/src/simulation/SnapshotDelta.h +++ b/src/simulation/SnapshotDelta.h @@ -1,9 +1,7 @@ #pragma once - -#include "Snapshot.h" - #include #include +#include "Snapshot.h" struct SnapshotDelta { @@ -58,6 +56,8 @@ struct SnapshotDelta HunkVector BlockMap; HunkVector ElecMap; + HunkVector BlockAir; + HunkVector BlockAirH; HunkVector FanVelocityX; HunkVector FanVelocityY; @@ -67,6 +67,8 @@ struct SnapshotDelta HunkVector WirelessData; HunkVector stickmen; SingleDiff> signs; + SingleDiff FrameCount; + SingleDiff> RngState; SingleDiff Authors; diff --git a/src/simulation/meson.build b/src/simulation/meson.build index e06026dd1..76cb360d5 100644 --- a/src/simulation/meson.build +++ b/src/simulation/meson.build @@ -21,6 +21,7 @@ powder_files += files( 'Editing.cpp', 'SimTool.cpp', 'ToolClasses.cpp', + 'Snapshot.cpp', 'SnapshotDelta.cpp', ) render_files += files(