From a22e2ffd1c0a9e9f04c929fe8c971fe4faf8f5f7 Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Sat, 28 Sep 2013 14:01:37 +0100 Subject: [PATCH] Issue #69. Added "Redate Plugins" file menu option for Skyrim. --- src/backend/game.cpp | 57 +++++++++++++++++++++++++++++++++++++ src/backend/game.h | 1 + src/gui/ids.h | 9 +++--- src/gui/main.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++-- src/gui/main.h | 2 ++ 5 files changed, 131 insertions(+), 6 deletions(-) diff --git a/src/backend/game.cpp b/src/backend/game.cpp index dcf4860e..81efa54f 100644 --- a/src/backend/game.cpp +++ b/src/backend/game.cpp @@ -272,6 +272,7 @@ namespace boss { throw error(error::liblo_error, err); } + activePlugins.clear(); for (size_t i=0; i < pluginArrSize; ++i) { activePlugins.insert(boost::to_lower_copy(string(pluginArr[i]))); } @@ -283,6 +284,62 @@ namespace boss { return activePlugins.find(boost::to_lower_copy(plugin)) != activePlugins.end(); } + void Game::GetLoadOrder(std::list& loadOrder) const { + BOOST_LOG_TRIVIAL(trace) << "Setting load order for game: " << _name; + + lo_game_handle gh; + char ** pluginArr; + size_t pluginArrSize; + + int ret; + if (Id() == g_game_tes4) + ret = lo_create_handle(&gh, LIBLO_GAME_TES4, gamePath.string().c_str()); + else if (Id() == g_game_tes5) + ret = lo_create_handle(&gh, LIBLO_GAME_TES5, gamePath.string().c_str()); + else if (Id() == g_game_fo3) + ret = lo_create_handle(&gh, LIBLO_GAME_FO3, gamePath.string().c_str()); + else if (Id() == g_game_fonv) + ret = lo_create_handle(&gh, LIBLO_GAME_FNV, gamePath.string().c_str()); + + if (ret != LIBLO_OK && ret != LIBLO_WARN_LO_MISMATCH) { + const char * e; + lo_get_error_message(&e); + BOOST_LOG_TRIVIAL(error) << "libloadorder failed to create a game handle. Details: " << e; + string err = lc::translate("libloadorder failed to create a game handle. Details:").str() + " " + e; + lo_cleanup(); + throw error(error::liblo_error, err); + } + + ret = lo_set_game_master(gh, _masterFile.c_str()); + + if (ret != LIBLO_OK) { + const char * e; + lo_get_error_message(&e); + lo_destroy_handle(gh); + BOOST_LOG_TRIVIAL(error) << "libloadorder failed to initialise game master file support. Details: " << e; + string err = lc::translate("libloadorder failed to initialise game master file support. Details:").str() + " " + e; + lo_cleanup(); + throw error(error::liblo_error, err); + } + + if (lo_get_load_order(gh, &pluginArr, &pluginArrSize) != LIBLO_OK) { + const char * e; + lo_get_error_message(&e); + lo_destroy_handle(gh); + BOOST_LOG_TRIVIAL(error) << "libloadorder failed to set the load order. Details: " << e; + string err = lc::translate("libloadorder failed to set the load order. Details:").str() + " " + e; + lo_cleanup(); + throw error(error::liblo_error, err); + } + + loadOrder.clear(); + for (size_t i=0; i < pluginArrSize; ++i) { + loadOrder.push_back(string(pluginArr[i])); + } + + lo_destroy_handle(gh); + } + void Game::SetLoadOrder(const std::list& loadOrder) const { BOOST_LOG_TRIVIAL(trace) << "Setting load order for game: " << _name; diff --git a/src/backend/game.h b/src/backend/game.h index 514405b1..b88d29f4 100644 --- a/src/backend/game.h +++ b/src/backend/game.h @@ -72,6 +72,7 @@ namespace boss { bool IsActive(const std::string& plugin) const; + void GetLoadOrder(std::list& loadOrder) const; void SetLoadOrder(const std::list& loadOrder) const; void RefreshActivePluginsList(); diff --git a/src/gui/ids.h b/src/gui/ids.h index 83df235c..f174efd7 100644 --- a/src/gui/ids.h +++ b/src/gui/ids.h @@ -36,10 +36,11 @@ enum { //Main window. OPTION_EditMetadata = wxID_HIGHEST + 1, // declares an id which will be used to call our button - OPTION_ViewLastReport, - OPTION_ViewDebugLog, - OPTION_SortPlugins, - MENU_ShowSettings, + OPTION_ViewLastReport, + OPTION_SortPlugins, + MENU_ViewDebugLog, + MENU_ShowSettings, + MENU_RedatePlugins, //Settings window. LIST_Games, BUTTON_AddGame, diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 81263705..34ea73f3 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -383,8 +383,9 @@ Launcher::Launcher(const wxChar *title, YAML::Node& settings, Game& game, vector //Construct menus. //File Menu FileMenu->Append(OPTION_ViewLastReport, translate("&View Last Report")); - FileMenu->Append(OPTION_ViewDebugLog, translate("View &Debug Log")); + FileMenu->Append(MENU_ViewDebugLog, translate("View &Debug Log")); FileMenu->Append(OPTION_SortPlugins, translate("&Sort Plugins")); + RedatePluginsItem = FileMenu->Append(MENU_RedatePlugins, translate("&Redate Plugins")); FileMenu->AppendSeparator(); FileMenu->Append(wxID_EXIT); MenuBar->Append(FileMenu, translate("&File")); @@ -419,9 +420,10 @@ Launcher::Launcher(const wxChar *title, YAML::Node& settings, Game& game, vector //Bind event handlers. Bind(wxEVT_COMMAND_MENU_SELECTED, &Launcher::OnQuit, this, wxID_EXIT); Bind(wxEVT_COMMAND_MENU_SELECTED, &Launcher::OnViewLastReport, this, OPTION_ViewLastReport); - Bind(wxEVT_COMMAND_MENU_SELECTED, &Launcher::OnOpenDebugLog, this, OPTION_ViewDebugLog); + Bind(wxEVT_COMMAND_MENU_SELECTED, &Launcher::OnOpenDebugLog, this, MENU_ViewDebugLog); Bind(wxEVT_COMMAND_MENU_SELECTED, &Launcher::OnSortPlugins, this, OPTION_SortPlugins); Bind(wxEVT_COMMAND_MENU_SELECTED, &Launcher::OnEditMetadata, this, OPTION_EditMetadata); + Bind(wxEVT_COMMAND_MENU_SELECTED, &Launcher::OnRedatePlugins, this, MENU_RedatePlugins); Bind(wxEVT_COMMAND_MENU_SELECTED, &Launcher::OnOpenSettings, this, MENU_ShowSettings); Bind(wxEVT_COMMAND_MENU_SELECTED, &Launcher::OnHelp, this, wxID_HELP); Bind(wxEVT_COMMAND_MENU_SELECTED, &Launcher::OnAbout, this, wxID_ABOUT); @@ -436,6 +438,11 @@ Launcher::Launcher(const wxChar *title, YAML::Node& settings, Game& game, vector if (!fs::exists(_game.ReportPath())) ViewButton->Enable(false); + if (_game.Id() == boss::g_game_tes5) + RedatePluginsItem->Enable(true); + else + RedatePluginsItem->Enable(false); + //Set title bar text. SetTitle(FromUTF8("BOSS - " + _game.Name())); @@ -950,6 +957,59 @@ void Launcher::OnViewLastReport(wxCommandEvent& event) { BOOST_LOG_TRIVIAL(debug) << "Report displayed."; } +void Launcher::OnRedatePlugins(wxCommandEvent& event) { + wxMessageDialog * dia = new wxMessageDialog(this, translate("This feature is provided so that modders using the Creation Kit may set the load order it uses. A side-effect is that any subscribed Steam Workshop mods will be re-downloaded by Steam. Do you wish to continue?"), translate("BOSS: Warning"), wxYES_NO|wxCANCEL|wxICON_EXCLAMATION); + + if (dia->ShowModal() == wxID_YES) { + BOOST_LOG_TRIVIAL(debug) << "Redating plugins."; + list loadorder; + try { + _game.GetLoadOrder(loadorder); + } catch (boss::error& e) { + BOOST_LOG_TRIVIAL(error) << "Failed to get load order. " << e.what(); + wxMessageBox( + FromUTF8(format(loc::translate("Error: Failed to get load order. %1%")) % e.what()), + translate("BOSS: Error"), + wxOK | wxICON_ERROR, + this); + } + + try { + if (!loadorder.empty()) { + + time_t lastTime, thisTime; + fs::path filepath = _game.DataPath() / loadorder.begin()->Name(); + if (!fs::exists(filepath) && fs::exists(filepath.string() + ".ghost")) + filepath += ".ghost"; + + lastTime = fs::last_write_time(filepath); + + for (list::const_iterator it=loadorder.begin(), itend=loadorder.end(); it != itend; ++it) { + + filepath = _game.DataPath() / loadorder.begin()->Name(); + if (!fs::exists(filepath) && fs::exists(filepath.string() + ".ghost")) + filepath += ".ghost"; + + time_t thisTime = fs::last_write_time(filepath); + if (thisTime > lastTime) + lastTime = thisTime; + else { + lastTime += 60; + fs::last_write_time(filepath, lastTime); //Space timestamps by a minute. + } + } + } + } catch(fs::filesystem_error& e) { + BOOST_LOG_TRIVIAL(error) << "Failed to set plugin timestamps. " << e.what(); + wxMessageBox( + FromUTF8(format(loc::translate("Error: Failed to set plugin timestamps. %1%")) % e.what()), + translate("BOSS: Error"), + wxOK | wxICON_ERROR, + this); + } + } +} + void Launcher::OnOpenSettings(wxCommandEvent& event) { BOOST_LOG_TRIVIAL(debug) << "Opening settings window..."; SettingsFrame *settings = new SettingsFrame(this, translate("BOSS: Settings"), _settings, _games); @@ -973,6 +1033,10 @@ void Launcher::OnGameChange(wxCommandEvent& event) { NULL); } SetTitle(FromUTF8("BOSS - " + _game.Name())); + if (_game.Id() == boss::g_game_tes5) + RedatePluginsItem->Enable(true); + else + RedatePluginsItem->Enable(false); } void Launcher::OnHelp(wxCommandEvent& event) { diff --git a/src/gui/main.h b/src/gui/main.h index 1f395a22..e9611e9d 100644 --- a/src/gui/main.h +++ b/src/gui/main.h @@ -50,6 +50,7 @@ public: void OnSortPlugins(wxCommandEvent& event); void OnEditMetadata(wxCommandEvent& event); void OnViewLastReport(wxCommandEvent& event); + void OnRedatePlugins(wxCommandEvent& event); void OnOpenSettings(wxCommandEvent& event); void OnOpenDebugLog(wxCommandEvent& event); @@ -61,6 +62,7 @@ public: void OnClose(wxCloseEvent& event); private: wxMenu * GameMenu; + wxMenuItem * RedatePluginsItem; wxButton * ViewButton; boss::Game& _game;