Skip to content

Commit

Permalink
Merge pull request ddnet#9014 from Robyt3/Editor-External-Mapres-Erro…
Browse files Browse the repository at this point in the history
…r-Handling

Fix editor crashes when images/sounds cannot be loaded, fix editor crashes with external RGB images
  • Loading branch information
def- authored Sep 22, 2024
2 parents 3d8bb6f + 94a4012 commit ec768b2
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 20 deletions.
24 changes: 11 additions & 13 deletions src/game/editor/editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4358,13 +4358,10 @@ bool CEditor::ReplaceImage(const char *pFileName, int StorageType, bool CheckDup
str_copy(pImg->m_aName, aBuf);
pImg->m_External = IsVanillaImage(pImg->m_aName);

if(!pImg->m_External)
ConvertToRgba(*pImg);
if(g_Config.m_ClEditorDilate == 1)
{
ConvertToRgba(*pImg);
if(g_Config.m_ClEditorDilate == 1)
{
DilateImage(*pImg);
}
DilateImage(*pImg);
}

pImg->m_AutoMapper.Load(pImg->m_aName);
Expand Down Expand Up @@ -4425,13 +4422,10 @@ bool CEditor::AddImage(const char *pFileName, int StorageType, void *pUser)
pImg->m_pData = ImgInfo.m_pData;
pImg->m_External = IsVanillaImage(aBuf);

if(!pImg->m_External)
ConvertToRgba(*pImg);
if(g_Config.m_ClEditorDilate == 1)
{
ConvertToRgba(*pImg);
if(g_Config.m_ClEditorDilate == 1)
{
DilateImage(*pImg);
}
DilateImage(*pImg);
}

int TextureLoadFlag = pEditor->Graphics()->Uses2DTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
Expand Down Expand Up @@ -8726,7 +8720,11 @@ bool CEditor::Save(const char *pFilename)
if(std::any_of(std::begin(m_WriterFinishJobs), std::end(m_WriterFinishJobs), [pFilename](const std::shared_ptr<CDataFileWriterFinishJob> &Job) { return str_comp(pFilename, Job->GetRealFileName()) == 0; }))
return false;

return m_Map.Save(pFilename);
const auto &&ErrorHandler = [this](const char *pErrorMessage) {
ShowFileDialogError("%s", pErrorMessage);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "editor/save", pErrorMessage);
};
return m_Map.Save(pFilename, ErrorHandler);
}

bool CEditor::HandleMapDrop(const char *pFileName, int StorageType)
Expand Down
3 changes: 2 additions & 1 deletion src/game/editor/editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ class CEditorMap
void CreateDefault(IGraphics::CTextureHandle EntitiesTexture);

// io
bool Save(const char *pFilename);
bool Save(const char *pFilename, const std::function<void(const char *pErrorMessage)> &ErrorHandler);
bool PerformPreSaveSanityChecks(const std::function<void(const char *pErrorMessage)> &ErrorHandler);
bool Load(const char *pFilename, int StorageType, const std::function<void(const char *pErrorMessage)> &ErrorHandler);
void PerformSanityChecks(const std::function<void(const char *pErrorMessage)> &ErrorHandler);

Expand Down
58 changes: 52 additions & 6 deletions src/game/editor/mapitems/map_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,25 @@ struct CSoundSource_DEPRECATED
int m_SoundEnvOffset;
};

bool CEditorMap::Save(const char *pFileName)
bool CEditorMap::Save(const char *pFileName, const std::function<void(const char *pErrorMessage)> &ErrorHandler)
{
char aFileNameTmp[IO_MAX_PATH_LENGTH];
IStorage::FormatTmpPath(aFileNameTmp, sizeof(aFileNameTmp), pFileName);

char aBuf[IO_MAX_PATH_LENGTH + 64];
str_format(aBuf, sizeof(aBuf), "saving to '%s'...", aFileNameTmp);
m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "editor", aBuf);

if(!PerformPreSaveSanityChecks(ErrorHandler))
{
return false;
}

CDataFileWriter Writer;
if(!Writer.Open(m_pEditor->Storage(), aFileNameTmp))
{
str_format(aBuf, sizeof(aBuf), "failed to open file '%s'...", aFileNameTmp);
m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "editor", aBuf);
str_format(aBuf, sizeof(aBuf), "Error: Failed to open file '%s' for writing.", aFileNameTmp);
ErrorHandler(aBuf);
return false;
}

Expand Down Expand Up @@ -402,11 +408,42 @@ bool CEditorMap::Save(const char *pFileName)
return true;
}

