diff --git a/binaries/data/mods/_test.mods/config/moda.cfg b/binaries/data/mods/_test.mods/config/moda.cfg new file mode 100644 index 0000000000..c8951f4c03 --- /dev/null +++ b/binaries/data/mods/_test.mods/config/moda.cfg @@ -0,0 +1,2 @@ +a = 10 +atext = "dummy" diff --git a/binaries/data/mods/_test.mods/config/modb.cfg b/binaries/data/mods/_test.mods/config/modb.cfg new file mode 100644 index 0000000000..d75c427e1b --- /dev/null +++ b/binaries/data/mods/_test.mods/config/modb.cfg @@ -0,0 +1 @@ +b = 10 diff --git a/binaries/data/mods/_test.mods/config/modreplace.cfg b/binaries/data/mods/_test.mods/config/modreplace.cfg new file mode 100644 index 0000000000..4c1cc9cf9b --- /dev/null +++ b/binaries/data/mods/_test.mods/config/modreplace.cfg @@ -0,0 +1,7 @@ +a = 8 +atext = "dummyreplaced" +b = 8 +c = 8 + +[scoped] +e = 8 diff --git a/binaries/data/mods/_test.mods/config/modscoped.cfg b/binaries/data/mods/_test.mods/config/modscoped.cfg new file mode 100644 index 0000000000..46227d1af8 --- /dev/null +++ b/binaries/data/mods/_test.mods/config/modscoped.cfg @@ -0,0 +1,2 @@ +[scoped] +e = 10 diff --git a/binaries/data/mods/_test.mods/config/start.cfg b/binaries/data/mods/_test.mods/config/start.cfg new file mode 100644 index 0000000000..4b26cb81b8 --- /dev/null +++ b/binaries/data/mods/_test.mods/config/start.cfg @@ -0,0 +1,8 @@ +a = 1 +b = 2 +c = 3 +d = 4 + +[scoped] +e = 5 +f = 6 diff --git a/source/ps/ConfigDB.cpp b/source/ps/ConfigDB.cpp index 8896f515b5..b117b922b1 100644 --- a/source/ps/ConfigDB.cpp +++ b/source/ps/ConfigDB.cpp @@ -310,6 +310,9 @@ bool CConfigDB::Reload(EConfigNamespace ns) } TConfigMap newMap; + if (ns == CFG_MOD) + newMap.swap(m_Map[CFG_MOD]); + char *filebuf = (char*)buffer.get(); char *filebufend = filebuf+buflen; diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index cfb97b42ae..6c3c9ce459 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -151,6 +151,14 @@ void MountMods(const Paths& paths, const std::vector& mods) g_VFS->Mount(L"", modPath / modName / "", baseFlags, priority); else g_VFS->Mount(L"", modUserPath / modName / "", userFlags, priority); + + // If mod have a config/.cfg, load the configuration. + VfsPath modConfigPath{fmt::format("config/{}.cfg", mods[i].c_str())}; + if (!VfsFileExists(modConfigPath)) + continue; + + g_ConfigDB.SetConfigFile(CFG_MOD, modConfigPath); + g_ConfigDB.Reload(CFG_MOD); } // Mount the user mod last. In dev copy, mount it with a low priority. Otherwise, make it writable. diff --git a/source/ps/tests/test_ConfigDB.h b/source/ps/tests/test_ConfigDB.h index d7b7c666b6..36769d0728 100644 --- a/source/ps/tests/test_ConfigDB.h +++ b/source/ps/tests/test_ConfigDB.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -32,8 +32,9 @@ public: void setUp() { g_VFS = CreateVfs(); - TS_ASSERT_OK(g_VFS->Mount(L"config", DataDir() / "_testconfig" / "")); + TS_ASSERT_OK(g_VFS->Mount(L"", DataDir() / "mods" / "_test.mods" / "", VFS_MOUNT_MUST_EXIST)); + TS_ASSERT_OK(g_VFS->Mount(L"config", DataDir() / "_testconfig" / "", 0, VFS_MAX_PRIORITY)); configDB = std::make_unique(); } @@ -85,4 +86,56 @@ public: TS_ASSERT_EQUALS(res, 3); } } + + void test_setting_mods() + { + configDB->SetConfigFile(CFG_DEFAULT, "config/start.cfg"); + configDB->Reload(CFG_DEFAULT); + TS_ASSERT_EQUALS(configDB->Get("a", 0, CFG_MOD), 1); + TS_ASSERT_EQUALS(configDB->Get("b", 0, CFG_MOD), 2); + TS_ASSERT_EQUALS(configDB->Get("c", 0, CFG_MOD), 3); + TS_ASSERT_EQUALS(configDB->Get("d", 0, CFG_MOD), 4); + TS_ASSERT_EQUALS(configDB->Get("scoped.e", 0, CFG_MOD), 5); + TS_ASSERT_EQUALS(configDB->Get("scoped.f", 0, CFG_MOD), 6); + + configDB->SetConfigFile(CFG_MOD, "config/moda.cfg"); + configDB->Reload(CFG_MOD); + TS_ASSERT_EQUALS(configDB->Get("a", 0, CFG_MOD), 10); + TS_ASSERT_EQUALS(configDB->Get("b", 0, CFG_MOD), 2); + TS_ASSERT_EQUALS(configDB->Get("c", 0, CFG_MOD), 3); + TS_ASSERT_EQUALS(configDB->Get("d", 0, CFG_MOD), 4); + TS_ASSERT_EQUALS(configDB->Get("scoped.e", 0, CFG_MOD), 5); + TS_ASSERT_EQUALS(configDB->Get("scoped.f", 0, CFG_MOD), 6); + TS_ASSERT_EQUALS(configDB->Get("atext", std::string{}, CFG_MOD), "dummy"); + + configDB->SetConfigFile(CFG_MOD, "config/modb.cfg"); + configDB->Reload(CFG_MOD); + TS_ASSERT_EQUALS(configDB->Get("a", 0, CFG_MOD), 10); + TS_ASSERT_EQUALS(configDB->Get("b", 0, CFG_MOD), 10); + TS_ASSERT_EQUALS(configDB->Get("c", 0, CFG_MOD), 3); + TS_ASSERT_EQUALS(configDB->Get("d", 0, CFG_MOD), 4); + TS_ASSERT_EQUALS(configDB->Get("scoped.e", 0, CFG_MOD), 5); + TS_ASSERT_EQUALS(configDB->Get("scoped.f", 0, CFG_MOD), 6); + TS_ASSERT_EQUALS(configDB->Get("atext", std::string{}, CFG_MOD), "dummy"); + + configDB->SetConfigFile(CFG_MOD, "config/modscoped.cfg"); + configDB->Reload(CFG_MOD); + TS_ASSERT_EQUALS(configDB->Get("a", 0, CFG_MOD), 10); + TS_ASSERT_EQUALS(configDB->Get("b", 0, CFG_MOD), 10); + TS_ASSERT_EQUALS(configDB->Get("c", 0, CFG_MOD), 3); + TS_ASSERT_EQUALS(configDB->Get("d", 0, CFG_MOD), 4); + TS_ASSERT_EQUALS(configDB->Get("scoped.e", 0, CFG_MOD), 10); + TS_ASSERT_EQUALS(configDB->Get("scoped.f", 0, CFG_MOD), 6); + TS_ASSERT_EQUALS(configDB->Get("atext", std::string{}, CFG_MOD), "dummy"); + + configDB->SetConfigFile(CFG_MOD, "config/modreplace.cfg"); + configDB->Reload(CFG_MOD); + TS_ASSERT_EQUALS(configDB->Get("a", 0, CFG_MOD), 8); + TS_ASSERT_EQUALS(configDB->Get("b", 0, CFG_MOD), 8); + TS_ASSERT_EQUALS(configDB->Get("c", 0, CFG_MOD), 8); + TS_ASSERT_EQUALS(configDB->Get("d", 0, CFG_MOD), 4); + TS_ASSERT_EQUALS(configDB->Get("scoped.e", 0, CFG_MOD), 8); + TS_ASSERT_EQUALS(configDB->Get("scoped.f", 0, CFG_MOD), 6); + TS_ASSERT_EQUALS(configDB->Get("atext", std::string{}, CFG_MOD), "dummyreplaced"); + } };