1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-08 22:26:51 +02:00

Merge pull request #5363 from IvanSavenko/crashfixes

[1.6.5] Crashfixes for reported crashes from 1.6.4
This commit is contained in:
Ivan Savenko
2025-02-02 13:52:51 +02:00
committed by GitHub
11 changed files with 62 additions and 15 deletions

View File

@@ -62,6 +62,7 @@
#include "windows/CTutorialWindow.h"
#include "windows/GUIClasses.h"
#include "windows/InfoWindows.h"
#include "windows/settings/SettingsMainWindow.h"
#include "../CCallback.h"
@@ -187,6 +188,7 @@ void CPlayerInterface::closeAllDialogs()
while(true)
{
auto adventureWindow = GH.windows().topWindow<AdventureMapInterface>();
auto settingsWindow = GH.windows().topWindow<SettingsMainWindow>();
auto infoWindow = GH.windows().topWindow<CInfoWindow>();
auto topWindow = GH.windows().topWindow<WindowBase>();
@@ -196,10 +198,16 @@ void CPlayerInterface::closeAllDialogs()
if(infoWindow && infoWindow->ID != QueryID::NONE)
break;
if (topWindow == nullptr)
throw std::runtime_error("Invalid or non-existing top window! Total windows: " + std::to_string(GH.windows().count()));
if (settingsWindow)
{
settingsWindow->close();
continue;
}
topWindow->close();
if (topWindow)
topWindow->close();
else
GH.windows().popWindows(1); // does not inherits from WindowBase, e.g. settings dialog
}
}

View File

@@ -683,18 +683,24 @@ BattleHex::EDir BattleFieldController::selectAttackDirection(const BattleHex & m
// | - - | - - | - - | - o o | o o - | - - | - - | o o
for (size_t i : { 1, 2, 3})
attackAvailability[i] = occupiableHexes.contains(neighbours[i]) && occupiableHexes.contains(neighbours[i].cloneInDirection(BattleHex::RIGHT, false));
{
BattleHex target = neighbours[i].cloneInDirection(BattleHex::RIGHT, false);
attackAvailability[i] = neighbours[i].isValid() && occupiableHexes.contains(neighbours[i]) && target.isValid() && occupiableHexes.contains(target);
}
for (size_t i : { 4, 5, 0})
attackAvailability[i] = occupiableHexes.contains(neighbours[i]) && occupiableHexes.contains(neighbours[i].cloneInDirection(BattleHex::LEFT, false));
{
BattleHex target = neighbours[i].cloneInDirection(BattleHex::LEFT, false);
attackAvailability[i] = neighbours[i].isValid() && occupiableHexes.contains(neighbours[i]) && target.isValid() && occupiableHexes.contains(target);
}
attackAvailability[6] = occupiableHexes.contains(neighbours[0]) && occupiableHexes.contains(neighbours[1]);
attackAvailability[7] = occupiableHexes.contains(neighbours[3]) && occupiableHexes.contains(neighbours[4]);
attackAvailability[6] = neighbours[0].isValid() && neighbours[1].isValid() && occupiableHexes.contains(neighbours[0]) && occupiableHexes.contains(neighbours[1]);
attackAvailability[7] = neighbours[3].isValid() && neighbours[4].isValid() && occupiableHexes.contains(neighbours[3]) && occupiableHexes.contains(neighbours[4]);
}
else
{
for (size_t i = 0; i < 6; ++i)
attackAvailability[i] = occupiableHexes.contains(neighbours[i]);
attackAvailability[i] = neighbours[i].isValid() && occupiableHexes.contains(neighbours[i]);
attackAvailability[6] = false;
attackAvailability[7] = false;
@@ -739,7 +745,7 @@ BattleHex::EDir BattleFieldController::selectAttackDirection(const BattleHex & m
BattleHex BattleFieldController::fromWhichHexAttack(const BattleHex & attackTarget)
{
BattleHex::EDir direction = selectAttackDirection(getHoveredHex());
BattleHex::EDir direction = selectAttackDirection(attackTarget);
const CStack * attacker = owner.stacksController->getActiveStack();

View File

@@ -686,7 +686,12 @@ void StackInfoBasicPanel::initializeData(const CStack * stack)
if (hasGraphics)
{
//FIXME: support permanent duration
int duration = stack->getFirstBonus(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)))->turnsRemain;
auto spellBonuses = stack->getBonuses(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)));
if (spellBonuses->empty())
throw std::runtime_error("Failed to find effects for spell " + effect.toSpell()->getJsonKey());
int duration = spellBonuses->front()->duration;
icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));
if(settings["general"]["enableUiEnhancements"].Bool())

View File

