From 89839fdc74cbf19f7f8e0f957fede6d2305fee97 Mon Sep 17 00:00:00 2001 From: Oliver Hamlet Date: Thu, 5 Oct 2017 20:58:42 +0100 Subject: [PATCH] Add load order state management (Re)load the current state when loading plugins, and add an API function for managing load order state so that clients have full control over when libloadorder reloads its cached state. --- include/loot/game_interface.h | 12 +++++++++++- src/api/game/game.cpp | 5 +++++ src/api/game/game.h | 2 ++ src/api/game/load_order_handler.cpp | 8 ++++++++ src/api/game/load_order_handler.h | 2 ++ src/tests/api/interface/game_interface_test.h | 4 ++++ src/tests/api/internals/game/game_test.h | 6 ++++++ .../internals/game/load_order_handler_test.h | 17 +++++++++++++++++ .../internals/metadata/condition_grammar_test.h | 2 ++ src/tests/api/internals/plugin/plugin_test.h | 2 ++ 10 files changed, 59 insertions(+), 1 deletion(-) 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();