mirror of
https://github.com/vcmi/vcmi.git
synced 2025-04-07 07:10:04 +02:00
Show proper error message if player attempts to load save with missing
identifiers instead of silent crash to main menu
This commit is contained in:
parent
54480c6209
commit
cc71651ee4
@ -75,6 +75,7 @@
|
||||
"vcmi.server.confirmReconnect" : "Do you want to reconnect to the last session?",
|
||||
"vcmi.server.errors.modNoDependency" : "Failed to load mod {'%s'}!\n It depends on mod {'%s'} which is not active!\n",
|
||||
"vcmi.server.errors.modConflict" : "Failed to load mod {'%s'}!\n Conflicts with active mod {'%s'}!\n",
|
||||
"vcmi.server.errors.unknownEntity" : "Failed to load save! Unknown entity '%s' found in saved game! Save may not be compatible with currently installed version of mods!",
|
||||
|
||||
"vcmi.settingsMainWindow.generalTab.hover" : "General",
|
||||
"vcmi.settingsMainWindow.generalTab.help" : "Switches to General Options tab, which contains settings related to general game client behavior.",
|
||||
|
@ -75,6 +75,7 @@
|
||||
"vcmi.server.confirmReconnect" : "Підключитися до минулої сесії?",
|
||||
"vcmi.server.errors.modNoDependency" : "Не вдалося увімкнути мод {'%s'}!\n Модифікація потребує мод {'%s'} який зараз не активний!\n",
|
||||
"vcmi.server.errors.modConflict" : "Не вдалося увімкнути мод {'%s'}!\n Конфліктує з активним модом {'%s'}!\n",
|
||||
"vcmi.server.errors.unknownEntity" : "Не вдалося завантажити гру! У збереженій грі знайдено невідомий об'єкт '%s'! Це збереження може бути несумісним зі встановленою версією модифікацій!",
|
||||
|
||||
"vcmi.settingsMainWindow.generalTab.hover" : "Загальні",
|
||||
"vcmi.settingsMainWindow.generalTab.help" : "Перемикає на вкладку загальних параметрів, яка містить налаштування, пов'язані із загальною поведінкою ігрового клієнта",
|
||||
|
@ -122,12 +122,21 @@ namespace GameConstants
|
||||
#endif
|
||||
}
|
||||
|
||||
si32 HeroClassID::decode(const std::string & identifier)
|
||||
int32_t IdentifierBase::resolveIdentifier(const std::string & entityType, const std::string identifier)
|
||||
{
|
||||
if (identifier.empty())
|
||||
return -1;
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeMap(), "heroClass", identifier);
|
||||
return rawId.value();
|
||||
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), entityType, identifier);
|
||||
|
||||
if (rawId)
|
||||
return rawId.value();
|
||||
throw IdentifierResolutionException(identifier);
|
||||
}
|
||||
|
||||
si32 HeroClassID::decode(const std::string & identifier)
|
||||
{
|
||||
return resolveIdentifier("heroClass", identifier);
|
||||
}
|
||||
|
||||
std::string HeroClassID::encode(const si32 index)
|
||||
@ -171,10 +180,7 @@ std::string MapObjectID::encode(int32_t index)
|
||||
|
||||
si32 MapObjectID::decode(const std::string & identifier)
|
||||
{
|
||||
if (identifier.empty())
|
||||
return -1;
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "object", identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier("object", identifier);
|
||||
}
|
||||
|
||||
std::string MapObjectSubID::encode(MapObjectID primaryID, int32_t index)
|
||||
@ -193,17 +199,13 @@ std::string MapObjectSubID::encode(MapObjectID primaryID, int32_t index)
|
||||
|
||||
si32 MapObjectSubID::decode(MapObjectID primaryID, const std::string & identifier)
|
||||
{
|
||||
if (identifier.empty())
|
||||
return -1;
|
||||
|
||||
if(primaryID == Obj::PRISON || primaryID == Obj::HERO)
|
||||
return HeroTypeID::decode(identifier);
|
||||
|
||||
if (primaryID == Obj::SPELL_SCROLL)
|
||||
return SpellID::decode(identifier);
|
||||
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), VLC->objtypeh->getJsonKey(primaryID), identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier(VLC->objtypeh->getJsonKey(primaryID), identifier);
|
||||
}
|
||||
|
||||
std::string BoatId::encode(int32_t index)
|
||||
@ -215,20 +217,14 @@ std::string BoatId::encode(int32_t index)
|
||||
|
||||
si32 BoatId::decode(const std::string & identifier)
|
||||
{
|
||||
if (identifier.empty())
|
||||
return -1;
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "core:boat", identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier("core:boat", identifier);
|
||||
}
|
||||
|
||||
si32 HeroTypeID::decode(const std::string & identifier)
|
||||
{
|
||||
if (identifier.empty())
|
||||
return -1;
|
||||
if (identifier == "random")
|
||||
return -2;
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeMap(), "hero", identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier("hero", identifier);
|
||||
}
|
||||
|
||||
std::string HeroTypeID::encode(const si32 index)
|
||||
@ -257,10 +253,7 @@ const Artifact * ArtifactIDBase::toEntity(const Services * services) const
|
||||
|
||||
si32 ArtifactID::decode(const std::string & identifier)
|
||||
{
|
||||
if (identifier.empty())
|
||||
return -1;
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "artifact", identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier("artifact", identifier);
|
||||
}
|
||||
|
||||
std::string ArtifactID::encode(const si32 index)
|
||||
@ -277,10 +270,7 @@ std::string ArtifactID::entityType()
|
||||
|
||||
si32 SecondarySkill::decode(const std::string& identifier)
|
||||
{
|
||||
if (identifier.empty())
|
||||
return -1;
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "secondarySkill", identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier("secondarySkill", identifier);
|
||||
}
|
||||
|
||||
std::string SecondarySkill::encode(const si32 index)
|
||||
@ -317,10 +307,7 @@ const Creature * CreatureIDBase::toEntity(const CreatureService * creatures) con
|
||||
|
||||
si32 CreatureID::decode(const std::string & identifier)
|
||||
{
|
||||
if (identifier.empty())
|
||||
return -1;
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "creature", identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier("creature", identifier);
|
||||
}
|
||||
|
||||
std::string CreatureID::encode(const si32 index)
|
||||
@ -367,10 +354,7 @@ const HeroType * HeroTypeID::toEntity(const Services * services) const
|
||||
|
||||
si32 SpellID::decode(const std::string & identifier)
|
||||
{
|
||||
if (identifier.empty())
|
||||
return -1;
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "spell", identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier("spell", identifier);
|
||||
}
|
||||
|
||||
std::string SpellID::encode(const si32 index)
|
||||
@ -382,10 +366,7 @@ std::string SpellID::encode(const si32 index)
|
||||
|
||||
si32 BattleField::decode(const std::string & identifier)
|
||||
{
|
||||
if (identifier.empty())
|
||||
return -1;
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), "spell", identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier("battlefield", identifier);
|
||||
}
|
||||
|
||||
std::string BattleField::encode(const si32 index)
|
||||
@ -439,7 +420,7 @@ std::string PlayerColor::entityType()
|
||||
|
||||
si32 PrimarySkill::decode(const std::string& identifier)
|
||||
{
|
||||
return *VLC->identifiers()->getIdentifier(ModScope::scopeGame(), entityType(), identifier);
|
||||
return resolveIdentifier(entityType(), identifier);
|
||||
}
|
||||
|
||||
std::string PrimarySkill::encode(const si32 index)
|
||||
@ -454,11 +435,7 @@ std::string PrimarySkill::entityType()
|
||||
|
||||
si32 FactionID::decode(const std::string & identifier)
|
||||
{
|
||||
if (identifier.empty())
|
||||
return -1;
|
||||
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), entityType(), identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier(entityType(), identifier);
|
||||
}
|
||||
|
||||
std::string FactionID::encode(const si32 index)
|
||||
@ -480,13 +457,10 @@ const Faction * FactionID::toEntity(const Services * service) const
|
||||
|
||||
si32 TerrainId::decode(const std::string & identifier)
|
||||
{
|
||||
if (identifier.empty())
|
||||
return static_cast<si32>(TerrainId::NONE);
|
||||
if (identifier == "native")
|
||||
return TerrainId::NATIVE_TERRAIN;
|
||||
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), entityType(), identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier(entityType(), identifier);
|
||||
}
|
||||
|
||||
std::string TerrainId::encode(const si32 index)
|
||||
@ -508,8 +482,7 @@ si32 RoadId::decode(const std::string & identifier)
|
||||
if (identifier.empty())
|
||||
return RoadId::NO_ROAD.getNum();
|
||||
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), entityType(), identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier(entityType(), identifier);
|
||||
}
|
||||
|
||||
std::string RoadId::encode(const si32 index)
|
||||
@ -529,8 +502,7 @@ si32 RiverId::decode(const std::string & identifier)
|
||||
if (identifier.empty())
|
||||
return RiverId::NO_RIVER.getNum();
|
||||
|
||||
auto rawId = VLC->identifiers()->getIdentifier(ModScope::scopeGame(), entityType(), identifier);
|
||||
return rawId.value();
|
||||
return resolveIdentifier(entityType(), identifier);
|
||||
}
|
||||
|
||||
std::string RiverId::encode(const si32 index)
|
||||
@ -574,7 +546,7 @@ const ObstacleInfo * Obstacle::getInfo() const
|
||||
|
||||
si32 SpellSchool::decode(const std::string & identifier)
|
||||
{
|
||||
return *VLC->identifiers()->getIdentifier(ModScope::scopeGame(), entityType(), identifier);
|
||||
return resolveIdentifier(entityType(), identifier);
|
||||
}
|
||||
|
||||
std::string SpellSchool::encode(const si32 index)
|
||||
@ -592,7 +564,7 @@ std::string SpellSchool::entityType()
|
||||
|
||||
si32 GameResID::decode(const std::string & identifier)
|
||||
{
|
||||
return *VLC->identifiers()->getIdentifier(ModScope::scopeGame(), entityType(), identifier);
|
||||
return resolveIdentifier(entityType(), identifier);
|
||||
}
|
||||
|
||||
std::string GameResID::encode(const si32 index)
|
||||
|
@ -9,6 +9,19 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class IdentifierResolutionException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
const std::string identifierName;
|
||||
|
||||
IdentifierResolutionException(const std::string & identifierName )
|
||||
: std::runtime_error("Failed to resolve identifier " + identifierName)
|
||||
, identifierName(identifierName)
|
||||
{}
|
||||
};
|
||||
|
||||
class IdentifierBase
|
||||
{
|
||||
protected:
|
||||
@ -21,6 +34,11 @@ protected:
|
||||
{}
|
||||
|
||||
~IdentifierBase() = default;
|
||||
|
||||
/// Attempts to resolve identifier using provided entity type
|
||||
/// Returns resolved numeric identifier
|
||||
/// Throws IdentifierResolutionException on failure
|
||||
static int32_t resolveIdentifier(const std::string & entityType, const std::string identifier);
|
||||
public:
|
||||
int32_t num;
|
||||
|
||||
@ -233,4 +251,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -1802,9 +1802,20 @@ bool CGameHandler::load(const std::string & filename)
|
||||
lobby->announceMessage(errorMsg);
|
||||
return false;
|
||||
}
|
||||
catch(const IdentifierResolutionException & e)
|
||||
{
|
||||
logGlobal->error("Failed to load game: %s", e.what());
|
||||
MetaString errorMsg;
|
||||
errorMsg.appendTextID("vcmi.server.errors.unknownEntity");
|
||||
errorMsg.replaceRawString(e.identifierName);
|
||||
lobby->announceMessage(errorMsg.toString());//FIXME: should be localized on client side
|
||||
return false;
|
||||
}
|
||||
|
||||
catch(const std::exception & e)
|
||||
{
|
||||
logGlobal->error("Failed to load game: %s", e.what());
|
||||
lobby->announceMessage(std::string("Failed to load game: ") + e.what());
|
||||
return false;
|
||||
}
|
||||
gs->preInit(VLC);
|
||||
|
Loading…
x
Reference in New Issue
Block a user