diff --git a/include/loot/game_interface.h b/include/loot/game_interface.h index b8ebcdc9..7989fa97 100644 --- a/include/loot/game_interface.h +++ b/include/loot/game_interface.h @@ -63,7 +63,7 @@ public: /** * @brief Parses plugins and loads their data. * @details Any previously-loaded plugin data is discarded when this function - * is called. + * is called. This function also loads the current load order state. * @param plugins * The filenames of the plugins to load. * @param loadHeadersOnly @@ -127,6 +127,16 @@ public: * @{ */ + /** + * + * @brief Load the current load order state, discarding any previously held + * state. + * @details This function should be called whenever the load order or active + * state of plugins "on disk" changes, so that the cached state is + * updated to reflect the changes. + */ + virtual void LoadCurrentLoadOrderState() = 0; + /** * @brief Check if a plugin is active. * @param plugin diff --git a/src/api/game/game.cpp b/src/api/game/game.cpp index 82131de3..da9e473a 100644 --- a/src/api/game/game.cpp +++ b/src/api/game/game.cpp @@ -140,6 +140,7 @@ void Game::LoadPlugins(const std::vector& plugins, bool loadHeaders // Clear the existing plugin cache. cache_->ClearCachedPlugins(); + loadOrderHandler_->LoadCurrentState(); // Load the plugins. BOOST_LOG_TRIVIAL(trace) << "Starting plugin loading."; @@ -191,6 +192,10 @@ std::vector Game::SortPlugins(const std::vector& plugi return sorter.Sort(*this); } +void Game::LoadCurrentLoadOrderState() { + loadOrderHandler_->LoadCurrentState(); +} + bool Game::IsPluginActive(const std::string& plugin) const { try { return std::static_pointer_cast(GetPlugin(plugin))->IsActive(); diff --git a/src/api/game/game.h b/src/api/game/game.h index 61b6ab04..43657ba6 100644 --- a/src/api/game/game.h +++ b/src/api/game/game.h @@ -66,6 +66,8 @@ public: std::vector SortPlugins(const std::vector& plugins); + void LoadCurrentLoadOrderState(); + bool IsPluginActive(const std::string& pluginName) const; std::vector GetLoadOrder() const; diff --git a/src/api/game/load_order_handler.cpp b/src/api/game/load_order_handler.cpp index 8b5dbbfd..8c3d90b1 100644 --- a/src/api/game/load_order_handler.cpp +++ b/src/api/game/load_order_handler.cpp @@ -77,6 +77,14 @@ void LoadOrderHandler::Init(const GameType& gameType, HandleError("create a game handle", ret); } +void LoadOrderHandler::LoadCurrentState() { + BOOST_LOG_TRIVIAL(debug) << "Loading the current load order state."; + + unsigned int ret = lo_load_current_state(gh_); + + HandleError("load the current load order state", ret); +} + bool LoadOrderHandler::IsPluginActive(const std::string& pluginName) const { BOOST_LOG_TRIVIAL(debug) << "Checking if plugin \"" << pluginName << "\" is active."; diff --git a/src/api/game/load_order_handler.h b/src/api/game/load_order_handler.h index 49ead84c..bc98bc35 100644 --- a/src/api/game/load_order_handler.h +++ b/src/api/game/load_order_handler.h @@ -44,6 +44,8 @@ public: const boost::filesystem::path& gamePath, const boost::filesystem::path& gameLocalAppData = ""); + void LoadCurrentState(); + std::vector GetLoadOrder() const; bool IsPluginActive(const std::string& pluginName) const; diff --git a/src/tests/api/interface/game_interface_test.h b/src/tests/api/interface/game_interface_test.h index fb271b55..23a6c18a 100644 --- a/src/tests/api/interface/game_interface_test.h +++ b/src/tests/api/interface/game_interface_test.h @@ -158,18 +158,22 @@ TEST_P(GameInterfaceTest, sortPluginsShouldSucceedIfPassedValidArguments) { } TEST_P(GameInterfaceTest, isPluginActiveShouldReturnFalseIfTheGivenPluginIsNotActive) { + handle_->LoadCurrentLoadOrderState(); EXPECT_TRUE(handle_->IsPluginActive(blankEsm)); } TEST_P(GameInterfaceTest, isPluginActiveShouldReturnTrueIfTheGivenPluginIsActive) { + handle_->LoadCurrentLoadOrderState(); EXPECT_FALSE(handle_->IsPluginActive(blankEsp)); } TEST_P(GameInterfaceTest, getLoadOrderShouldReturnTheCurrentLoadOrder) { + handle_->LoadCurrentLoadOrderState(); ASSERT_EQ(getLoadOrder(), handle_->GetLoadOrder()); } TEST_P(GameInterfaceTest, setLoadOrderShouldSetTheLoadOrder) { + handle_->LoadCurrentLoadOrderState(); std::vector loadOrder({ masterFile, blankEsm, diff --git a/src/tests/api/internals/game/game_test.h b/src/tests/api/internals/game/game_test.h index 631c639d..997445e2 100644 --- a/src/tests/api/internals/game/game_test.h +++ b/src/tests/api/internals/game/game_test.h @@ -145,18 +145,21 @@ TEST_P(GameTest, loadPluginsWithHeadersOnlyFalseShouldFullyLoadAllInstalledPlugi TEST_P(GameTest, shouldShowBlankEsmAsActiveIfItHasNotBeenLoaded) { Game game = Game(GetParam(), dataPath.parent_path(), localPath); + game.LoadCurrentLoadOrderState(); EXPECT_TRUE(game.IsPluginActive(blankEsm)); } TEST_P(GameTest, shouldShowBlankEspAsInactiveIfItHasNotBeenLoaded) { Game game = Game(GetParam(), dataPath.parent_path(), localPath); + game.LoadCurrentLoadOrderState(); EXPECT_FALSE(game.IsPluginActive(blankEsp)); } TEST_P(GameTest, shouldShowBlankEsmAsActiveIfItsHeaderHasBeenLoaded) { Game game = Game(GetParam(), dataPath.parent_path(), localPath); + game.LoadCurrentLoadOrderState(); ASSERT_NO_THROW(loadInstalledPlugins(game, true)); @@ -165,6 +168,7 @@ TEST_P(GameTest, shouldShowBlankEsmAsActiveIfItsHeaderHasBeenLoaded) { TEST_P(GameTest, shouldShowBlankEspAsInactiveIfItsHeaderHasBeenLoaded) { Game game = Game(GetParam(), dataPath.parent_path(), localPath); + game.LoadCurrentLoadOrderState(); ASSERT_NO_THROW(loadInstalledPlugins(game, true)); @@ -173,6 +177,7 @@ TEST_P(GameTest, shouldShowBlankEspAsInactiveIfItsHeaderHasBeenLoaded) { TEST_P(GameTest, shouldShowBlankEsmAsActiveIfItHasBeenFullyLoaded) { Game game = Game(GetParam(), dataPath.parent_path(), localPath); + game.LoadCurrentLoadOrderState(); ASSERT_NO_THROW(loadInstalledPlugins(game, false)); @@ -181,6 +186,7 @@ TEST_P(GameTest, shouldShowBlankEsmAsActiveIfItHasBeenFullyLoaded) { TEST_P(GameTest, shouldShowBlankEspAsInactiveIfItHasBeenFullyLoaded) { Game game = Game(GetParam(), dataPath.parent_path(), localPath); + game.LoadCurrentLoadOrderState(); ASSERT_NO_THROW(loadInstalledPlugins(game, false)); diff --git a/src/tests/api/internals/game/load_order_handler_test.h b/src/tests/api/internals/game/load_order_handler_test.h index 8b6b48dd..6ade2fd2 100644 --- a/src/tests/api/internals/game/load_order_handler_test.h +++ b/src/tests/api/internals/game/load_order_handler_test.h @@ -92,8 +92,17 @@ TEST_P(LoadOrderHandlerTest, isPluginActiveShouldThrowIfTheHandlerHasNotBeenInit EXPECT_THROW(loadOrderHandler_.IsPluginActive(masterFile), std::system_error); } +TEST_P(LoadOrderHandlerTest, isPluginActiveShouldReturnFalseIfLoadOrderStateHasNotBeenLoaded) { + initialiseHandler(); + + EXPECT_FALSE(loadOrderHandler_.IsPluginActive(masterFile)); + EXPECT_FALSE(loadOrderHandler_.IsPluginActive(blankEsm)); + EXPECT_FALSE(loadOrderHandler_.IsPluginActive(blankEsp)); +} + TEST_P(LoadOrderHandlerTest, isPluginActiveShouldReturnCorrectPluginStatesAfterInitialisation) { initialiseHandler(); + loadOrderHandler_.LoadCurrentState(); EXPECT_TRUE(loadOrderHandler_.IsPluginActive(masterFile)); EXPECT_TRUE(loadOrderHandler_.IsPluginActive(blankEsm)); @@ -104,8 +113,15 @@ TEST_P(LoadOrderHandlerTest, getLoadOrderShouldThrowIfTheHandlerHasNotBeenInitia EXPECT_THROW(loadOrderHandler_.GetLoadOrder(), std::system_error); } +TEST_P(LoadOrderHandlerTest, getLoadOrderShouldReturnAnEmptyVectorIfStateHasNotBeenLoaded) { + initialiseHandler(); + + EXPECT_TRUE(loadOrderHandler_.GetLoadOrder().empty()); +} + TEST_P(LoadOrderHandlerTest, getLoadOrderShouldReturnTheCurrentLoadOrder) { initialiseHandler(); + loadOrderHandler_.LoadCurrentState(); ASSERT_EQ(getLoadOrder(), loadOrderHandler_.GetLoadOrder()); } @@ -116,6 +132,7 @@ TEST_P(LoadOrderHandlerTest, setLoadOrderShouldThrowIfTheHandlerHasNotBeenInitia TEST_P(LoadOrderHandlerTest, setLoadOrderShouldSetTheLoadOrder) { initialiseHandler(); + loadOrderHandler_.LoadCurrentState(); EXPECT_NO_THROW(loadOrderHandler_.SetLoadOrder(loadOrderToSet_)); diff --git a/src/tests/api/internals/metadata/condition_grammar_test.h b/src/tests/api/internals/metadata/condition_grammar_test.h index 6fb07847..c75c2ef6 100644 --- a/src/tests/api/internals/metadata/condition_grammar_test.h +++ b/src/tests/api/internals/metadata/condition_grammar_test.h @@ -45,6 +45,8 @@ protected: inline void SetUp() { CommonGameTestFixture::SetUp(); + game_.LoadCurrentLoadOrderState(); + // Write out an empty resource file. ASSERT_NO_THROW(boost::filesystem::create_directories(resourcePath.parent_path())); boost::filesystem::ofstream out(resourcePath); diff --git a/src/tests/api/internals/plugin/plugin_test.h b/src/tests/api/internals/plugin/plugin_test.h index cfb25998..1379ade0 100644 --- a/src/tests/api/internals/plugin/plugin_test.h +++ b/src/tests/api/internals/plugin/plugin_test.h @@ -44,6 +44,8 @@ protected: void SetUp() { CommonGameTestFixture::SetUp(); + game_.LoadCurrentLoadOrderState(); + // Write out an empty file. boost::filesystem::ofstream out(dataPath / emptyFile); out.close();