From cc27126f27aa6593387bd315b780657e4b1b27c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sat, 9 Dec 2023 15:35:26 +0100 Subject: [PATCH] Move palette code to GameSave Because Simulation shouldn't need to know about palettes. --- src/client/GameSave.cpp | 101 ++++++++++++++++++++++++++- src/client/GameSave.h | 5 ++ src/client/ThumbnailRendererTask.cpp | 2 +- src/gui/game/GameView.cpp | 2 +- src/gui/preview/PreviewView.cpp | 4 +- src/simulation/SaveRenderer.cpp | 6 +- src/simulation/SaveRenderer.h | 3 +- src/simulation/Simulation.cpp | 85 +--------------------- src/simulation/Simulation.h | 3 +- 9 files changed, 115 insertions(+), 96 deletions(-) diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index f506a0485..2baead119 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -47,6 +47,83 @@ GameSave::GameSave(const std::vector &data, bool newWantAuthors) } } +void GameSave::MapPalette() +{ + int partMap[PT_NUM]; + for(int i = 0; i < PT_NUM; i++) + { + partMap[i] = i; + } + + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + if(palette.size()) + { + for(int i = 0; i < PT_NUM; i++) + { + partMap[i] = 0; + } + for(auto &pi : palette) + { + if (pi.second > 0 && pi.second < PT_NUM) + { + int myId = 0; + for (int i = 0; i < PT_NUM; i++) + { + if (elements[i].Enabled && elements[i].Identifier == pi.first) + { + myId = i; + } + } + if (myId) + { + partMap[pi.second] = myId; + } + else + { + missingElements.identifiers.insert(pi); + } + } + } + } + auto paletteLookup = [this, &partMap](int type) { + if (type > 0 && type < PT_NUM) + { + auto carriedType = partMap[type]; + if (!carriedType) // type is not 0 so this shouldn't be 0 either + { + missingElements.ids.insert(type); + } + type = carriedType; + } + return type; + }; + + unsigned int pmapmask = (1<= PT_NUM) + { + continue; + } + tempPart.type = paletteLookup(tempPart.type); + for (auto index : possiblyCarriesType) + { + if (elements[tempPart.type].CarriesTypeIn & (1U << index)) + { + auto *prop = reinterpret_cast(reinterpret_cast(&tempPart) + properties[index].Offset); + auto carriedType = *prop & int(pmapmask); + auto extra = *prop >> pmapbits; + carriedType = paletteLookup(carriedType); + *prop = PMAP(extra, carriedType); + } + } + } +} + void GameSave::Expand(const std::vector &data) { try @@ -68,6 +145,7 @@ void GameSave::Expand(const std::vector &data) std::cerr << "Got Magic number '" << data[0] << data[1] << data[2] << "'" << std::endl; throw ParseException(ParseException::Corrupt, "Invalid save format"); } + MapPalette(); } else { @@ -1980,6 +2058,9 @@ std::pair> GameSave::serialiseOPS() const std::vector partsSaveIndex(NPART); unsigned int partsCount = 0; std::fill(&partsSaveIndex[0], &partsSaveIndex[0] + NPART, 0); + auto &sd = SimulationData::CRef(); + auto &elements = sd.elements; + std::set paletteSet; for (auto pos : partS.OriginRect().Range()) { //Find the first particle in this position @@ -1997,6 +2078,16 @@ std::pair> GameSave::serialiseOPS() const //Store saved particle index+1 for this partsptr index (0 means not saved) partsSaveIndex[i] = (partsCount++) + 1; + paletteSet.insert(particles[i].type); + for (auto index : possiblyCarriesType) + { + if (elements[particles[i].type].CarriesTypeIn & (1U << index)) + { + auto *prop = reinterpret_cast(reinterpret_cast(&particles[i]) + properties[index].Offset); + paletteSet.insert(TYP(*prop)); + } + } + //Type (required) partsData[partsDataLen++] = particles[i].type; @@ -2250,6 +2341,12 @@ std::pair> GameSave::serialiseOPS() const } } + std::vector paletteData; + for (int ID : paletteSet) + { + paletteData.push_back(GameSave::PaletteItem(elements[ID].Identifier, ID)); + } + unsigned int soapLinkDataLen = 0; std::vector soapLinkData(3*soapCount); if (soapCount) @@ -2381,10 +2478,10 @@ std::pair> GameSave::serialiseOPS() const { bson_append_binary(&b, "parts", (char)BSON_BIN_USER, (const char *)&partsData[0], partsDataLen); - if (palette.size()) + if (paletteData.size()) { bson_append_start_array(&b, "palette"); - for(auto iter = palette.begin(), end = palette.end(); iter != end; ++iter) + for(auto iter = paletteData.begin(), end = paletteData.end(); iter != end; ++iter) { bson_append_int(&b, (*iter).first.c_str(), (*iter).second); } diff --git a/src/client/GameSave.h b/src/client/GameSave.h index a22d359a3..bf34a6563 100644 --- a/src/client/GameSave.h +++ b/src/client/GameSave.h @@ -5,6 +5,7 @@ #include "common/Version.h" #include "simulation/Sign.h" #include "simulation/Particle.h" +#include "simulation/MissingElements.h" #include "Misc.h" #include "SimulationConfig.h" #include @@ -62,6 +63,8 @@ class GameSave void readPSv(const std::vector &data); std::pair> serialiseOPS() const; + void MapPalette(); + public: Vec2 blockSize = { 0, 0 }; bool fromNewerVersion = false; @@ -101,6 +104,8 @@ public: int edgeMode = 0; bool wantAuthors = true; + MissingElements missingElements; + //Signs std::vector signs; StkmData stkm; diff --git a/src/client/ThumbnailRendererTask.cpp b/src/client/ThumbnailRendererTask.cpp index 5267ed88d..fe40d5802 100644 --- a/src/client/ThumbnailRendererTask.cpp +++ b/src/client/ThumbnailRendererTask.cpp @@ -29,7 +29,7 @@ ThumbnailRendererTask::~ThumbnailRendererTask() bool ThumbnailRendererTask::doWork() { - std::tie(thumbnail, std::ignore) = SaveRenderer::Ref().Render(save.get(), decorations, fire); + thumbnail = SaveRenderer::Ref().Render(save.get(), decorations, fire); if (thumbnail) { thumbnail->ResizeToFit(size, true); diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index 9599efc92..d1379cc90 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -1964,7 +1964,7 @@ void GameView::NotifyTransformedPlaceSaveChanged(GameModel *sender) { if (sender->GetTransformedPlaceSave()) { - std::tie(placeSaveThumb, std::ignore) = SaveRenderer::Ref().Render(sender->GetTransformedPlaceSave(), true, true, sender->GetRenderer()); + placeSaveThumb = SaveRenderer::Ref().Render(sender->GetTransformedPlaceSave(), true, true, sender->GetRenderer()); selectMode = PlaceSave; selectPoint2 = mousePosition; } diff --git a/src/gui/preview/PreviewView.cpp b/src/gui/preview/PreviewView.cpp index 05506539a..5c322d05d 100644 --- a/src/gui/preview/PreviewView.cpp +++ b/src/gui/preview/PreviewView.cpp @@ -4,6 +4,7 @@ #include "client/Client.h" #include "client/SaveInfo.h" +#include "client/GameSave.h" #include "client/http/AddCommentRequest.h" #include "client/http/ReportSaveRequest.h" @@ -570,7 +571,8 @@ void PreviewView::NotifySaveChanged(PreviewModel * sender) if(save->GetGameSave()) { - std::tie(savePreview, missingElements) = SaveRenderer::Ref().Render(save->GetGameSave(), false, true); + missingElements = save->GetGameSave()->missingElements; + savePreview = SaveRenderer::Ref().Render(save->GetGameSave(), false, true); if (savePreview) savePreview->ResizeToFit(RES / 2, true); missingElementsButton->Visible = missingElements.identifiers.size() || missingElements.ids.size(); diff --git a/src/simulation/SaveRenderer.cpp b/src/simulation/SaveRenderer.cpp index 3f938d2b8..733409f76 100644 --- a/src/simulation/SaveRenderer.cpp +++ b/src/simulation/SaveRenderer.cpp @@ -18,7 +18,7 @@ SaveRenderer::SaveRenderer() SaveRenderer::~SaveRenderer() = default; -std::pair, MissingElements> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource) +std::unique_ptr SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource) { // this function usually runs on a thread different from where element info in SimulationData may be written, so we acquire a read-only lock on it auto &sd = SimulationData::CRef(); @@ -35,7 +35,7 @@ std::pair, MissingElements> SaveRenderer::Render(co sim->clear_sim(); - auto missingElementTypes = sim->Load(save, true, { 0, 0 }); + sim->Load(save, true, { 0, 0 }); ren->decorations_enable = true; ren->blackDecorations = !decorations; ren->ClearAccumulation(); @@ -59,5 +59,5 @@ std::pair, MissingElements> SaveRenderer::Render(co auto tempThumb = std::make_unique(save->blockSize * CELL); tempThumb->BlendImage(ren->Data(), 0xFF, ren->Size().OriginRect()); - return { std::move(tempThumb), missingElementTypes }; + return tempThumb; } diff --git a/src/simulation/SaveRenderer.h b/src/simulation/SaveRenderer.h index dc913e1d9..a5fffca98 100644 --- a/src/simulation/SaveRenderer.h +++ b/src/simulation/SaveRenderer.h @@ -5,7 +5,6 @@ #include #include "common/ExplicitSingleton.h" #include "common/String.h" -#include "MissingElements.h" class GameSave; class VideoBuffer; @@ -21,5 +20,5 @@ class SaveRenderer: public ExplicitSingleton public: SaveRenderer(); ~SaveRenderer(); - std::pair, MissingElements> Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr); + std::unique_ptr Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr); }; diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index a48b45527..b1040f7d9 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -22,67 +22,15 @@ static float remainder_p(float x, float y) return std::fmod(x, y) + (x>=0 ? 0 : y); } -MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec2 blockP) // block coordinates +void Simulation::Load(const GameSave *save, bool includePressure, Vec2 blockP) // block coordinates { - MissingElements missingElements; auto partP = blockP * CELL; - unsigned int pmapmask = (1<pmapbits)-1; - - int partMap[PT_NUM]; - for(int i = 0; i < PT_NUM; i++) - { - partMap[i] = i; - } auto &sd = SimulationData::CRef(); auto &elements = sd.elements; - if(save->palette.size()) - { - for(int i = 0; i < PT_NUM; i++) - { - partMap[i] = 0; - } - for(auto &pi : save->palette) - { - if (pi.second > 0 && pi.second < PT_NUM) - { - int myId = 0; - for (int i = 0; i < PT_NUM; i++) - { - if (elements[i].Enabled && elements[i].Identifier == pi.first) - { - myId = i; - } - } - if (myId) - { - partMap[pi.second] = myId; - } - else - { - missingElements.identifiers.insert(pi); - } - } - } - } - auto paletteLookup = [&partMap, &missingElements](int type) { - if (type > 0 && type < PT_NUM) - { - auto carriedType = partMap[type]; - if (!carriedType) // type is not 0 so this shouldn't be 0 either - { - missingElements.ids.insert(type); - } - type = carriedType; - } - return type; - }; RecalcFreeParticles(false); - auto &possiblyCarriesType = Particle::PossiblyCarriesType(); - auto &properties = Particle::GetProperties(); - std::map soapList; for (int n = 0; n < NPART && n < save->particlesCount; n++) { @@ -97,26 +45,12 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec int x = int(tempPart.x + 0.5f); int y = int(tempPart.y + 0.5f); - // Check various scenarios where we are unable to spawn the element, and set type to 0 to block spawning later if (!InBounds(x, y)) { continue; } - tempPart.type = paletteLookup(tempPart.type); - for (auto index : possiblyCarriesType) - { - if (elements[tempPart.type].CarriesTypeIn & (1U << index)) - { - auto *prop = reinterpret_cast(reinterpret_cast(&tempPart) + properties[index].Offset); - auto carriedType = *prop & int(pmapmask); - auto extra = *prop >> save->pmapbits; - carriedType = paletteLookup(carriedType); - *prop = PMAP(extra, carriedType); - } - } - // Ensure we can spawn this element if ((player.spwn == 1 && tempPart.type==PT_STKM) || (player2.spwn == 1 && tempPart.type==PT_STKM2)) { @@ -339,8 +273,6 @@ MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec { air->ApproximateBlockAirMaps(); } - - return missingElements; } std::unique_ptr Simulation::Save(bool includePressure, Rect partR) // particle coordinates @@ -349,8 +281,6 @@ std::unique_ptr Simulation::Save(bool includePressure, Rect partR auto blockP = blockR.TopLeft; auto newSave = std::make_unique(blockR.Size()); - auto &possiblyCarriesType = Particle::PossiblyCarriesType(); - auto &properties = Particle::GetProperties(); newSave->frameCount = frameCount; newSave->rngState = rng.state(); @@ -360,7 +290,6 @@ std::unique_ptr Simulation::Save(bool includePressure, Rect partR // Map of soap particles loaded into this save, old ID -> new ID // Now stores all particles, not just SOAP (but still only used for soap) std::map particleMap; - std::set paletteSet; auto &sd = SimulationData::CRef(); auto &elements = sd.elements; @@ -381,22 +310,10 @@ std::unique_ptr Simulation::Save(bool includePressure, Rect partR storedParts++; elementCount[tempPart.type]++; - paletteSet.insert(tempPart.type); - for (auto index : possiblyCarriesType) - { - if (elements[tempPart.type].CarriesTypeIn & (1U << index)) - { - auto *prop = reinterpret_cast(reinterpret_cast(&tempPart) + properties[index].Offset); - paletteSet.insert(TYP(*prop)); - } - } } } } - for (int ID : paletteSet) - newSave->palette.push_back(GameSave::PaletteItem(elements[ID].Identifier, ID)); - if (storedParts && elementCount[PT_SOAP]) { // fix SOAP links using particleMap, a map of old particle ID -> new particle ID diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index 21f0fc82c..c23a80d4f 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -11,7 +11,6 @@ #include "common/tpt-rand.h" #include "Element.h" #include "SimulationConfig.h" -#include "MissingElements.h" #include #include #include @@ -114,7 +113,7 @@ public: uint64_t frameCount; bool ensureDeterminism; - MissingElements Load(const GameSave *save, bool includePressure, Vec2 blockP); // block coordinates + void Load(const GameSave *save, bool includePressure, Vec2 blockP); // block coordinates std::unique_ptr Save(bool includePressure, Rect partR); // particle coordinates void SaveSimOptions(GameSave &gameSave); SimulationSample GetSample(int x, int y);