Skip to content

Commit 5f92580

Browse files
committed
Merge pull request OpenXcom#1009 from myk002/badmods
disable mods that have bad rulesets
2 parents 5e75a95 + 54abc0e commit 5f92580

4 files changed

Lines changed: 44 additions & 21 deletions

File tree

src/Engine/FileMap.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ namespace OpenXcom
2828
namespace FileMap
2929
{
3030

31-
static std::vector< std::vector<std::string> > _rulesets;
32-
static std::map<std::string, std::string> _resources;
31+
static std::vector<std::pair<std::string, std::vector<std::string> > > _rulesets;
32+
static std::map<std::string, std::string> _resources;
3333
static std::map< std::string, std::set<std::string> > _vdirs;
34-
static std::set<std::string> _emptySet;
34+
static std::set<std::string> _emptySet;
3535

3636
static std::string _canonicalize(const std::string &in)
3737
{
@@ -91,7 +91,7 @@ std::set<std::string> _filterFiles(const T &files, const std::string &ext)
9191
std::set<std::string> filterFiles(const std::vector<std::string> &files, const std::string &ext) { return _filterFiles(files, ext); }
9292
std::set<std::string> filterFiles(const std::set<std::string> &files, const std::string &ext) { return _filterFiles(files, ext); }
9393

94-
const std::vector< std::vector<std::string> > &getRulesets()
94+
const std::vector<std::pair<std::string, std::vector<std::string> > > &getRulesets()
9595
{
9696
return _rulesets;
9797
}
@@ -107,20 +107,21 @@ static std::string _combinePath(const std::string &prefixPath, const std::string
107107
return ret;
108108
}
109109

110-
static void _mapFiles(const std::string &basePath, const std::string &relPath, bool ignoreRulesets)
110+
static void _mapFiles(const std::string &modId, const std::string &basePath,
111+
const std::string &relPath, bool ignoreRulesets)
111112
{
112113
std::string fullDir = basePath + (relPath.length() ? "/" + relPath : "");
113114
std::vector<std::string> files = CrossPlatform::getFolderContents(fullDir);
114115
std::set<std::string> rulesetFiles = _filterFiles(files, "rul");
115116

116117
if (!ignoreRulesets && rulesetFiles.size())
117118
{
118-
_rulesets.insert(_rulesets.begin(), std::vector<std::string>());
119+
_rulesets.insert(_rulesets.begin(), std::pair<std::string, std::vector<std::string> >(modId, std::vector<std::string>()));
119120
for (std::set<std::string>::iterator i = rulesetFiles.begin(); i != rulesetFiles.end(); ++i)
120121
{
121122
std::string fullpath = fullDir + "/" + *i;
122123
Log(LOG_DEBUG) << " recording ruleset: " << fullpath;
123-
_rulesets.front().push_back(fullpath);
124+
_rulesets.front().second.push_back(fullpath);
124125
}
125126
}
126127

@@ -143,7 +144,7 @@ static void _mapFiles(const std::string &basePath, const std::string &relPath, b
143144
// record ruleset files in that subdirectory, otherwise ignore them
144145
bool ignoreRulesetsRecurse =
145146
!rulesetFiles.empty() || !relPath.empty() || _canonicalize(*i) != "ruleset";
146-
_mapFiles(basePath, _combinePath(relPath, *i), ignoreRulesetsRecurse);
147+
_mapFiles(modId, basePath, _combinePath(relPath, *i), ignoreRulesetsRecurse);
147148
continue;
148149
}
149150

@@ -179,10 +180,10 @@ void clear()
179180
_vdirs.clear();
180181
}
181182

182-
void load(const std::string &path, bool ignoreRulesets)
183+
void load(const std::string &modId, const std::string &path, bool ignoreRulesets)
183184
{
184185
Log(LOG_INFO) << " mapping resources in: " << path;
185-
_mapFiles(path, "", ignoreRulesets);
186+
_mapFiles(modId, path, "", ignoreRulesets);
186187
}
187188

188189
}

src/Engine/FileMap.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,18 @@ namespace FileMap
4646
std::set<std::string> filterFiles(const std::vector<std::string> &files, const std::string &ext);
4747
std::set<std::string> filterFiles(const std::set<std::string> &files, const std::string &ext);
4848

49-
/// Returns the ruleset files found, grouped by mod, while mapping resources. The highest-prioirity mod
49+
/// Returns the ruleset files found, grouped by mod, while mapping resources. The highest-priority mod
5050
/// will be last in the returned vector.
51-
const std::vector< std::vector<std::string> > &getRulesets();
51+
const std::vector<std::pair<std::string, std::vector<std::string> > > &getRulesets();
5252

5353
/// clears FileMap state
5454
void clear();
5555

5656
/// Scans a directory tree rooted at the specified filesystem path. Any files it encounters that have already
5757
/// been mapped will be ignored. Therefore, load files from mods with the highest priority first. If
58-
/// ignoreRulesets is false (the default), it will add any rulesets it finds to the front of the vector
58+
/// ignoreRulesets is false, it will add any rulesets it finds to the front of the vector
5959
/// returned by getRulesets().
60-
void load(const std::string &path, bool ignoreRulesets = false);
60+
void load(const std::string &modId, const std::string &path, bool ignoreRulesets);
6161
}
6262

