diff --git a/BOSS.ico b/BOSS.ico new file mode 100644 index 00000000..568cbaf2 Binary files /dev/null and b/BOSS.ico differ diff --git a/CMakeLists.txt b/CMakeLists.txt index 47c938ec..f3dd0ad8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,8 @@ include_directories ("${PROJECT_LIBS_DIR}/alphanum" "${PROJECT_LIBS_DIR}/utf8" " # Settings when compiling for Windows. IF (CMAKE_SYSTEM_NAME MATCHES "Windows") + add_definitions (-DUNICODE -D_UNICODE) + set (BOSS_SRC ${BOSS_SRC} "${CMAKE_SOURCE_DIR}/resource.rc") IF (${PROJECT_LINK} MATCHES "STATIC") add_definitions (-DLIBLO_STATIC) add_definitions (-DBOSS_STATIC) @@ -52,8 +54,10 @@ IF (CMAKE_HOST_SYSTEM_NAME MATCHES "Linux") set (CMAKE_MODULE_LINKER_FLAGS "-static-libstdc++ -static-libgcc") IF (CMAKE_SYSTEM_NAME MATCHES "Windows") - link_directories ("${PROJECT_LIBS_DIR}/boost/stage-mingw-${PROJECT_ARCH}/lib") - set (BOSS_LIBS version) + link_directories ("${PROJECT_LIBS_DIR}/boost/stage-mingw-${PROJECT_ARCH}/lib" "${PROJECT_LIBS_DIR}/wxWidgets/build-msw/lib") + include_directories ("${PROJECT_LIBS_DIR}/wxWidgets/build-msw/lib/wx/include/i586-mingw32msvc-msw-unicode-static-2.9" "${PROJECT_LIBS_DIR}/wxWidgets/include") + set (BOSS_LIBS version wx_mswu_core-2.9-i586-mingw32msvc wx_baseu-2.9-i586-mingw32msvc wx_mswu_adv-2.9-i586-mingw32msvc wxpng-2.9-i586-mingw32msvc wxzlib-2.9-i586-mingw32msvc comctl32) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--subsystem,windows") ENDIF () set (BOSS_LIBS ${BOSS_LIBS} zlibstatic loadorder yaml-cpp boost_locale boost_filesystem boost_system boost_regex) @@ -65,14 +69,23 @@ IF (CMAKE_HOST_SYSTEM_NAME MATCHES "Windows") set (CMAKE_CXX_FLAGS "/EHsc") ENDIF () +############################## +# More General Settings +############################## + +set (BOSS_GUI_SRC ${BOSS_SRC} "${CMAKE_SOURCE_DIR}/src/gui/ids.cpp" "${CMAKE_SOURCE_DIR}/src/gui/main.cpp" "${CMAKE_SOURCE_DIR}/src/gui/settings.cpp") + +set (BOSS_API_SRC ${BOSS_SRC} "${CMAKE_SOURCE_DIR}/src/api.cpp") + + ############################## # Actual Building ############################## # Build API. -#add_library (boss ${PROJECT_LINK} "${CMAKE_SOURCE_DIR}/src/api.cpp" ${BOSS_SRC}) +#add_library (boss ${PROJECT_LINK} ${BOSS_API_SRC}) #target_link_libraries (boss ${BOSS_LIBS}) # Build tester. -add_executable (tester "${CMAKE_SOURCE_DIR}/src/tester.cpp" ${BOSS_SRC}) -target_link_libraries (tester ${BOSS_LIBS}) +add_executable (BOSS ${BOSS_GUI_SRC}) +target_link_libraries (BOSS ${BOSS_LIBS}) diff --git a/examples/settings.yaml b/examples/settings.yaml index 28041a9b..cf7c04aa 100644 --- a/examples/settings.yaml +++ b/examples/settings.yaml @@ -3,8 +3,8 @@ Language: eng # An ISO 639-3 language string. -Game: auto # auto, oblivion, skyrim, fallout3, falloutnv -Last Game: auto # auto, oblivion, skyrim, fallout3, falloutnv +Game: auto # auto, oblivion, nehrim, skyrim, fallout3, falloutnv +Last Game: auto # auto, oblivion, nehrim, skyrim, fallout3, falloutnv Debug Verbosity: 0 # 0, 1, 2, 3. Logging takes place if > 0. Update Masterlist: true diff --git a/resource.rc b/resource.rc new file mode 100644 index 00000000..15abb9f5 --- /dev/null +++ b/resource.rc @@ -0,0 +1,22 @@ +#include "wx/msw/wx.rc" +1 VERSIONINFO + FILEVERSION 3,0,0,0 + PRODUCTVERSION 3,0,0,0 + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileVersion", "3.0.0" + VALUE "LegalCopyright", "Copyright (C) 2013 WrinklyNinja" + VALUE "ProductVersion", "3.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END +MAINICON ICON "BOSS.ico" diff --git a/src/game.cpp b/src/game.cpp index dc6fcc7d..acf6bf66 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -43,9 +43,7 @@ namespace fs = boost::filesystem; namespace boss { - Game::Game() { - throw error(ERROR_INVALID_ARGS, "No arguments supplied."); - } + Game::Game() {} Game::Game(const unsigned int gameCode, const string path, const bool noPathInit) : id(gameCode) { diff --git a/src/globals.h b/src/globals.h index c574624a..a4a267e8 100644 --- a/src/globals.h +++ b/src/globals.h @@ -30,6 +30,7 @@ namespace boss { const unsigned int GAME_TES5 = 2; const unsigned int GAME_FO3 = 3; const unsigned int GAME_FONV = 4; + const unsigned int GAME_NEHRIM = 5; const unsigned int VERSION_MAJOR = 3; const unsigned int VERSION_MINOR = 0; diff --git a/src/gui/ids.cpp b/src/gui/ids.cpp new file mode 100644 index 00000000..df7ec623 --- /dev/null +++ b/src/gui/ids.cpp @@ -0,0 +1,38 @@ +/* BOSS + + A plugin load order optimiser for games that use the esp/esm plugin system. + + Copyright (C) 2013 WrinklyNinja + + This file is part of BOSS. + + BOSS is free software: you can redistribute + it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + BOSS is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with BOSS. If not, see + . +*/ + +#include "ids.h" + +#include + +wxString translate(const std::string& str) { + return wxString(boost::locale::translate(str).str().c_str(), wxConvUTF8); +} + +wxString FromUTF8(const std::string& str) { + return wxString(str.c_str(), wxConvUTF8); +} + +wxString FromUTF8(const boost::format& f) { + return FromUTF8(f.str()); +} diff --git a/src/gui/ids.h b/src/gui/ids.h new file mode 100644 index 00000000..a2836dcb --- /dev/null +++ b/src/gui/ids.h @@ -0,0 +1,74 @@ +/* BOSS + + A plugin load order optimiser for games that use the esp/esm plugin system. + + Copyright (C) 2013 WrinklyNinja + + This file is part of BOSS. + + BOSS is free software: you can redistribute + it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + BOSS is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with BOSS. If not, see + . +*/ + +#ifndef __BOSS_GUI_IDS__ +#define __BOSS_GUI_IDS__ + +#include +#include +#include "wx/wxprec.h" + +#ifndef WX_PRECOMP +# include "wx/wx.h" +#endif + + +enum { + //Main window. + OPTION_EditMetadata = wxID_HIGHEST + 1, // declares an id which will be used to call our button + OPTION_ViewLastReport, + OPTION_SortPlugins, + MENU_Quit, + MENU_OpenMainReadMe, + MENU_OpenSyntaxReadMe, + MENU_OpenAPIReadMe, + MENU_OpenVersionHistory, + MENU_OpenLicenses, + MENU_ShowAbout, + MENU_ShowSettings, + MENU_Oblivion, + MENU_Nehrim, + MENU_Skyrim, + MENU_Fallout3, + MENU_FalloutNewVegas, + //Settings window. + OPTION_OKExitSettings, + OPTION_CancelExitSettings +}; + +wxString translate(const std::string& str); + +wxString FromUTF8(const std::string& str); + +wxString FromUTF8(const boost::format& f); + +// Temporary hacks. +const char * const libespm_options_path = "libespm.cfg"; +const char * const libespm_game = "Skyrim"; + +const char * const masterlist_path = "masterlist.yaml"; +const char * const userlist_path = "userlist.yaml"; +const char * const results_path = "results.yaml"; +const char * const settings_path = "settings.yaml"; + +#endif diff --git a/src/gui/main.cpp b/src/gui/main.cpp new file mode 100644 index 00000000..c2674f83 --- /dev/null +++ b/src/gui/main.cpp @@ -0,0 +1,519 @@ +/* BOSS + + A plugin load order optimiser for games that use the esp/esm plugin system. + + Copyright (C) 2013 WrinklyNinja + + This file is part of BOSS. + + BOSS is free software: you can redistribute + it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + BOSS is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with BOSS. If not, see + . +*/ + +#include "../globals.h" +#include "../metadata.h" +#include "../parsers.h" +#include "main.h" +#include "settings.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +BEGIN_EVENT_TABLE ( Launcher, wxFrame ) + EVT_MENU ( MENU_Quit, Launcher::OnQuit ) + EVT_MENU ( OPTION_EditMetadata, Launcher::OnEditMetadata ) + EVT_MENU ( OPTION_ViewLastReport, Launcher::OnViewLastReport ) + EVT_MENU ( OPTION_SortPlugins, Launcher::OnSortPlugins ) + EVT_MENU ( MENU_OpenMainReadMe, Launcher::OnOpenFile ) + EVT_MENU ( MENU_OpenSyntaxReadMe, Launcher::OnOpenFile ) + EVT_MENU ( MENU_OpenAPIReadMe, Launcher::OnOpenFile ) + EVT_MENU ( MENU_OpenVersionHistory, Launcher::OnOpenFile ) + EVT_MENU ( MENU_OpenLicenses, Launcher::OnOpenFile ) + EVT_MENU ( MENU_ShowAbout, Launcher::OnAbout ) + EVT_MENU ( MENU_ShowSettings, Launcher::OnOpenSettings ) + EVT_MENU ( MENU_Oblivion, Launcher::OnGameChange ) + EVT_MENU ( MENU_Nehrim, Launcher::OnGameChange ) + EVT_MENU ( MENU_Skyrim, Launcher::OnGameChange ) + EVT_MENU ( MENU_Fallout3, Launcher::OnGameChange ) + EVT_MENU ( MENU_FalloutNewVegas, Launcher::OnGameChange ) + EVT_BUTTON ( OPTION_SortPlugins, Launcher::OnSortPlugins ) + EVT_BUTTON ( OPTION_EditMetadata, Launcher::OnEditMetadata ) + EVT_BUTTON ( OPTION_ViewLastReport, Launcher::OnViewLastReport ) +END_EVENT_TABLE() + +IMPLEMENT_APP(BossGUI); + +using namespace boss; +using namespace std; + +namespace fs = boost::filesystem; +namespace loc = boost::locale; + +// Temporary hacks. +const fs::path readme_path = fs::path("Docs") / "BOSS Readme.html"; +const fs::path syntax_doc_path = fs::path("Docs") / "BOSS Metadata File Syntax.html"; +const fs::path api_doc_path = fs::path("Docs") / "BOSS API Readme.html"; +const fs::path version_history_path = fs::path("Docs") / "BOSS Version History.html"; +const fs::path licenses_path = fs::path("Docs") / "Licenses.txt"; + +bool BossGUI::OnInit() { + //Check if GUI is already running. + wxSingleInstanceChecker *checker = new wxSingleInstanceChecker; + + if (checker->IsAnotherRunning()) { + //Should print error message here. + delete checker; // OnExit() won't be called if we return false + checker = NULL; + + return false; + } + + //Load settings. + YAML::Node settings; + if (fs::exists(settings_path)) { + settings = YAML::LoadFile(settings_path); + } + + //Apply logging and language settings (skipping for tester though). + + //Also skipping game detection. + Game game(GAME_TES5); + vector detected; + detected.push_back(GAME_TES5); + + //Create launcher window. + Launcher * launcher = new Launcher(wxT("BOSS"), settings, game, detected); + + launcher->SetIcon(wxIconLocation("BOSS.exe")); + launcher->Show(); + SetTopWindow(launcher); + + return true; +} + +Launcher::Launcher(const wxChar *title, const YAML::Node& settings, const Game& game, const vector& detectedGames) : wxFrame(NULL, wxID_ANY, title), _game(game), _detectedGames(detectedGames), _settings(settings) { + + //Set up menu bar first. + MenuBar = new wxMenuBar(); + // File Menu + FileMenu = new wxMenu(); + FileMenu->Append(OPTION_ViewLastReport, translate("&View Last Report"), translate("Opens your last report.")); + FileMenu->Append(OPTION_SortPlugins, translate("&Sort Plugins"), translate("Sorts your installed plugins.")); + FileMenu->AppendSeparator(); + FileMenu->Append(MENU_Quit, translate("&Quit"), translate("Quit BOSS.")); + MenuBar->Append(FileMenu, translate("&File")); + //Edit Menu + EditMenu = new wxMenu(); + EditMenu->Append(OPTION_EditMetadata, translate("&Metadata..."), translate("Opens a window where you can edit plugin metadata.")); + EditMenu->Append(MENU_ShowSettings, translate("&Settings..."), translate("Opens the Settings window.")); + MenuBar->Append(EditMenu, translate("&Edit")); + //Game menu + GameMenu = new wxMenu(); + GameMenu->AppendRadioItem(MENU_Oblivion, wxT("&Oblivion"), translate("Switch to running BOSS for Oblivion.")); + GameMenu->AppendRadioItem(MENU_Nehrim, wxT("&Nehrim"), translate("Switch to running BOSS for Nehrim.")); + GameMenu->AppendRadioItem(MENU_Skyrim, wxT("&Skyrim"), translate("Switch to running BOSS for Skyrim.")); + GameMenu->AppendRadioItem(MENU_Fallout3, wxT("&Fallout 3"), translate("Switch to running BOSS for Fallout 3.")); + GameMenu->AppendRadioItem(MENU_FalloutNewVegas, wxT("&Fallout: New Vegas"), translate("Switch to running BOSS for Fallout: New Vegas.")); + MenuBar->Append(GameMenu, translate("&Active Game")); + // About menu + HelpMenu = new wxMenu(); + HelpMenu->Append(MENU_OpenMainReadMe, translate("Open &Main Readme"), translate("Opens the main BOSS readme in your default web browser.")); + HelpMenu->Append(MENU_OpenSyntaxReadMe, translate("Open &Metadata File Syntax Doc"), translate("Opens the BOSS metadata file syntax documentation in your default web browser.")); + HelpMenu->Append(MENU_OpenAPIReadMe, translate("&Open API Readme"), translate("Opens the BOSS API readme in your default web browser.")); + HelpMenu->Append(MENU_OpenVersionHistory, translate("Open &Version History"), translate("Opens the BOSS version history in your default web browser.")); + HelpMenu->Append(MENU_OpenLicenses, translate("View &Copyright Licenses"), translate("View the GNU General Public License v3.0 and GNU Free Documentation License v1.3.")); + HelpMenu->AppendSeparator(); + HelpMenu->Append(MENU_ShowAbout, translate("&About BOSS..."), translate("Shows information about BOSS.")); + MenuBar->Append(HelpMenu, translate("&Help")); + SetMenuBar(MenuBar); + + //Set up stuff in the frame. + SetBackgroundColour(wxColour(255,255,255)); + + //Add the three buttons. + wxBoxSizer *buttonBox = new wxBoxSizer(wxVERTICAL); + buttonBox->Add(EditButton = new wxButton(this,OPTION_EditMetadata, translate("Edit Metadata")), 1, wxEXPAND|wxALIGN_CENTRE|wxALL, 10); + buttonBox->Add(SortButton = new wxButton(this,OPTION_SortPlugins, translate("Sort Plugins")), 1, wxEXPAND|wxALIGN_CENTRE|wxLEFT|wxRIGHT, 10); + buttonBox->Add(ViewButton = new wxButton(this,OPTION_ViewLastReport, translate("View Last Report")), 1, wxEXPAND|wxALIGN_CENTRE|wxALL, 10); + + SortButton->SetDefault(); + + if (_game.Id() == GAME_TES4) + GameMenu->FindItem(MENU_Oblivion)->Check(); + else if (_game.Id() == GAME_NEHRIM) + GameMenu->FindItem(MENU_Nehrim)->Check(); + else if (_game.Id() == GAME_TES5) + GameMenu->FindItem(MENU_Skyrim)->Check(); + else if (_game.Id() == GAME_FO3) + GameMenu->FindItem(MENU_Fallout3)->Check(); + else if (_game.Id() == GAME_FONV) + GameMenu->FindItem(MENU_FalloutNewVegas)->Check(); + + DisableUndetectedGames(); + + //Now set the layout and sizes. + SetSizerAndFit(buttonBox); + SetSize(wxSize(250, 200)); +} + +//Called when the frame exits. +void Launcher::OnQuit(wxCommandEvent& event) { + Close(true); // Tells the OS to quit running this process +} + +void Launcher::OnSortPlugins(wxCommandEvent& event) { + + wxProgressDialog *progDia = new wxProgressDialog(translate("BOSS: Working..."),translate("BOSS working..."), 1000, this, wxPD_APP_MODAL|wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME); + + time_t t0 = time(NULL); + + /* Stuff still missing from a normal execution of BOSS: + + - Reading of settings file. + - Detecting game to run for. + - Error handling. + - Masterlist updating. + - Checks for metadata self-consistency. + - Checks for cyclic dependencies and incompatibilities. + - Setting of load order. + + Need to include libespm setup into game setup, once the former is made to be not global. + */ + + ofstream out("out.txt"); + + out << "Setting up libespm and BOSS..." << endl; + + // Set up libesm. + common::options::setGame(libespm_game); + ifstream input(libespm_options_path); + common::readOptions(input); + input.close(); + + //Set up BOSS vars. + boss::Game game(boss::GAME_TES5); + + out << "Reading plugins in Data folder..." << endl; + time_t start, end; + start = time(NULL); + + // Get a list of the plugins. + list plugins; + for (fs::directory_iterator it(game.DataPath()); it != fs::directory_iterator(); ++it) { + if (fs::is_regular_file(it->status()) && (it->path().extension().string() == ".esp" || it->path().extension().string() == ".esm")) { + + string filename = it->path().filename().string(); + if (filename == "Skyrim.esm" + || filename == "Tamriel Compendium.esp" + || filename == "Tamriel Compendium - Skill Books.esp") + continue; // Libespm crashes with these plugins. + + out << "Reading plugin: " << filename << endl; + boss::Plugin plugin(game, filename); + plugins.push_back(plugin); + + progDia->Pulse(); + } + } + + end = time(NULL); + out << "Time taken to read plugins: " << (end - start) << " seconds." << endl; + start = time(NULL); + + YAML::Node mlist, ulist; + list messages, mlist_messages, ulist_messages; + list mlist_plugins, ulist_plugins; + + if (fs::exists(masterlist_path)) { + out << "Parsing masterlist..." << endl; + + mlist = YAML::LoadFile(masterlist_path); + if (mlist["globals"]) + mlist_messages = mlist["globals"].as< list >(); + if (mlist["plugins"]) + mlist_plugins = mlist["plugins"].as< list >(); + + end = time(NULL); + out << "Time taken to parse masterlist: " << (end - start) << " seconds." << endl; + start = time(NULL); + } + + if (fs::exists(userlist_path)) { + out << "Parsing userlist..." << endl; + + ulist = YAML::LoadFile(userlist_path); + if (ulist["globals"]) + ulist_messages = ulist["globals"].as< list >(); + if (ulist["plugins"]) + ulist_plugins = ulist["plugins"].as< list >(); + + end = time(NULL); + out << "Time taken to parse userlist: " << (end - start) << " seconds." << endl; + start = time(NULL); + } + + progDia->Pulse(); + + if (fs::exists(masterlist_path) || fs::exists(userlist_path)) { + out << "Merging plugin lists..." << endl; + + //Merge all global message lists. + messages = mlist_messages; + messages.insert(messages.end(), ulist_messages.begin(), ulist_messages.end()); + + //Merge plugin list, masterlist and userlist plugin data. + for (list::iterator it=plugins.begin(), endIt=plugins.end(); it != endIt; ++it) { + //Check if there is already a plugin in the 'plugins' list or not. + list::iterator pos = std::find(mlist_plugins.begin(), mlist_plugins.end(), *it); + + if (pos != mlist_plugins.end()) { + //Need to merge plugins. + it->Merge(*pos); + } + + pos = std::find(ulist_plugins.begin(), ulist_plugins.end(), *it); + + if (pos != ulist_plugins.end()) { + //Need to merge plugins. + it->Merge(*pos); + } + } + + end = time(NULL); + out << "Time taken to merge lists: " << (end - start) << " seconds." << endl; + start = time(NULL); + } + + progDia->Pulse(); + + out << "Evaluating any conditions in plugin list..." << endl; + + for (list::iterator it=plugins.begin(), endIt=plugins.end(); it != endIt; ++it) { + try { + it->EvalAllConditions(game); + } catch (boss::error& e) { + out << e.what() << endl; + } + } + + end = time(NULL); + out << "Time taken to evaluate plugin list: " << (end - start) << " seconds." << endl; + start = time(NULL); + + progDia->Pulse(); + + out << "Checking install validity..." << endl; + + for (list::iterator it=plugins.begin(), endIt = plugins.end(); it != endIt; ++it) { + map issues = it->CheckInstallValidity(game); + for (map::const_iterator jt=issues.begin(), endJt=issues.end(); jt != endJt; ++jt) { + if (jt->second) + out << "Error: Invalid install detected! \"" << jt->first << "\" is incompatible with \"" << it->Name() << "\" and is present." << endl; + else + out << "Error: Invalid install detected! \"" << jt->first << "\" is required by \"" << it->Name() << "\" but is missing." << endl; + } + } + + + + progDia->Pulse(); + + out << "Printing plugin details..." << endl; + + for (list::iterator it=plugins.begin(), endIt = plugins.end(); it != endIt; ++it) { + out << it->Name() << endl + << '\t' << "Number of records: " << it->FormIDs().size() << endl + << '\t' << "Is Master: " << it->IsMaster() << endl + << '\t' << "Masters:" << endl; + + vector masters = it->Masters(); + for(int i = 0; i < masters.size(); ++i) + out << '\t' << '\t' << i << ": " << masters[i] << endl; + + out << '\t' << "Conflicts with:" << endl; + for (list::iterator jt=plugins.begin(), endJt = plugins.end(); jt != endJt; ++jt) { + if (*jt != *it && !jt->MustLoadAfter(*it)) { + size_t overlap = jt->OverlapFormIDs(*it).size(); + if (overlap > 0) + out << '\t' << '\t' << jt->Name() << " (" << overlap << " records)" << endl; + } + } + } + + progDia->Pulse(); + + end = time(NULL); + out << "Time taken to print plugins' details: " << (end - start) << " seconds." << endl; + start = time(NULL); + + out << "Sorting plugins..." << endl; + + plugins.sort(); + + end = time(NULL); + out << "Time taken to sort plugins: " << (end - start) << " seconds." << endl; + + progDia->Pulse(); + + for (list::iterator it=plugins.begin(), endIt = plugins.end(); it != endIt; ++it) + out << it->Name() << endl; + + out << "Writing results file..." << endl; + + YAML::Emitter yout; + yout.SetIndent(2); + yout << YAML::BeginMap + << YAML::Key << "globals" << YAML::Value << messages + << YAML::Key << "plugins" << YAML::Value << plugins + << YAML::EndMap; + + ofstream results_out(results_path); + results_out << yout.c_str(); + results_out.close(); + + progDia->Pulse(); + + out << "Tester finished. Total time taken: " << time(NULL) - t0 << endl; + out.close(); + + progDia->Destroy(); +} + +void Launcher::OnEditMetadata(wxCommandEvent& event) { + +} + +void Launcher::OnViewLastReport(wxCommandEvent& event) { + +} + +void Launcher::OnOpenSettings(wxCommandEvent& event) { + //Tell the user that stuff is happenining. + SettingsFrame *settings = new SettingsFrame(translate("BOSS: Settings"), this, _settings); + settings->SetIcon(wxIconLocation("BOSS.exe")); + settings->Show(); +} + +void Launcher::OnGameChange(wxCommandEvent& event) { + try { + switch (event.GetId()) { + case MENU_Oblivion: + _game = Game(GAME_TES4); + _settings["Last Game"] = "oblivion"; + break; + case MENU_Nehrim: + _game = Game(GAME_NEHRIM); + _settings["Last Game"] = "nehrim"; + break; + case MENU_Skyrim: + _game = Game(GAME_TES5); + _settings["Last Game"] = "skyrim"; + break; + case MENU_Fallout3: + _game = Game(GAME_FO3); + _settings["Last Game"] = "fallout3"; + break; + case MENU_FalloutNewVegas: + _game = Game(GAME_FONV); + _settings["Last Game"] = "falloutnv"; + break; + } + } catch (error& e) { + wxMessageBox(e.what(), translate("BOSS: Error"), wxOK | wxICON_ERROR, this); + } + _game.CreateBOSSGameFolder(); + SetTitle(wxT("BOSS - " + _game.Name())); //Don't need to convert name, known to be only ASCII chars. +} + +void Launcher::OnOpenFile(wxCommandEvent& event) { + string file; + if (event.GetId() == MENU_OpenMainReadMe) + file = readme_path.string(); + else if (event.GetId() == MENU_OpenSyntaxReadMe) + file = syntax_doc_path.string(); + else if (event.GetId() == MENU_OpenAPIReadMe) + file = api_doc_path.string(); + else if (event.GetId() == MENU_OpenVersionHistory) + file = version_history_path.string(); + else if (event.GetId() == MENU_OpenLicenses) + file = licenses_path.string(); + //Look for file. + if (fs::exists(file)) { + wxLaunchDefaultApplication(file); + } else //No ReadMe exists, show a pop-up message saying so. + wxMessageBox( + FromUTF8(boost::format(loc::translate("Error: \"%1%\" cannot be found.")) % file), + translate("BOSS: Error"), + wxOK | wxICON_ERROR, + this); +} + +void Launcher::OnAbout(wxCommandEvent& event) { + wxAboutDialogInfo aboutInfo; + aboutInfo.SetName("BOSS"); + aboutInfo.SetVersion(IntToString(VERSION_MAJOR)+"."+IntToString(VERSION_MINOR)+"."+IntToString(VERSION_PATCH)); + aboutInfo.SetDescription(translate("A utility that optimises \nTES IV: Oblivion, Nehrim - At Fate's Edge, TES V: Skyrim, Fallout 3 and Fallout: New Vegas mod load orders.")); + aboutInfo.SetCopyright("Copyright (C) 2009-2013 BOSS Development Team."); + aboutInfo.SetWebSite("http://code.google.com/p/better-oblivion-sorting-software/"); + aboutInfo.SetLicence("This program is free software: you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation, either version 3 of the License, or\n" + "(at your option) any later version.\n" + "\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program. If not, see ."); + aboutInfo.SetIcon(wxIconLocation("BOSS.exe")); + wxAboutBox(aboutInfo); +} + +void Launcher::DisableUndetectedGames() { + GameMenu->FindItem(MENU_Oblivion)->Enable(false); + GameMenu->FindItem(MENU_Nehrim)->Enable(false); + GameMenu->FindItem(MENU_Skyrim)->Enable(false); + GameMenu->FindItem(MENU_Fallout3)->Enable(false); + GameMenu->FindItem(MENU_FalloutNewVegas)->Enable(false); + for (size_t i=0; i < _detectedGames.size(); i++) { + if (_detectedGames[i] == GAME_TES4) + GameMenu->FindItem(MENU_Oblivion)->Enable(); + else if (_detectedGames[i] == GAME_NEHRIM) + GameMenu->FindItem(MENU_Nehrim)->Enable(); + else if (_detectedGames[i] == GAME_TES5) + GameMenu->FindItem(MENU_Skyrim)->Enable(); + else if (_detectedGames[i] == GAME_FO3) + GameMenu->FindItem(MENU_Fallout3)->Enable(); + else if (_detectedGames[i] == GAME_FONV) + GameMenu->FindItem(MENU_FalloutNewVegas)->Enable(); + } + + SetTitle(wxT("BOSS - " + _game.Name())); //Don't need to convert name, known to be only ASCII chars. +} diff --git a/src/gui/main.h b/src/gui/main.h new file mode 100644 index 00000000..9153fc2b --- /dev/null +++ b/src/gui/main.h @@ -0,0 +1,71 @@ +/* BOSS + + A plugin load order optimiser for games that use the esp/esm plugin system. + + Copyright (C) 2013 WrinklyNinja + + This file is part of BOSS. + + BOSS is free software: you can redistribute + it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + BOSS is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with BOSS. If not, see + . +*/ + +#ifndef __BOSS_GUI_MAIN__ +#define __BOSS_GUI_MAIN__ + +#include "ids.h" +#include "../game.h" + +#include +#include + +//Program class. +class BossGUI : public wxApp { +public: + bool OnInit(); //Load settings, apply logging and language settings, check if BOSS is already running, detect games, set game to last game or to first detected game if auto, create launcher window. +}; + +class Launcher : public wxFrame { +public: + Launcher(const wxChar *title, const YAML::Node& settings, const boss::Game& inGame, const std::vector& inGames); + + void OnSortPlugins(wxCommandEvent& event); + void OnEditMetadata(wxCommandEvent& event); + void OnViewLastReport(wxCommandEvent& event); + + void OnOpenSettings(wxCommandEvent& event); + void OnGameChange(wxCommandEvent& event); + void OnOpenFile(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + void OnQuit(wxCommandEvent& event); + + DECLARE_EVENT_TABLE() +private: + wxMenuBar *MenuBar; + wxMenu *FileMenu; + wxMenu *EditMenu; + wxMenu *GameMenu; + wxMenu *HelpMenu; + wxButton *SortButton; + wxButton *ViewButton; + wxButton *EditButton; + + std::vector _detectedGames; + boss::Game _game; + YAML::Node _settings; //BOSS Settings. + + void DisableUndetectedGames(); +}; + +#endif diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp new file mode 100644 index 00000000..cad68914 --- /dev/null +++ b/src/gui/settings.cpp @@ -0,0 +1,239 @@ +/* BOSS + + A plugin load order optimiser for games that use the esp/esm plugin system. + + Copyright (C) 2013 WrinklyNinja + + This file is part of BOSS. + + BOSS is free software: you can redistribute + it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + BOSS is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with BOSS. If not, see + . +*/ + +#include "settings.h" +#include + +BEGIN_EVENT_TABLE ( SettingsFrame, wxFrame ) + EVT_BUTTON ( OPTION_OKExitSettings, SettingsFrame::OnQuit) + EVT_BUTTON ( OPTION_CancelExitSettings, SettingsFrame::OnQuit) +END_EVENT_TABLE() + +using namespace std; + +SettingsFrame::SettingsFrame(const wxString title, wxFrame *parent, YAML::Node& settings) : wxFrame(parent, wxID_ANY, title), _settings(settings) { + + wxString DebugVerbosity[] = { + translate("None"), + translate("Low"), + translate("Medium"), + translate("High") + }; + + wxString Game[] = { + translate("Autodetect"), + wxT("Oblivion"), + wxT("Nehrim"), + wxT("Skyrim"), + wxT("Fallout 3"), + wxT("Fallout: New Vegas"), + }; + + wxString Language[] = { + wxT("English"), + /* wxString("Español", wxConvUTF8), + wxT("Deutsch"), + wxString("Русский", wxConvUTF8), + wxString("简体中文", wxConvUTF8)*/ + }; + + //Set up stuff in the frame. + SetBackgroundColour(wxColour(255,255,255)); + + wxSizerFlags leftItem(1); + leftItem.Border(wxALL, 10).Expand().Left(); + + wxSizerFlags rightItem(0); + rightItem.Border(wxALL, 10).Expand().Right(); + + wxSizerFlags wholeItem(1); + wholeItem.Border(wxALL, 10).Expand(); + + wxBoxSizer *bigBox = new wxBoxSizer(wxVERTICAL); + + wxFlexGridSizer *GridSizer = new wxFlexGridSizer(2, 5, 5); + + GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Default Game:")), leftItem); + GridSizer->Add(GameChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 6, Game), rightItem); + + GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Language:")), leftItem); + GridSizer->Add(LanguageChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 1, Language), rightItem); + + GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Debug Verbosity:")), leftItem); + GridSizer->Add(DebugVerbosityChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 4, DebugVerbosity), rightItem); + + GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Oblivion Masterlist URL:")), leftItem); + GridSizer->Add(OblivionURL = new wxTextCtrl(this, wxID_ANY), rightItem); + + GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Nehrim Masterlist URL:")), leftItem); + GridSizer->Add(NehrimURL = new wxTextCtrl(this, wxID_ANY), rightItem); + + GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Skyrim Masterlist URL:")), leftItem); + GridSizer->Add(SkyrimURL = new wxTextCtrl(this, wxID_ANY), rightItem); + + GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Fallout 3 Masterlist URL:")), leftItem); + GridSizer->Add(FO3URL = new wxTextCtrl(this, wxID_ANY), rightItem); + + GridSizer->Add(new wxStaticText(this, wxID_ANY, translate("Fallout: New Vegas Masterlist URL:")), leftItem); + GridSizer->Add(FONVURL = new wxTextCtrl(this, wxID_ANY), rightItem); + + bigBox->Add(GridSizer); + + bigBox->Add(UpdateMasterlistBox = new wxCheckBox(this, wxID_ANY, translate("Update masterlist before sorting.")), wholeItem); + + wxString text = translate("Language settings will be applied after the BOSS GUI is restarted."); + bigBox->Add(new wxStaticText(this, wxID_ANY, text), wholeItem); + + //Need to add 'OK' and 'Cancel' buttons. + wxBoxSizer *hbox = new wxBoxSizer(wxHORIZONTAL); + hbox->Add(new wxButton(this, OPTION_OKExitSettings, translate("OK"), wxDefaultPosition, wxSize(70, 30))); + hbox->Add(new wxButton(this, OPTION_CancelExitSettings, translate("Cancel"), wxDefaultPosition, wxSize(70, 30)), 0, wxLEFT, 20); + + //Now add TabHolder and OK button to window sizer. + bigBox->Add(hbox, 0, wxCENTER|wxALL, 10); + + //Initialise options with values. For checkboxes, they are off by default. + SetDefaultValues(); + + //Tooltips. + DebugVerbosityChoice->SetToolTip(translate("The output is logged to the BOSSDebugLog.txt file")); + + //Now set the layout and sizes. + SetSizerAndFit(bigBox); +} + +void SettingsFrame::SetDefaultValues() { + + if (_settings["Language"]) { + string lang = _settings["Language"].as(); + if (lang == "eng") + LanguageChoice->SetSelection(0); + } + + if (_settings["Game"]) { + string game = _settings["Game"].as(); + if (game == "auto") + GameChoice->SetSelection(0); + else if (game == "oblivion") + GameChoice->SetSelection(1); + else if (game == "nehrim") + GameChoice->SetSelection(2); + else if (game == "skyrim") + GameChoice->SetSelection(3); + else if (game == "fallout3") + GameChoice->SetSelection(4); + else if (game == "falloutnv") + GameChoice->SetSelection(5); + } + + if (_settings["Debug Verbosity"]) { + unsigned int verbosity = _settings["Debug Verbosity"].as(); + DebugVerbosityChoice->SetSelection(verbosity); + } + + if (_settings["Update Masterlist"]) { + bool update = _settings["Update Masterlist"].as(); + UpdateMasterlistBox->SetValue(update); + } + + if (_settings["Masterlist URLs"]) { + YAML::Node urls = _settings["Masterlist URLs"]; + + if (urls["Oblivion"]) + OblivionURL->SetValue(urls["Oblivion"].as()); + + if (urls["Nehrim"]) + NehrimURL->SetValue(urls["Nehrim"].as()); + + if (urls["Skyrim"]) + SkyrimURL->SetValue(urls["Skyrim"].as()); + + if (urls["Fallout 3"]) + FO3URL->SetValue(urls["Fallout 3"].as()); + + if (urls["Fallout New Vegas"]) + FONVURL->SetValue(urls["Fallout New Vegas"].as()); + } +} + +void SettingsFrame::OnQuit(wxCommandEvent& event) { + if (event.GetId() == OPTION_OKExitSettings) { + + switch (GameChoice->GetSelection()) { + case 0: + _settings["Game"] = "auto"; + break; + case 1: + _settings["Game"] = "oblivion"; + break; + case 2: + _settings["Game"] = "nehrim"; + break; + case 3: + _settings["Game"] = "skyrim"; + break; + case 4: + _settings["Game"] = "fallout3"; + break; + case 5: + _settings["Game"] = "falloutnv"; + break; + } + + switch (LanguageChoice->GetSelection()) { + case 0: + _settings["Language"] = "eng"; + break; + } + + _settings["Debug Verbosity"] = DebugVerbosityChoice->GetSelection(); + + _settings["Update Masterlist"] = UpdateMasterlistBox->IsChecked(); + + _settings["Masterlist URLs"]["Oblivion"] = string(OblivionURL->GetValue().ToUTF8()); + + _settings["Masterlist URLs"]["Nehrim"] = string(NehrimURL->GetValue().ToUTF8()); + + _settings["Masterlist URLs"]["Skyrim"] = string(SkyrimURL->GetValue().ToUTF8()); + + _settings["Masterlist URLs"]["Fallout 3"] = string(FO3URL->GetValue().ToUTF8()); + + _settings["Masterlist URLs"]["Fallout New Vegas"] = string(FONVURL->GetValue().ToUTF8()); + + //Also set the logger settings now. + /* g_logger.setOriginTracking(gl_debug_with_source); + g_logger.setVerbosity(static_cast(LV_WARN + gl_debug_verbosity)); + if (gl_log_debug_output) + g_logger.setStream(debug_log_path.string().c_str());*/ + + YAML::Emitter yout; + yout.SetIndent(2); + yout << _settings; + + ofstream out(settings_path); + out << yout.c_str(); + out.close(); + } + + this->Close(); +} diff --git a/src/gui/settings.h b/src/gui/settings.h new file mode 100644 index 00000000..addff22a --- /dev/null +++ b/src/gui/settings.h @@ -0,0 +1,50 @@ +/* BOSS + + A plugin load order optimiser for games that use the esp/esm plugin system. + + Copyright (C) 2013 WrinklyNinja + + This file is part of BOSS. + + BOSS is free software: you can redistribute + it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + BOSS is distributed in the hope that it will + be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with BOSS. If not, see + . +*/ + +#ifndef __BOSS_GUI_SETTINGS__ +#define __BOSS_GUI_SETTINGS__ + +#include "ids.h" +#include +#include + +class SettingsFrame : public wxFrame { +public: + SettingsFrame(const wxString title, wxFrame *parent, YAML::Node& settings); + void OnQuit(wxCommandEvent& event); + void SetDefaultValues(); + DECLARE_EVENT_TABLE() +private: + wxChoice *DebugVerbosityChoice; + wxChoice *GameChoice; + wxChoice *LanguageChoice; + wxCheckBox *UpdateMasterlistBox; + wxTextCtrl *OblivionURL; + wxTextCtrl *NehrimURL; + wxTextCtrl *SkyrimURL; + wxTextCtrl *FO3URL; + wxTextCtrl *FONVURL; + + YAML::Node _settings; +}; +#endif diff --git a/src/helpers.cpp b/src/helpers.cpp index dfce504b..87bddc5b 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -63,10 +63,10 @@ namespace boss { using namespace std; - using namespace boost; using boost::algorithm::replace_all; using boost::algorithm::replace_first; namespace karma = boost::spirit::karma; + namespace fs = boost::filesystem; //Calculate the CRC of the given file for comparison purposes. uint32_t GetCrc32(const fs::path& filename) { diff --git a/src/helpers.h b/src/helpers.h index fa10083d..05d3567e 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -33,14 +33,13 @@ #include namespace boss { - namespace fs = boost::filesystem; ////////////////////////////////////////////////////////////////////////// // Helper functions ////////////////////////////////////////////////////////////////////////// //Calculate the CRC of the given file for comparison purposes. - uint32_t GetCrc32(const fs::path& filename); + uint32_t GetCrc32(const boost::filesystem::path& filename); //Converts an integer to a string using BOOST's Spirit.Karma. Faster than a stringstream conversion. std::string IntToString(const int n); @@ -65,7 +64,7 @@ namespace boss { Version(); Version(const char * ver); Version(const std::string ver); - Version(const fs::path file); + Version(const boost::filesystem::path file); std::string AsString() const; diff --git a/src/metadata.cpp b/src/metadata.cpp index 781b2d86..1351fea2 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -479,16 +479,16 @@ namespace boss { map issues; if (tags.find(Tag("Filter")) == tags.end()) { for (vector::const_iterator it=masters.begin(), endIt=masters.end(); it != endIt; ++it) { - if (!fs::exists(game.DataPath() / *it)) + if (!boost::filesystem::exists(game.DataPath() / *it)) issues.insert(pair(*it,false)); } } for (set::const_iterator it=requirements.begin(), endIt=requirements.end(); it != endIt; ++it) { - if (!fs::exists(game.DataPath() / it->Name())) + if (!boost::filesystem::exists(game.DataPath() / it->Name())) issues.insert(pair(it->Name(),false)); } for (set::const_iterator it=incompatibilities.begin(), endIt=incompatibilities.end(); it != endIt; ++it) { - if (fs::exists(game.DataPath() / it->Name())) + if (boost::filesystem::exists(game.DataPath() / it->Name())) issues.insert(pair(it->Name(),true)); } return issues; diff --git a/src/parsers.h b/src/parsers.h index 575ba4bf..92c85e9d 100644 --- a/src/parsers.h +++ b/src/parsers.h @@ -436,7 +436,7 @@ namespace boss { throw boss::error(boss::ERROR_INVALID_ARGS, "The regex string \"" + filename + "\" is invalid."); } - for (fs::directory_iterator itr(parent_path); itr != fs::directory_iterator(); ++itr) { + for (boost::filesystem::directory_iterator itr(parent_path); itr != boost::filesystem::directory_iterator(); ++itr) { if (boost::regex_match(itr->path().filename().string(), regex)) { result = true; return; diff --git a/src/tester.cpp b/src/tester.cpp deleted file mode 100644 index d1fd5689..00000000 --- a/src/tester.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* BOSS - - A plugin load order optimiser for games that use the esp/esm plugin system. - - Copyright (C) 2012 WrinklyNinja - - This file is part of BOSS. - - BOSS is free software: you can redistribute - it and/or modify it under the terms of the GNU General Public License - as published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - BOSS is distributed in the hope that it will - be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with BOSS. If not, see - . -*/ - -#include -#include "metadata.h" -#include "parsers.h" -#include "game.h" -#include "error.h" -#include "globals.h" - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include - -namespace fs = boost::filesystem; - -using namespace std; - -// Temporary hack. -const char * const libespm_options_path = "libespm.cfg"; -const char * const libespm_game = "Skyrim"; - -const char * const masterlist_path = "masterlist.yaml"; -const char * const userlist_path = "userlist.yaml"; -const char * const results_path = "results.yaml"; - -int main(int argc, char *argv[]) { - - time_t t0 = time(NULL); - - /* Stuff still missing from a normal execution of BOSS: - - - Reading of settings file. - - Detecting game to run for. - - Error handling. - - Masterlist updating. - - Checks for metadata self-consistency. - - Checks for cyclic dependencies and incompatibilities. - - Setting of load order. - - Need to include libespm setup into game setup, once the former is made to be not global. - */ - - cout << "Setting up libespm and BOSS..." << endl; - - // Set up libesm. - common::options::setGame(libespm_game); - ifstream input(libespm_options_path); - common::readOptions(input); - input.close(); - - //Set up BOSS vars. - boss::Game game(boss::GAME_TES5); - - cout << "Reading plugins in Data folder..." << endl; - time_t start, end; - start = time(NULL); - - // Get a list of the plugins. - list plugins; - for (fs::directory_iterator it(game.DataPath()); it != fs::directory_iterator(); ++it) { - if (fs::is_regular_file(it->status()) && (it->path().extension().string() == ".esp" || it->path().extension().string() == ".esm")) { - - string filename = it->path().filename().string(); - if (filename == "Skyrim.esm" - || filename == "Tamriel Compendium.esp" - || filename == "Tamriel Compendium - Skill Books.esp") - continue; // Libespm crashes with these plugins. - - cout << "Reading plugin: " << filename << endl; - boss::Plugin plugin(game, filename); - plugins.push_back(plugin); - } - } - - end = time(NULL); - cout << "Time taken to read plugins: " << (end - start) << " seconds." << endl; - start = time(NULL); - - YAML::Node mlist, ulist; - list messages, mlist_messages, ulist_messages; - list mlist_plugins, ulist_plugins; - - if (fs::exists(masterlist_path)) { - cout << "Parsing masterlist..." << endl; - - mlist = YAML::LoadFile(masterlist_path); - if (mlist["globals"]) - mlist_messages = mlist["globals"].as< list >(); - if (mlist["plugins"]) - mlist_plugins = mlist["plugins"].as< list >(); - - end = time(NULL); - cout << "Time taken to parse masterlist: " << (end - start) << " seconds." << endl; - start = time(NULL); - } - - if (fs::exists(userlist_path)) { - cout << "Parsing userlist..." << endl; - - ulist = YAML::LoadFile(userlist_path); - if (ulist["globals"]) - ulist_messages = ulist["globals"].as< list >(); - if (ulist["plugins"]) - ulist_plugins = ulist["plugins"].as< list >(); - - end = time(NULL); - cout << "Time taken to parse userlist: " << (end - start) << " seconds." << endl; - start = time(NULL); - } - - if (fs::exists(masterlist_path) || fs::exists(userlist_path)) { - cout << "Merging plugin lists..." << endl; - - //Merge all global message lists. - messages = mlist_messages; - messages.insert(messages.end(), ulist_messages.begin(), ulist_messages.end()); - - //Merge plugin list, masterlist and userlist plugin data. - for (list::iterator it=plugins.begin(), endIt=plugins.end(); it != endIt; ++it) { - //Check if there is already a plugin in the 'plugins' list or not. - list::iterator pos = std::find(mlist_plugins.begin(), mlist_plugins.end(), *it); - - if (pos != mlist_plugins.end()) { - //Need to merge plugins. - it->Merge(*pos); - } - - pos = std::find(ulist_plugins.begin(), ulist_plugins.end(), *it); - - if (pos != ulist_plugins.end()) { - //Need to merge plugins. - it->Merge(*pos); - } - } - - end = time(NULL); - cout << "Time taken to merge lists: " << (end - start) << " seconds." << endl; - start = time(NULL); - } - - cout << "Evaluating any conditions in plugin list..." << endl; - - for (list::iterator it=plugins.begin(), endIt=plugins.end(); it != endIt; ++it) { - try { - it->EvalAllConditions(game); - } catch (boss::error& e) { - cout << e.what() << endl; - } - } - - end = time(NULL); - cout << "Time taken to evaluate plugin list: " << (end - start) << " seconds." << endl; - start = time(NULL); - - cout << "Checking install validity..." << endl; - - for (list::iterator it=plugins.begin(), endIt = plugins.end(); it != endIt; ++it) { - map issues = it->CheckInstallValidity(game); - for (map::const_iterator jt=issues.begin(), endJt=issues.end(); jt != endJt; ++jt) { - if (jt->second) - cout << "Error: Invalid install detected! \"" << jt->first << "\" is incompatible with \"" << it->Name() << "\" and is present." << endl; - else - cout << "Error: Invalid install detected! \"" << jt->first << "\" is required by \"" << it->Name() << "\" but is missing." << endl; - } - } - - - - cout << "Printing plugin details..." << endl; - - for (list::iterator it=plugins.begin(), endIt = plugins.end(); it != endIt; ++it) { - cout << it->Name() << endl - << '\t' << "Number of records: " << it->FormIDs().size() << endl - << '\t' << "Is Master: " << it->IsMaster() << endl - << '\t' << "Masters:" << endl; - - vector masters = it->Masters(); - for(int i = 0; i < masters.size(); ++i) - cout << '\t' << '\t' << i << ": " << masters[i] << endl; - - cout << '\t' << "Conflicts with:" << endl; - for (list::iterator jt=plugins.begin(), endJt = plugins.end(); jt != endJt; ++jt) { - if (*jt != *it && !jt->MustLoadAfter(*it)) { - size_t overlap = jt->OverlapFormIDs(*it).size(); - if (overlap > 0) - cout << '\t' << '\t' << jt->Name() << " (" << overlap << " records)" << endl; - } - } - } - - end = time(NULL); - cout << "Time taken to print plugins' details: " << (end - start) << " seconds." << endl; - start = time(NULL); - - cout << "Sorting plugins..." << endl; - - plugins.sort(); - - end = time(NULL); - cout << "Time taken to sort plugins: " << (end - start) << " seconds." << endl; - - for (list::iterator it=plugins.begin(), endIt = plugins.end(); it != endIt; ++it) - cout << it->Name() << endl; - - cout << "Writing results file..." << endl; - - YAML::Emitter yout; - yout.SetIndent(2); - yout << YAML::BeginMap - << YAML::Key << "globals" << YAML::Value << messages - << YAML::Key << "plugins" << YAML::Value << plugins - << YAML::EndMap; - - ofstream out(results_path); - out << yout.c_str(); - out.close(); - - cout << "Tester finished. Total time taken: " << time(NULL) - t0 << endl; - return 0; -}