浏览代码

Merge pull request #4035 from IvanSavenko/stabilization

[1.5.2] Fixes for crashes in 1.5.1
Ivan Savenko 1 年之前
父节点
当前提交
d8f48f2c59

+ 1 - 1
client/CPlayerInterface.cpp

@@ -137,7 +137,7 @@ CPlayerInterface::CPlayerInterface(PlayerColor Player):
 	LOCPLINT = this;
 	playerID=Player;
 	human=true;
-	battleInt = nullptr;
+	battleInt.reset();
 	castleInt = nullptr;
 	makingTurn = false;
 	showingDialog = new ConditionalWait();

+ 1 - 1
client/battle/BattleInterface.cpp

@@ -332,7 +332,7 @@ void BattleInterface::battleFinished(const BattleResult& br, QueryID queryID)
 	GH.windows().pushWindow(wnd);
 
 	curInt->waitWhileDialog(); // Avoid freeze when AI end turn after battle. Check bug #1897
-	CPlayerInterface::battleInt = nullptr;
+	CPlayerInterface::battleInt.reset();
 }
 
 void BattleInterface::spellCast(const BattleSpellCast * sc)

+ 0 - 5
client/battle/BattleWindow.cpp

@@ -192,11 +192,6 @@ void BattleWindow::createTimerInfoWindows()
 	}
 }
 
-BattleWindow::~BattleWindow()
-{
-	CPlayerInterface::battleInt = nullptr;
-}
-
 std::shared_ptr<BattleConsole> BattleWindow::buildBattleConsole(const JsonNode & config) const
 {
 	auto rect = readRect(config["rect"]);

+ 0 - 1
client/battle/BattleWindow.h

@@ -82,7 +82,6 @@ class BattleWindow : public InterfaceObjectConfigurable
 
 public:
 	BattleWindow(BattleInterface & owner );
-	~BattleWindow();
 
 	/// Closes window once battle finished
 	void close();

+ 3 - 2
lib/CCreatureHandler.cpp

@@ -26,6 +26,7 @@
 #include "mapObjectConstructors/AObjectTypeHandler.h"
 #include "mapObjectConstructors/CObjectClassesHandler.h"
 #include "modding/CModHandler.h"
+#include "ExceptionsCommon.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -670,9 +671,9 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
 		// object does not have any templates - this is not usable object (e.g. pseudo-creature like Arrow Tower)
 		if (VLC->objtypeh->getHandlerFor(Obj::MONSTER, cre->getId().num)->getTemplates().empty())
 		{
-			assert(cre->special);
 			if (!cre->special)
-				logMod->error("Creature %s does not have valid map object but is not marked as special!", cre->getJsonKey());
+				throw DataLoadingException("Mod " + scope + " is corrupted! Please disable or reinstall this mod. Reason: creature " + cre->getJsonKey() + " has no adventure map animation but is not marked as special!" );
+
 			VLC->objtypeh->removeSubObject(Obj::MONSTER, cre->getId().num);
 		}
 	});

+ 12 - 1
lib/CGeneralTextHandler.h

@@ -202,7 +202,18 @@ public:
 
 		std::string key;
 		auto sz = stringsLocalizations.size();
