Complain about missing custom elements when opening online saves
The complaint manifests as a button in the bottom right corner of the half-size preview. Also convert the loading error popup to such a button.
This commit is contained in:
parent
374209eebe
commit
36800a76cd
@ -29,7 +29,7 @@ ThumbnailRendererTask::~ThumbnailRendererTask()
|
|||||||
|
|
||||||
bool ThumbnailRendererTask::doWork()
|
bool ThumbnailRendererTask::doWork()
|
||||||
{
|
{
|
||||||
thumbnail = std::unique_ptr<VideoBuffer>(SaveRenderer::Ref().Render(save.get(), decorations, fire));
|
std::tie(thumbnail, std::ignore) = SaveRenderer::Ref().Render(save.get(), decorations, fire);
|
||||||
if (thumbnail)
|
if (thumbnail)
|
||||||
{
|
{
|
||||||
thumbnail->ResizeToFit(size, true);
|
thumbnail->ResizeToFit(size, true);
|
||||||
|
@ -1958,7 +1958,7 @@ void GameView::NotifyTransformedPlaceSaveChanged(GameModel *sender)
|
|||||||
{
|
{
|
||||||
if (sender->GetTransformedPlaceSave())
|
if (sender->GetTransformedPlaceSave())
|
||||||
{
|
{
|
||||||
placeSaveThumb = SaveRenderer::Ref().Render(sender->GetTransformedPlaceSave(), true, true, sender->GetRenderer());
|
std::tie(placeSaveThumb, std::ignore) = SaveRenderer::Ref().Render(sender->GetTransformedPlaceSave(), true, true, sender->GetRenderer());
|
||||||
selectMode = PlaceSave;
|
selectMode = PlaceSave;
|
||||||
selectPoint2 = mousePosition;
|
selectPoint2 = mousePosition;
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,22 @@ PreviewView::PreviewView(std::unique_ptr<VideoBuffer> newSavePreview):
|
|||||||
browserOpenButton->SetActionCallback({ [this] { c->OpenInBrowser(); } });
|
browserOpenButton->SetActionCallback({ [this] { c->OpenInBrowser(); } });
|
||||||
AddComponent(browserOpenButton);
|
AddComponent(browserOpenButton);
|
||||||
|
|
||||||
|
loadErrorButton = new ui::Button({ 0, 0 }, ui::Point(148, 19), "Error loading save");
|
||||||
|
loadErrorButton->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
|
||||||
|
loadErrorButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||||
|
loadErrorButton->SetIcon(IconDelete);
|
||||||
|
loadErrorButton->SetActionCallback({ [this] { ShowLoadError(); } });
|
||||||
|
loadErrorButton->Visible = false;
|
||||||
|
AddComponent(loadErrorButton);
|
||||||
|
|
||||||
|
missingElementsButton = new ui::Button({ 0, 0 }, ui::Point(148, 19), "Missing custom elements");
|
||||||
|
missingElementsButton->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
|
||||||
|
missingElementsButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||||
|
missingElementsButton->SetIcon(IconReport);
|
||||||
|
missingElementsButton->SetActionCallback({ [this] { ShowMissingCustomElements(); } });
|
||||||
|
missingElementsButton->Visible = false;
|
||||||
|
AddComponent(missingElementsButton);
|
||||||
|
|
||||||
if(showAvatars)
|
if(showAvatars)
|
||||||
saveNameLabel = new ui::Label(ui::Point(39, (YRES/2)+4), ui::Point(100, 16), "");
|
saveNameLabel = new ui::Label(ui::Point(39, (YRES/2)+4), ui::Point(100, 16), "");
|
||||||
else
|
else
|
||||||
@ -387,9 +403,9 @@ void PreviewView::OnTick(float dt)
|
|||||||
c->Update();
|
c->Update();
|
||||||
if (doError)
|
if (doError)
|
||||||
{
|
{
|
||||||
new ErrorMessage("Error loading save", doErrorMessage, { [this]() {
|
openButton->Enabled = false;
|
||||||
c->Exit();
|
loadErrorButton->Visible = true;
|
||||||
} });
|
UpdateLoadStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reportSaveRequest && reportSaveRequest->CheckDone())
|
if (reportSaveRequest && reportSaveRequest->CheckDone())
|
||||||
@ -464,6 +480,36 @@ void PreviewView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ct
|
|||||||
openButton->DoAction();
|
openButton->DoAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PreviewView::ShowLoadError()
|
||||||
|
{
|
||||||
|
new ErrorMessage("Error loading save", doErrorMessage, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void PreviewView::ShowMissingCustomElements()
|
||||||
|
{
|
||||||
|
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";
|
||||||
|
for (auto &identifier : missingElementTypes)
|
||||||
|
{
|
||||||
|
sb << "\n - " << identifier.FromUtf8();
|
||||||
|
}
|
||||||
|
new InformationMessage("Missing custom elements", sb.Build(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PreviewView::UpdateLoadStatus()
|
||||||
|
{
|
||||||
|
auto y = YRES / 2 - 22;
|
||||||
|
auto showButton = [&y](ui::Button *button) {
|
||||||
|
if (button->Visible)
|
||||||
|
{
|
||||||
|
button->Position = { XRES / 2 - button->Size.X - 3, y };
|
||||||
|
y -= button->Size.Y + 3;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
showButton(missingElementsButton);
|
||||||
|
showButton(loadErrorButton);
|
||||||
|
}
|
||||||
|
|
||||||
void PreviewView::NotifySaveChanged(PreviewModel * sender)
|
void PreviewView::NotifySaveChanged(PreviewModel * sender)
|
||||||
{
|
{
|
||||||
auto *save = sender->GetSaveInfo();
|
auto *save = sender->GetSaveInfo();
|
||||||
@ -510,9 +556,11 @@ void PreviewView::NotifySaveChanged(PreviewModel * sender)
|
|||||||
|
|
||||||
if(save->GetGameSave())
|
if(save->GetGameSave())
|
||||||
{
|
{
|
||||||
savePreview = SaveRenderer::Ref().Render(save->GetGameSave(), false, true);
|
std::tie(savePreview, missingElementTypes) = 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();
|
||||||
|
UpdateLoadStatus();
|
||||||
}
|
}
|
||||||
else if (!sender->GetCanOpen())
|
else if (!sender->GetCanOpen())
|
||||||
openButton->Enabled = false;
|
openButton->Enabled = false;
|
||||||
|
@ -26,25 +26,28 @@ class PreviewModel;
|
|||||||
class PreviewController;
|
class PreviewController;
|
||||||
class PreviewView: public ui::Window
|
class PreviewView: public ui::Window
|
||||||
{
|
{
|
||||||
PreviewController * c;
|
PreviewController *c{};
|
||||||
|
std::vector<ByteString> missingElementTypes;
|
||||||
std::unique_ptr<VideoBuffer> savePreview;
|
std::unique_ptr<VideoBuffer> savePreview;
|
||||||
ui::Button * openButton;
|
ui::Button *openButton{};
|
||||||
ui::Button * browserOpenButton;
|
ui::Button *browserOpenButton{};
|
||||||
ui::Button * favButton;
|
ui::Button *favButton{};
|
||||||
ui::Button * reportButton;
|
ui::Button *reportButton{};
|
||||||
ui::Button * submitCommentButton;
|
ui::Button *submitCommentButton{};
|
||||||
ui::Textbox * addCommentBox;
|
ui::Button *loadErrorButton{};
|
||||||
ui::Label * commentWarningLabel;
|
ui::Button *missingElementsButton{};
|
||||||
ui::Label * saveNameLabel;
|
ui::Textbox *addCommentBox{};
|
||||||
ui::Label * authorDateLabel;
|
ui::Label *commentWarningLabel{};
|
||||||
ui::AvatarButton * avatarButton;
|
ui::Label *saveNameLabel{};
|
||||||
ui::Label * pageInfo;
|
ui::Label *authorDateLabel{};
|
||||||
ui::Label * saveDescriptionLabel;
|
ui::AvatarButton *avatarButton{};
|
||||||
ui::Label * viewsLabel;
|
ui::Label *pageInfo{};
|
||||||
ui::Label * saveIDLabel;
|
ui::Label *saveDescriptionLabel{};
|
||||||
ui::Label * saveIDLabel2;
|
ui::Label *viewsLabel{};
|
||||||
ui::CopyTextButton * saveIDButton;
|
ui::Label *saveIDLabel{};
|
||||||
ui::ScrollPanel * commentsPanel;
|
ui::Label *saveIDLabel2{};
|
||||||
|
ui::CopyTextButton *saveIDButton{};
|
||||||
|
ui::ScrollPanel *commentsPanel{};
|
||||||
std::vector<ui::Component*> commentComponents;
|
std::vector<ui::Component*> commentComponents;
|
||||||
std::vector<ui::Component*> commentTextComponents;
|
std::vector<ui::Component*> commentTextComponents;
|
||||||
int votesUp;
|
int votesUp;
|
||||||
@ -70,6 +73,9 @@ class PreviewView: public ui::Window
|
|||||||
void submitComment();
|
void submitComment();
|
||||||
bool CheckSwearing(String text);
|
bool CheckSwearing(String text);
|
||||||
void CheckComment();
|
void CheckComment();
|
||||||
|
void ShowMissingCustomElements();
|
||||||
|
void ShowLoadError();
|
||||||
|
void UpdateLoadStatus();
|
||||||
|
|
||||||
std::unique_ptr<http::AddCommentRequest> addCommentRequest;
|
std::unique_ptr<http::AddCommentRequest> addCommentRequest;
|
||||||
std::unique_ptr<http::ReportSaveRequest> reportSaveRequest;
|
std::unique_ptr<http::ReportSaveRequest> reportSaveRequest;
|
||||||
|
@ -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::unique_ptr<VideoBuffer> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource)
|
std::pair<std::unique_ptr<VideoBuffer>, std::vector<ByteString>> 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);
|
||||||
|
|
||||||
@ -32,11 +32,9 @@ std::unique_ptr<VideoBuffer> SaveRenderer::Render(const GameSave *save, bool dec
|
|||||||
ren->SetColourMode(renderModeSource->GetColourMode());
|
ren->SetColourMode(renderModeSource->GetColourMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<VideoBuffer> tempThumb;
|
|
||||||
|
|
||||||
sim->clear_sim();
|
sim->clear_sim();
|
||||||
|
|
||||||
sim->Load(save, true, { 0, 0 });
|
auto missingElementTypes = sim->Load(save, true, { 0, 0 });
|
||||||
ren->decorations_enable = true;
|
ren->decorations_enable = true;
|
||||||
ren->blackDecorations = !decorations;
|
ren->blackDecorations = !decorations;
|
||||||
ren->ClearAccumulation();
|
ren->ClearAccumulation();
|
||||||
@ -57,10 +55,10 @@ std::unique_ptr<VideoBuffer> SaveRenderer::Render(const GameSave *save, bool dec
|
|||||||
ren->RenderBegin();
|
ren->RenderBegin();
|
||||||
ren->RenderEnd();
|
ren->RenderEnd();
|
||||||
|
|
||||||
tempThumb = std::make_unique<VideoBuffer>(save->blockSize * CELL);
|
auto tempThumb = std::make_unique<VideoBuffer>(save->blockSize * CELL);
|
||||||
tempThumb->BlendImage(ren->Data(), 0xFF, ren->Size().OriginRect());
|
tempThumb->BlendImage(ren->Data(), 0xFF, ren->Size().OriginRect());
|
||||||
|
|
||||||
return tempThumb;
|
return { std::move(tempThumb), missingElementTypes };
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveRenderer::~SaveRenderer()
|
SaveRenderer::~SaveRenderer()
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
#include "common/ExplicitSingleton.h"
|
#include "common/ExplicitSingleton.h"
|
||||||
|
#include "common/String.h"
|
||||||
|
|
||||||
class GameSave;
|
class GameSave;
|
||||||
class VideoBuffer;
|
class VideoBuffer;
|
||||||
@ -15,7 +18,7 @@ class SaveRenderer: public ExplicitSingleton<SaveRenderer> {
|
|||||||
std::mutex renderMutex;
|
std::mutex renderMutex;
|
||||||
public:
|
public:
|
||||||
SaveRenderer();
|
SaveRenderer();
|
||||||
std::unique_ptr<VideoBuffer> Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr);
|
std::pair<std::unique_ptr<VideoBuffer>, std::vector<ByteString>> 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();
|
||||||
};
|
};
|
||||||
|
@ -19,8 +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];
|
||||||
|
|
||||||
void Simulation::Load(const GameSave *save, bool includePressure, Vec2<int> blockP) // block coordinates
|
std::vector<ByteString> Simulation::Load(const GameSave *save, bool includePressure, Vec2<int> blockP) // block coordinates
|
||||||
{
|
{
|
||||||
|
std::vector<ByteString> missingElementTypes;
|
||||||
auto partP = blockP * CELL;
|
auto partP = blockP * CELL;
|
||||||
unsigned int pmapmask = (1<<save->pmapbits)-1;
|
unsigned int pmapmask = (1<<save->pmapbits)-1;
|
||||||
|
|
||||||
@ -44,8 +45,15 @@ void Simulation::Load(const GameSave *save, bool includePressure, Vec2<int> bloc
|
|||||||
// if this is a custom element, set the ID to the ID we found when comparing identifiers in the palette map
|
// if this is a custom element, set the ID to the ID we found when comparing identifiers in the palette map
|
||||||
// set type to 0 if we couldn't find an element with that identifier present when loading,
|
// set type to 0 if we couldn't find an element with that identifier present when loading,
|
||||||
// unless this is a default element, in which case keep the current ID, because otherwise when an element is renamed it wouldn't show up anymore in older saves
|
// unless this is a default element, in which case keep the current ID, because otherwise when an element is renamed it wouldn't show up anymore in older saves
|
||||||
if (myId != 0 || !pi.first.BeginsWith("DEFAULT_PT_"))
|
if (myId != 0)
|
||||||
|
{
|
||||||
partMap[pi.second] = myId;
|
partMap[pi.second] = myId;
|
||||||
|
}
|
||||||
|
else if (!pi.first.BeginsWith("DEFAULT_PT_"))
|
||||||
|
{
|
||||||
|
missingElementTypes.push_back(pi.first);
|
||||||
|
partMap[pi.second] = myId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -318,6 +326,8 @@ void Simulation::Load(const GameSave *save, bool includePressure, Vec2<int> bloc
|
|||||||
{
|
{
|
||||||
air->ApproximateBlockAirMaps();
|
air->ApproximateBlockAirMaps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return missingElementTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
@ -121,7 +121,7 @@ public:
|
|||||||
uint64_t frameCount;
|
uint64_t frameCount;
|
||||||
bool ensureDeterminism;
|
bool ensureDeterminism;
|
||||||
|
|
||||||
void Load(const GameSave *save, bool includePressure, Vec2<int> blockP); // block coordinates
|
std::vector<ByteString> 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);
|
||||||
|
Reference in New Issue
Block a user