6363
}

src/Engine/Game.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -534,16 +534,36 @@ void Game::loadRulesets()
534534
Ruleset::resetGlobalStatics();
535535
delete _rules;
536536
_rules = new Ruleset();
537-
const std::vector< std::vector<std::string> > &rulesets(FileMap::getRulesets());
537+
const std::vector<std::pair<std::string, std::vector<std::string> > > &rulesets(FileMap::getRulesets());
538538
for (int i = 0; rulesets.size() > i; ++i)
539539
{
540540
try
541541
{
542-
_rules->loadModRulesets(rulesets[i], i);
542+
_rules->loadModRulesets(rulesets[i].second, i);
543543
}
544544
catch (YAML::Exception &e)
545545
{
546-
throw Exception("failed to load ruleset: " + std::string(e.what()));
546+
const std::string &modId = rulesets[i].first;
547+
Log(LOG_WARNING) << "disabling mod with invalid ruleset: " << modId;
548+
std::vector<std::pair<std::string, bool> >::iterator it =
549+
std::find(Options::mods.begin(), Options::mods.end(),
550+
std::pair<std::string, bool>(modId, true));
551+
if (it == Options::mods.end())
552+
{
553+
Log(LOG_ERROR) << "cannot find broken mod in mods list: " << modId;
554+
Log(LOG_ERROR) << "clearing mods list";
555+
Options::mods.clear();
556+
}
557+
else
558+
{
559+
it->second = false;
560+
}
561+
Options::save();
562+
563+
throw Exception("failed to load ruleset from mod '" +
564+
Options::getModInfos().at(modId).getName() +
565+
"' (" + std::string(e.what()) +
566+
"); disabling mod for next startup");
547567
}
548568
}
549569
_rules->sortLists();

src/Engine/Options.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,9 @@ bool init(int argc, char *argv[])
575575
}
576576
else
577577
{
578-
if (inactiveMaster.empty())
578+
// prefer activating standard masters over a possibly broken
579+
// third party master
580+
if (inactiveMaster.empty() || j->first == "xcom1" || j->first == "xcom2")
579581
{
580582
inactiveMaster = j->first;
581583
}
@@ -662,11 +664,11 @@ static void _loadMod(const ModInfo &modInfo, std::set<std::string> circDepCheck)
662664
return;
663665
}
664666

665-
FileMap::load(modInfo.getPath());
667+
FileMap::load(modInfo.getId(), modInfo.getPath(), false);
666668
for (std::vector<std::string>::const_iterator i = modInfo.getExternalResourceDirs().begin(); i != modInfo.getExternalResourceDirs().end(); ++i)
667669
{
668670
// always ignore ruleset files in external resource dirs
669-
FileMap::load(CrossPlatform::searchDataFolder(*i), true);
671+
FileMap::load(modInfo.getId(), CrossPlatform::searchDataFolder(*i), true);
670672
}
671673

672674
// if this is a master but it has a master of its own, allow it to
@@ -705,7 +707,7 @@ void mapResources()
705707
_loadMod(modInfo, circDepCheck);
706708
}
707709
// pick up stuff in common
708-
FileMap::load(CrossPlatform::searchDataFolder("common"), true);
710+
FileMap::load("", CrossPlatform::searchDataFolder("common"), true);
709711
}
710712

711713
/**

0 commit comments

Comments
 (0)