bool CEditorMap::PerformPreSaveSanityChecks(const std::function<void(const char *pErrorMessage)> &ErrorHandler)
{
bool Success = true;
char aErrorMessage[256];

for(const std::shared_ptr<CEditorImage> &pImage : m_vpImages)
{
if(!pImage->m_External && pImage->m_pData == nullptr)
{
str_format(aErrorMessage, sizeof(aErrorMessage), "Error: Saving is not possible because the image '%s' could not be loaded. Remove or replace this image.", pImage->m_aName);
ErrorHandler(aErrorMessage);
Success = false;
}
}

for(const std::shared_ptr<CEditorSound> &pSound : m_vpSounds)
{
if(pSound->m_pData == nullptr)
{
str_format(aErrorMessage, sizeof(aErrorMessage), "Error: Saving is not possible because the sound '%s' could not be loaded. Remove or replace this sound.", pSound->m_aName);
ErrorHandler(aErrorMessage);
Success = false;
}
}

return Success;
}

bool CEditorMap::Load(const char *pFileName, int StorageType, const std::function<void(const char *pErrorMessage)> &ErrorHandler)
{
CDataFileReader DataFile;
if(!DataFile.Open(m_pEditor->Storage(), pFileName, StorageType))
{
ErrorHandler("Error: Failed to open map file. See local console for details.");
return false;
}

// check version
const CMapItemVersion *pItemVersion = static_cast<CMapItemVersion *>(DataFile.FindItem(MAPITEMTYPE_VERSION, 0));
Expand Down Expand Up @@ -513,11 +550,15 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio
ConvertToRgba(*pImg);

int TextureLoadFlag = m_pEditor->Graphics()->Uses2DTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
if(ImgInfo.m_Width % 16 != 0 || ImgInfo.m_Height % 16 != 0)
if(pImg->m_Width % 16 != 0 || pImg->m_Height % 16 != 0)
TextureLoadFlag = 0;
pImg->m_Texture = m_pEditor->Graphics()->LoadTextureRaw(ImgInfo, TextureLoadFlag, aBuf);
ImgInfo.m_pData = nullptr;
pImg->m_External = 1;
pImg->m_Texture = m_pEditor->Graphics()->LoadTextureRaw(*pImg, TextureLoadFlag, aBuf);
}
else
{
str_format(aBuf, sizeof(aBuf), "Error: Failed to load external image '%s'.", pImg->m_aName);
ErrorHandler(aBuf);
}
}
else
Expand Down Expand Up @@ -579,6 +620,11 @@ bool CEditorMap::Load(const char *pFileName, int StorageType, const std::functio
{
pSound->m_SoundId = m_pEditor->Sound()->LoadOpusFromMem(pSound->m_pData, pSound->m_DataSize, true);
}
else
{
str_format(aBuf, sizeof(aBuf), "Error: Failed to load external sound '%s'.", pSound->m_aName);
ErrorHandler(aBuf);
}
}
else
{
Expand Down
15 changes: 15 additions & 0 deletions src/game/editor/popups.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,11 @@ CUi::EPopupMenuFunctionResult CEditor::PopupImage(void *pContext, CUIRect View,
{
if(pEditor->DoButton_MenuItem(&s_ExternalButton, "Embed", 0, &Slot, 0, "Embeds the image into the map file."))
{
if(pImg->m_pData == nullptr)
{
pEditor->ShowFileDialogError("Embedding is not possible because the image could not be loaded.");
return CUi::POPUP_KEEP_OPEN;
}
pImg->m_External = 0;
return CUi::POPUP_CLOSE_CURRENT;
}
Expand Down Expand Up @@ -1730,6 +1735,11 @@ CUi::EPopupMenuFunctionResult CEditor::PopupImage(void *pContext, CUIRect View,
View.HSplitTop(RowHeight, &Slot, &View);
if(pEditor->DoButton_MenuItem(&s_ExportButton, "Export", 0, &Slot, 0, "Export the image"))
{
if(pImg->m_pData == nullptr)
{
pEditor->ShowFileDialogError("Exporting is not possible because the image could not be loaded.");
return CUi::POPUP_KEEP_OPEN;
}
pEditor->InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_IMG, "Save image", "Save", "mapres", false, CallbackSaveImage, pEditor);
pEditor->m_FileDialogFileNameInput.Set(pImg->m_aName);
return CUi::POPUP_CLOSE_CURRENT;
Expand Down Expand Up @@ -1825,6 +1835,11 @@ CUi::EPopupMenuFunctionResult CEditor::PopupSound(void *pContext, CUIRect View,
View.HSplitTop(RowHeight, &Slot, &View);
if(pEditor->DoButton_MenuItem(&s_ExportButton, "Export", 0, &Slot, 0, "Export sound"))
{
if(pSound->m_pData == nullptr)
{
pEditor->ShowFileDialogError("Exporting is not possible because the sound could not be loaded.");
return CUi::POPUP_KEEP_OPEN;
}
pEditor->InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_SOUND, "Save sound", "Save", "mapres", false, CallbackSaveSound, pEditor);
pEditor->m_FileDialogFileNameInput.Set(pSound->m_aName);
return CUi::POPUP_CLOSE_CURRENT;
Expand Down

0 comments on commit ec768b2

Please sign in to comment.