@@ -116,6 +116,7 @@ void GlobalLobbyLoginWindow::onLogin()
onConnectionSuccess();
buttonClose->block(true);
buttonLogin->block(true);
}
void GlobalLobbyLoginWindow::onConnectionSuccess()
@@ -142,4 +143,5 @@ void GlobalLobbyLoginWindow::onConnectionFailed(const std::string & reason)
labelStatus->setText(formatter.toString());
buttonClose->block(false);
buttonLogin->block(false);
}

View File

@@ -134,6 +134,7 @@ CGuiHandler::~CGuiHandler()
// enforce deletion order on shutdown
// all UI elements including adventure map must be destroyed before Gui Handler
// proper solution would be removal of adventureInt global
windowHandlerInstance->clear();
adventureInt.reset();
}

View File

@@ -345,7 +345,7 @@ void WindowBase::close()
if(!GH.windows().isTopWindow(this))
{
auto topWindow = GH.windows().topWindow<IShowActivatable>().get();
throw std::runtime_error(std::string("Only top interface can be closed! Top window is ") + typeid(*this).name() + " but attempted to close " + typeid(*topWindow).name());
throw std::runtime_error(std::string("Only top interface can be closed! Top window is ") + typeid(*topWindow).name() + " but attempted to close " + typeid(*this).name());
}
GH.windows().popWindows(1);
}

View File

@@ -68,6 +68,9 @@ void OptionsTab::recreate()
entries.clear();
humanPlayers = 0;
for (auto heroOverview : GH.windows().findWindows<CHeroOverview>())
heroOverview->close();
for (auto selectionWindow : GH.windows().findWindows<SelectionWindow>())
{
selectionWindow->reopen();

View File

@@ -120,6 +120,9 @@ const Rect & SDLImageOptimizer::getResultDimensions() const
void SDLImageScaler::scaleSurface(Point targetDimensions, EScalingAlgorithm algorithm)
{
if (!intermediate)
return; // may happen on scaling of empty images
if(!targetDimensions.x || !targetDimensions.y)
throw std::runtime_error("invalid scaling dimensions!");
@@ -144,6 +147,9 @@ void SDLImageScaler::scaleSurface(Point targetDimensions, EScalingAlgorithm algo
void SDLImageScaler::scaleSurfaceIntegerFactor(int factor, EScalingAlgorithm algorithm)
{
if (!intermediate)
return; // may happen on scaling of empty images
if(factor == 0)
throw std::runtime_error("invalid scaling factor!");

View File

@@ -234,7 +234,11 @@ CStackWindow::ActiveSpellsSection::ActiveSpellsSection(CStackWindow * owner, int
spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds."
boost::replace_first(spellText, "%s", spell->getNameTranslated());
//FIXME: support permanent duration
int duration = battleStack->getFirstBonus(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)))->turnsRemain;
auto spellBonuses = battleStack->getBonuses(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)));
if (spellBonuses->empty())
throw std::runtime_error("Failed to find effects for spell " + effect.toSpell()->getJsonKey());
int duration = spellBonuses->front()->duration;
boost::replace_first(spellText, "%d", std::to_string(duration));
spellIcons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));

View File

@@ -29,7 +29,6 @@ private:
std::shared_ptr<CIntObject> createTab(size_t index);
void openTab(size_t index);
void close(); //TODO: copypaste of WindowBase::close(), consider changing Windowbase to IWindowbase with default close() implementation and changing WindowBase inheritance to CIntObject + IWindowBase
void loadGameButtonCallback();
void saveGameButtonCallback();
@@ -40,6 +39,7 @@ private:
public:
SettingsMainWindow(BattleInterface * parentBattleInterface = nullptr);
void close(); //TODO: copypaste of WindowBase::close(), consider changing Windowbase to IWindowbase with default close() implementation and changing WindowBase inheritance to CIntObject + IWindowBase
void showAll(Canvas & to) override;
void onScreenResize() override;
};

View File

@@ -161,12 +161,24 @@ uint32_t TextOperations::getUnicodeCodepoint(char data, const std::string & enco
std::string TextOperations::toUnicode(const std::string &text, const std::string &encoding)
{
return boost::locale::conv::to_utf<char>(text, encoding);
try {
return boost::locale::conv::to_utf<char>(text, encoding);
}
catch (const boost::locale::conv::conversion_error &)
{
throw std::runtime_error("Failed to convert text '" + text + "' from encoding " + encoding );
}
}
std::string TextOperations::fromUnicode(const std::string &text, const std::string &encoding)
{
return boost::locale::conv::from_utf<char>(text, encoding);
try {
return boost::locale::conv::from_utf<char>(text, encoding);
}
catch (const boost::locale::conv::conversion_error &)
{
throw std::runtime_error("Failed to convert text '" + text + "' to encoding " + encoding );
}
}
void TextOperations::trimRightUnicode(std::string & text, const size_t amount)