List element IDs that don't have an identifier associated in a save

36800a76cd lists missing element identifiers but neglects to handle IDs that don't even have one associated.
This commit is contained in:
Tamás Bálint Misius 2023-12-05 10:19:13 +01:00
parent 66136c8866
commit 9f8449357f
No known key found for this signature in database
GPG Key ID: 5B472A12F6ECA9F2
7 changed files with 54 additions and 18 deletions

View File

@ -488,10 +488,24 @@ void PreviewView::ShowLoadError()
void PreviewView::ShowMissingCustomElements() void PreviewView::ShowMissingCustomElements()
{ {
StringBuilder sb; StringBuilder sb;
sb << "This save uses custom elements that are not currently available. Make sure that you use the mod and/or have all the scripts the save requires to fully load. A list of identifiers of missing custom elements follows, which may help you determine how to fix this problem.\n"; sb << "This save uses custom elements that are not currently available. Make sure that you use the mod and/or have all the scripts the save requires to fully load.";
for (auto &identifier : missingElementTypes) auto remainingIds = missingElements.ids;
if (missingElements.identifiers.size())
{ {
sb << "\n - " << identifier.FromUtf8(); sb << "\n\nA list of identifiers of missing custom elements follows, which may help you determine how to fix this problem.\n";
for (auto &[ identifier, id ] : missingElements.identifiers)
{
sb << "\n - " << identifier.FromUtf8();
remainingIds.erase(id); // remove ids from the missing id set that are already covered by unknown identifiers
}
}
if (remainingIds.size())
{
sb << "\n\nA list of element IDs of missing custom elements with no identifier associated follows. This can only be fixed by the author of the save.\n";
for (auto id : remainingIds)
{
sb << "\n - " << id;
}
} }
new InformationMessage("Missing custom elements", sb.Build(), true); new InformationMessage("Missing custom elements", sb.Build(), true);
} }
@ -556,10 +570,10 @@ void PreviewView::NotifySaveChanged(PreviewModel * sender)
if(save->GetGameSave()) if(save->GetGameSave())
{ {
std::tie(savePreview, missingElementTypes) = SaveRenderer::Ref().Render(save->GetGameSave(), false, true); std::tie(savePreview, missingElements) = SaveRenderer::Ref().Render(save->GetGameSave(), false, true);
if (savePreview) if (savePreview)
savePreview->ResizeToFit(RES / 2, true); savePreview->ResizeToFit(RES / 2, true);
missingElementsButton->Visible = missingElementTypes.size(); missingElementsButton->Visible = missingElements.identifiers.size() || missingElements.ids.size();
UpdateLoadStatus(); UpdateLoadStatus();
} }
else if (!sender->GetCanOpen()) else if (!sender->GetCanOpen())

View File

@ -4,6 +4,7 @@
#include <vector> #include <vector>
#include "common/String.h" #include "common/String.h"
#include "gui/interface/Window.h" #include "gui/interface/Window.h"
#include "simulation/MissingElements.h"
namespace http namespace http
{ {
@ -27,7 +28,7 @@ class PreviewController;
class PreviewView: public ui::Window class PreviewView: public ui::Window
{ {
PreviewController *c{}; PreviewController *c{};
std::vector<ByteString> missingElementTypes; MissingElements missingElements;
std::unique_ptr<VideoBuffer> savePreview; std::unique_ptr<VideoBuffer> savePreview;
ui::Button *openButton{}; ui::Button *openButton{};
ui::Button *browserOpenButton{}; ui::Button *browserOpenButton{};

View File

@ -0,0 +1,10 @@
#pragma once
#include <set>
#include <map>
#include "common/String.h"
struct MissingElements
{
std::map<ByteString, int> identifiers;
std::set<int> ids;
};

View File

@ -20,7 +20,7 @@ void SaveRenderer::Flush(int begin, int end)
std::fill(ren->graphicscache + begin, ren->graphicscache + end, gcache_item()); std::fill(ren->graphicscache + begin, ren->graphicscache + end, gcache_item());
} }
std::pair<std::unique_ptr<VideoBuffer>, std::vector<ByteString>> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource) std::pair<std::unique_ptr<VideoBuffer>, MissingElements> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource)
{ {
std::lock_guard<std::mutex> gx(renderMutex); std::lock_guard<std::mutex> gx(renderMutex);

View File

@ -5,6 +5,7 @@
#include <vector> #include <vector>
#include "common/ExplicitSingleton.h" #include "common/ExplicitSingleton.h"
#include "common/String.h" #include "common/String.h"
#include "MissingElements.h"
class GameSave; class GameSave;
class VideoBuffer; class VideoBuffer;
@ -18,7 +19,7 @@ class SaveRenderer: public ExplicitSingleton<SaveRenderer> {
std::mutex renderMutex; std::mutex renderMutex;
public: public:
SaveRenderer(); SaveRenderer();
std::pair<std::unique_ptr<VideoBuffer>, std::vector<ByteString>> Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr); std::pair<std::unique_ptr<VideoBuffer>, MissingElements> Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr);
void Flush(int begin, int end); void Flush(int begin, int end);
virtual ~SaveRenderer(); virtual ~SaveRenderer();
}; };

