Skip to content

Commit 8164264

Browse files
committed
feat(xrGame): Make configs/mp optional in single-player
Single-player should not hard-require multiplayer configuration under `gamedata/configs/mp/`. Previously, `CMapListHelper` always loaded `$game_config$/mp/map_list.ltx` and asserted that maps/weathers were present. For SP-only installs or story mods that remove MP configs, that made startup/save-load fail and also forced expensive archive scanning. Changes: - Treat `mp/map_list.ltx` (and its `[weather]` section) as optional: if missing, log and keep MP map/weather lists empty. - Remove `R_ASSERT`s and avoid dereferencing null map list entries; return an empty "unknown" map list when queried. Notes: - The LTX/INI loader remains strict and generic (missing `#include` targets still fail). - `mp_ranks.ltx` is still expected for NPC weapon ranking; it is not MP-only.
1 parent 83ac6bb commit 8164264

File tree

1 file changed

+36
-7
lines changed

1 file changed

+36
-7
lines changed

src/xrGame/UIGameCustom.cpp

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,18 @@ void CMapListHelper::Load()
431431
{
432432
string_path cfgFileName;
433433
FS.update_path(cfgFileName, "$game_config$", "mp" DELIMITER "map_list.ltx");
434+
if (!FS.exist(cfgFileName))
435+
{
436+
Log("~ Can't open MP map list:", cfgFileName);
437+
return;
438+
}
439+
434440
CInifile maplistCfg(cfgFileName);
441+
if (!maplistCfg.section_exist("weather"))
442+
{
443+
Log("~ MP map list has no [weather] section:", cfgFileName);
444+
return;
445+
}
435446
// read weathers set
436447
CInifile::Sect weatherCfg = maplistCfg.r_section("weather");
437448
m_weathers.reserve(weatherCfg.Data.size());
@@ -468,17 +479,27 @@ void CMapListHelper::Load()
468479
FS.unload_archive(arch);
469480
}
470481
levelsPath->_set_root(prevRoot.c_str());
471-
// XXX nitrocaster: is that really fatal?
472-
R_ASSERT2(m_storage.size() > 0, "unable to fill map list");
473-
R_ASSERT2(m_weathers.size() > 0, "unable to fill weathers list");
482+
if (m_storage.empty())
483+
Log("! Unable to fill MP map list (no maps discovered).");
484+
if (m_weathers.empty())
485+
Log("! Unable to fill MP weather list (no weather presets discovered).");
474486
}
475487

476488
const SGameTypeMaps& CMapListHelper::GetMapListFor(const shared_str& gameType)
477489
{
478490
if (m_storage.size() == 0)
479491
Load();
480492
// XXX nitrocaster: always use enum for game type representation
481-
return *GetMapListInt(gameType);
493+
if (auto* maps = GetMapListInt(gameType))
494+
return *maps;
495+
496+
static SGameTypeMaps empty{};
497+
if (!empty.m_game_type_name.size())
498+
{
499+
empty.m_game_type_name = "unknown";
500+
empty.m_game_type_id = eGameIDNoGame;
501+
}
502+
return empty;
482503
}
483504

484505
SGameTypeMaps* CMapListHelper::GetMapListInt(const shared_str& gameType)
@@ -496,8 +517,16 @@ const SGameTypeMaps& CMapListHelper::GetMapListFor(const EGameIDs gameId)
496517
if (m_storage.size() == 0)
497518
{
498519
Load();
499-
// XXX nitrocaster: is that really fatal?
500-
R_ASSERT2(m_storage.size() > 0, "unable to fill map list");
520+
}
521+
if (m_storage.empty())
522+
{
523+
static SGameTypeMaps empty{};
524+
if (!empty.m_game_type_name.size())
525+
{
526+
empty.m_game_type_name = "unknown";
527+
empty.m_game_type_id = eGameIDNoGame;
528+
}
529+
return empty;
501530
}
502531
for (SGameTypeMaps& maps : m_storage)
503532
{
@@ -509,7 +538,7 @@ const SGameTypeMaps& CMapListHelper::GetMapListFor(const EGameIDs gameId)
509538

510539
const xr_vector<MPWeatherDesc>& CMapListHelper::GetGameWeathers()
511540
{
512-
if (m_weathers.size() == 0)
541+
if (m_weathers.empty())
513542
Load();
514543
return m_weathers;
515544
}

0 commit comments

Comments
 (0)