Started implementing GUI. The 'Sort Plugins' button just runs the tester code for now. Metadata editor is unimplemented.

This commit is contained in:
WrinklyNinja
2013-05-04 22:25:01 +01:00
parent 5462d27927
commit 3f8702be93
17 changed files with 1042 additions and 269 deletions
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

+18 -5
View File
@@ -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})
+2 -2
View File
@@ -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
+22
View File
@@ -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"
+1 -3
View File
@@ -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) {
+1
View File
@@ -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;
+38
View File
@@ -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
<http://www.gnu.org/licenses/>.
*/
#include "ids.h"
#include <boost/locale.hpp>
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());
}
+74
View File
@@ -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
<http://www.gnu.org/licenses/>.
*/
#ifndef __BOSS_GUI_IDS__
#define __BOSS_GUI_IDS__
#include <string>
#include <boost/format.hpp>
#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
+519
View File
File diff suppressed because it is too large Load Diff
+71
View File
@@ -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
<http://www.gnu.org/licenses/>.
*/
#ifndef __BOSS_GUI_MAIN__
#define __BOSS_GUI_MAIN__
#include "ids.h"
#include "../game.h"
#include <vector>
#include <yaml-cpp/yaml.h>
//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<unsigned int>& 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<unsigned int> _detectedGames;
boss::Game _game;
YAML::Node _settings; //BOSS Settings.
void DisableUndetectedGames();
};
#endif
+239
View File
@@ -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
<http://www.gnu.org/licenses/>.
*/
#include "settings.h"
#include <fstream>
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<string>();
if (lang == "eng")
LanguageChoice->SetSelection(0);
}
if (_settings["Game"]) {
string game = _settings["Game"].as<string>();
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<unsigned int>();
DebugVerbosityChoice->SetSelection(verbosity);
}
if (_settings["Update Masterlist"]) {
bool update = _settings["Update Masterlist"].as<bool>();
UpdateMasterlistBox->SetValue(update);
}
if (_settings["Masterlist URLs"]) {
YAML::Node urls = _settings["Masterlist URLs"];
if (urls["Oblivion"])
OblivionURL->SetValue(urls["Oblivion"].as<string>());
if (urls["Nehrim"])
NehrimURL->SetValue(urls["Nehrim"].as<string>());
if (urls["Skyrim"])
SkyrimURL->SetValue(urls["Skyrim"].as<string>());
if (urls["Fallout 3"])
FO3URL->SetValue(urls["Fallout 3"].as<string>());
if (urls["Fallout New Vegas"])
FONVURL->SetValue(urls["Fallout New Vegas"].as<string>());
}
}
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<LogVerbosity>(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();
}
+50
View File
@@ -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
<http://www.gnu.org/licenses/>.
*/
#ifndef __BOSS_GUI_SETTINGS__
#define __BOSS_GUI_SETTINGS__
#include "ids.h"
#include <yaml-cpp/yaml.h>
#include <wx/listctrl.h>
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
+1 -1
View File
@@ -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) {
+2 -3
View File
@@ -33,14 +33,13 @@
#include <boost/filesystem.hpp>
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;
+3 -3
View File
@@ -479,16 +479,16 @@ namespace boss {
map<string,bool> issues;
if (tags.find(Tag("Filter")) == tags.end()) {
for (vector<string>::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<string,bool>(*it,false));
}
}
for (set<File>::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<string,bool>(it->Name(),false));
}
for (set<File>::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<string,bool>(it->Name(),true));
}
return issues;
+1 -1
View File
@@ -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;
-251
View File
@@ -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
<http://www.gnu.org/licenses/>.
*/
#include <yaml-cpp/yaml.h>
#include "metadata.h"
#include "parsers.h"
#include "game.h"
#include "error.h"
#include "globals.h"
#include <ostream>
#include <fstream>
#include <stdint.h>
#include <ctime>
#include <algorithm>
#include <iterator>
#include <src/commonSupport.h>
#include <src/fileFormat.h>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
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<boss::Plugin> 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<boss::Message> messages, mlist_messages, ulist_messages;
list<boss::Plugin> 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<boss::Message> >();
if (mlist["plugins"])
mlist_plugins = mlist["plugins"].as< list<boss::Plugin> >();
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<boss::Message> >();
if (ulist["plugins"])
ulist_plugins = ulist["plugins"].as< list<boss::Plugin> >();
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<boss::Plugin>::iterator it=plugins.begin(), endIt=plugins.end(); it != endIt; ++it) {
//Check if there is already a plugin in the 'plugins' list or not.
list<boss::Plugin>::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<boss::Plugin>::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<boss::Plugin>::iterator it=plugins.begin(), endIt = plugins.end(); it != endIt; ++it) {
map<string, bool> issues = it->CheckInstallValidity(game);
for (map<string,bool>::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<boss::Plugin>::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<std::string> 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<boss::Plugin>::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<boss::Plugin>::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;
}