View File

@ -19,9 +19,9 @@ extern int Element_LOLZ_lolz[XRES/9][YRES/9];
extern int Element_LOVE_RuleTable[9][9]; extern int Element_LOVE_RuleTable[9][9];
extern int Element_LOVE_love[XRES/9][YRES/9]; extern int Element_LOVE_love[XRES/9][YRES/9];
std::vector<ByteString> Simulation::Load(const GameSave *save, bool includePressure, Vec2<int> blockP) // block coordinates MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec2<int> blockP) // block coordinates
{ {
std::vector<ByteString> missingElementTypes; MissingElements missingElements;
auto partP = blockP * CELL; auto partP = blockP * CELL;
unsigned int pmapmask = (1<<save->pmapbits)-1; unsigned int pmapmask = (1<<save->pmapbits)-1;
@ -54,11 +54,23 @@ std::vector<ByteString> Simulation::Load(const GameSave *save, bool includePress
} }
else else
{ {
missingElementTypes.push_back(pi.first); 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); RecalcFreeParticles(false);
@ -86,7 +98,7 @@ std::vector<ByteString> Simulation::Load(const GameSave *save, bool includePress
continue; continue;
} }
tempPart.type = partMap[tempPart.type]; tempPart.type = paletteLookup(tempPart.type);
for (auto index : possiblyCarriesType) for (auto index : possiblyCarriesType)
{ {
if (elements[tempPart.type].CarriesTypeIn & (1U << index)) if (elements[tempPart.type].CarriesTypeIn & (1U << index))
@ -94,10 +106,7 @@ std::vector<ByteString> Simulation::Load(const GameSave *save, bool includePress
auto *prop = reinterpret_cast<int *>(reinterpret_cast<char *>(&tempPart) + properties[index].Offset); auto *prop = reinterpret_cast<int *>(reinterpret_cast<char *>(&tempPart) + properties[index].Offset);
auto carriedType = *prop & int(pmapmask); auto carriedType = *prop & int(pmapmask);
auto extra = *prop >> save->pmapbits; auto extra = *prop >> save->pmapbits;
if (carriedType >= 0 && carriedType < PT_NUM) carriedType = paletteLookup(carriedType);
{
carriedType = partMap[carriedType];
}
*prop = PMAP(extra, carriedType); *prop = PMAP(extra, carriedType);
} }
} }
@ -329,7 +338,7 @@ std::vector<ByteString> Simulation::Load(const GameSave *save, bool includePress
air->ApproximateBlockAirMaps(); air->ApproximateBlockAirMaps();
} }
return missingElementTypes; return missingElements;
} }
std::unique_ptr<GameSave> Simulation::Save(bool includePressure, Rect<int> partR) // particle coordinates std::unique_ptr<GameSave> Simulation::Save(bool includePressure, Rect<int> partR) // particle coordinates

View File

@ -11,6 +11,7 @@
#include "common/tpt-rand.h" #include "common/tpt-rand.h"
#include "Element.h" #include "Element.h"
#include "SimulationConfig.h" #include "SimulationConfig.h"
#include "MissingElements.h"
#include <cstring> #include <cstring>
#include <cstddef> #include <cstddef>
#include <vector> #include <vector>
@ -121,7 +122,7 @@ public:
uint64_t frameCount; uint64_t frameCount;
bool ensureDeterminism; bool ensureDeterminism;
std::vector<ByteString> Load(const GameSave *save, bool includePressure, Vec2<int> blockP); // block coordinates MissingElements Load(const GameSave *save, bool includePressure, Vec2<int> blockP); // block coordinates
std::unique_ptr<GameSave> Save(bool includePressure, Rect<int> partR); // particle coordinates std::unique_ptr<GameSave> Save(bool includePressure, Rect<int> partR); // particle coordinates
void SaveSimOptions(GameSave &gameSave); void SaveSimOptions(GameSave &gameSave);
SimulationSample GetSample(int x, int y); SimulationSample GetSample(int x, int y);