-		h & sz;
+
+		if (h.version >= Handler::Version::REMOVE_TEXT_CONTAINER_SIZE_T)
+		{
+			int64_t size = sz;
+			h & size;
+			sz = size;
+		}
+		else
+		{
+			h & sz;
+		}
+
 		if(h.saving)
 		{
 			for(auto s : stringsLocalizations)

+ 0 - 1
lib/constants/VariantIdentifier.h

@@ -51,7 +51,6 @@ public:
 	IdentifierType as() const
 	{
 		auto * result = std::get_if<IdentifierType>(&value);
-		assert(result);
 
 		if (result)
 			return *result;

+ 15 - 7
lib/gameState/CGameStateCampaign.cpp

@@ -111,19 +111,19 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(const CampaignTravel & tr
 		//trimming artifacts
 		for(auto & hero : campaignHeroReplacements)
 		{
-			const auto & checkAndRemoveArtifact = [&](const ArtifactPosition & artifactPosition)
+			const auto & checkAndRemoveArtifact = [&](const ArtifactPosition & artifactPosition) -> bool
 			{
 				if(artifactPosition == ArtifactPosition::SPELLBOOK)
-					return; // do not handle spellbook this way
+					return false; // do not handle spellbook this way
 
 				const ArtSlotInfo *info = hero.hero->getSlot(artifactPosition);
 				if(!info)
-					return;
+					return false;
 
 				// TODO: why would there be nullptr artifacts?
 				const CArtifactInstance *art = info->artifact;
 				if(!art)
-					return;
+					return false;
 
 				bool takeable = travelOptions.artifactsKeptByHero.count(art->artType->getId());
 
@@ -132,7 +132,11 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(const CampaignTravel & tr
 
 				ArtifactLocation al(hero.hero->id, artifactPosition);
 				if(!takeable && !hero.hero->getSlot(al.slot)->locked)  //don't try removing locked artifacts -> it crashes #1719
+				{
 					hero.hero->getArt(al.slot)->removeFrom(*hero.hero, al.slot);
+					return true;
+				}
+				return false;
 			};
 
 			// process on copy - removal of artifact will invalidate container
@@ -140,9 +144,13 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(const CampaignTravel & tr
 			for(const auto & art : artifactsWorn)
 				checkAndRemoveArtifact(art.first);
 
-			// process in reverse - removal of artifact will shift all artifacts after this one
-			for(int slotNumber = hero.hero->artifactsInBackpack.size() - 1; slotNumber >= 0; slotNumber--)
-				checkAndRemoveArtifact(ArtifactPosition::BACKPACK_START + slotNumber);
+			for (int slotNumber = 0; slotNumber < hero.hero->artifactsInBackpack.size();)
+			{
+				if (checkAndRemoveArtifact(ArtifactPosition::BACKPACK_START + slotNumber))
+					continue; // artifact was removed and backpack slots were shifted -> test this slot again
+				else
+					slotNumber++; // artifact was kept for transfer -> test next slot
+			};
 		}
 	}
 

+ 3 - 1
lib/serializer/ESerializationVersion.h

@@ -44,5 +44,7 @@ enum class ESerializationVersion : int32_t
 
 	RELEASE_150 = ARTIFACT_COSTUMES, // for convenience
 
-	CURRENT = ARTIFACT_COSTUMES
+	REMOVE_TEXT_CONTAINER_SIZE_T, // Fixed serialization of size_t from text containers
+
+	CURRENT = REMOVE_TEXT_CONTAINER_SIZE_T
 };

+ 4 - 1
server/battles/BattleResultProcessor.cpp

@@ -142,6 +142,9 @@ CasualtiesAfterBattle::CasualtiesAfterBattle(const CBattleInfoCallback & battle,
 
 void CasualtiesAfterBattle::updateArmy(CGameHandler *gh)
 {
+	if (gh->getObjInstance(army->id) == nullptr)
+		throw std::runtime_error("Object " + army->getObjectName() + " is not on the map!");
+
 	for (TStackAndItsNewCount &ncount : newStackCounts)
 	{
 		if (ncount.second > 0)
@@ -544,7 +547,7 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleID & battleID, const
 	// units will be given after casualties are taken
 	const SlotID necroSlot = raisedStack.type ? finishingBattle->winnerHero->getSlotFor(raisedStack.type) : SlotID();
 
-	if (necroSlot != SlotID())
+	if (necroSlot != SlotID() && !finishingBattle->isDraw())
 	{
 		finishingBattle->winnerHero->showNecromancyDialog(raisedStack, gameHandler->getRandomGenerator());
 		gameHandler->addToSlot(StackLocation(finishingBattle->winnerHero, necroSlot), raisedStack.type, raisedStack.count);