Merge pull request #9014 from Robyt3/Editor-External-Mapres-Error-Handling

Fix editor crashes when images/sounds cannot be loaded, fix editor crashes with external RGB images
This commit is contained in:
Dennis Felsing 2024-09-22 12:17:13 +00:00 committed by GitHub
commit ec768b2269
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 80 additions and 20 deletions

View file

@ -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);
@ -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;
@ -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)

View file

@ -200,7 +200,8 @@ public:
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);

View file

@ -34,7 +34,7 @@ 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);
@ -42,11 +42,17 @@ bool CEditorMap::Save(const char *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;
}
@ -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));
@ -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
@ -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
{

View file

@ -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;
}
@ -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;
@ -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;