1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-26 03:52:01 +02:00

Merge branch 'develop' of github.com:karol57/vcmi into karol57-develop

This commit is contained in:
Ivan Savenko 2014-09-04 20:29:24 +03:00
commit de9c5b1af7
49 changed files with 1150 additions and 877 deletions

View File

@ -7,7 +7,7 @@
#define strcpy_s(a, b, c) strncpy(a, c, b)
#endif
#ifdef __ANDROID__
#ifdef VCMI_ANDROID
#define GetGlobalAiVersion BattleAI_GetGlobalAiVersion
#define GetAiName BattleAI_GetAiName
#define GetNewBattleAI BattleAI_GetNewBattleAI

View File

@ -7,7 +7,7 @@
#define strcpy_s(a, b, c) strncpy(a, c, b)
#endif
#ifdef __ANDROID__
#ifdef VCMI_ANDROID
#define GetGlobalAiVersion StupidAI_GetGlobalAiVersion
#define GetAiName StupidAI_GetAiName
#define GetNewBattleAI StupidAI_GetNewBattleAI

View File

@ -5,7 +5,7 @@
#define strcpy_s(a, b, c) strncpy(a, c, b)
#endif
#ifdef __ANDROID__
#ifdef VCMI_ANDROID
#define GetGlobalAiVersion VCAI_GetGlobalAiVersion
#define GetAiName VCAI_GetAiName
#define GetNewAI VCAI_GetNewAI

View File

@ -3,6 +3,8 @@ GENERAL:
* VCMI can now be compiled with SDL2
* Better upscaling when running in fullscreen mode.
* Non-latin characters can now be entered in chat window or used for save names.
* (windows) Moved VCMI data directory from '%userprofile%\vcmi' to '%userprofile%\Documents\My Games\vcmi'
* (windows, OSX) Moved VCMI save directory from 'VCMI_DATA\Games' to 'VCMI_DATA\Saves'
RANDOM MAP GENERATOR:

View File

@ -49,10 +49,58 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
# pragma warning (disable : 4800 ) /* disable conversion to bool warning -- I think it's intended in all places */
#endif
/* ---------------------------------------------------------------------------- */
/* System detection. */
/* ---------------------------------------------------------------------------- */
// Based on: http://sourceforge.net/p/predef/wiki/OperatingSystems/
// and on: http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
// TODO?: Should be moved to vstd\os_detect.h (and then included by Global.h)
#ifdef _WIN16 // Defined for 16-bit environments
# error "16-bit Windows isn't supported"
#elif defined(_WIN64) // Defined for 64-bit environments
# define VCMI_WINDOWS
# define VCMI_WINDOWS_64
#elif defined(_WIN32) // Defined for both 32-bit and 64-bit environments
# define VCMI_WINDOWS
# define VCMI_WINDOWS_32
#elif defined(_WIN32_WCE)
# error "Windows CE isn't supported"
#elif defined(__linux__) || defined(__gnu_linux__) || defined(linux) || defined(__linux)
# define VCMI_UNIX
# define VCMI_LINUX
# ifdef __ANDROID__
# define VCMI_ANDROID
# endif
#elif defined(__APPLE__) && defined(__MACH__)
# define VCMI_UNIX
# define VCMI_APPLE
# include "TargetConditionals.h"
# if TARGET_IPHONE_SIMULATOR
# define VCMI_IOS
# define VCMI_IOS_SIM
# elif TARGET_OS_IPHONE
# define VCMI_IOS
# elif TARGET_OS_MAC
# define VCMI_MAC
# else
//# warning "Unknown Apple target."?
# endif
#else
# error "VCMI supports only Windows, OSX, Linux and Android targets"
#endif
#ifdef VCMI_IOS
# error "iOS system isn't yet supported."
#endif
/* ---------------------------------------------------------------------------- */
/* Commonly used C++, Boost headers */
/* ---------------------------------------------------------------------------- */
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#ifdef VCMI_WINDOWS
# define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - delete this line if something is missing.
# define NOMINMAX // Exclude min/max macros from <Windows.h>. Use std::[min/max] from <algorithm> instead.
#endif
#define _USE_MATH_DEFINES
#include <cstdio>
@ -86,7 +134,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#define BOOST_FILESYSTEM_VERSION 3
#if BOOST_VERSION > 105000
#define BOOST_THREAD_VERSION 3
# define BOOST_THREAD_VERSION 3
#endif
#define BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE 1
#define BOOST_BIND_NO_PLACEHOLDERS
@ -99,9 +147,12 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/format.hpp>
#include <boost/functional/hash.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/locale/generator.hpp>
#include <boost/logic/tribool.hpp>
#include <boost/optional.hpp>
#include <boost/program_options.hpp>
@ -112,13 +163,8 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#include <boost/variant.hpp>
#include <boost/math/special_functions/round.hpp>
#ifdef ANDROID
#include <android/log.h>
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
# define M_PI 3.14159265358979323846
#endif
/* ---------------------------------------------------------------------------- */
@ -151,30 +197,20 @@ typedef boost::lock_guard<boost::recursive_mutex> TLockGuardRec;
/* Macros */
/* ---------------------------------------------------------------------------- */
// Import + Export macro declarations
#ifdef _WIN32
#ifdef VCMI_WINDOWS
# ifdef __GNUC__
# define DLL_IMPORT __attribute__((dllimport))
# define DLL_EXPORT __attribute__((dllexport))
# else
# define DLL_IMPORT __declspec(dllimport)
# define DLL_EXPORT __declspec(dllexport)
# endif
# define ELF_VISIBILITY
#else
# ifdef __GNUC__
# define DLL_IMPORT __attribute__ ((visibility("default")))
# define DLL_EXPORT __attribute__ ((visibility("default")))
# define ELF_VISIBILITY __attribute__ ((visibility("default")))
# endif
#endif
#ifdef _WIN32
# ifdef __GNUC__
# define DLL_IMPORT __attribute__((dllimport))
# else
# define DLL_IMPORT __declspec(dllimport)
# endif
# define ELF_VISIBILITY
#else
# ifdef __GNUC__
# define DLL_IMPORT __attribute__ ((visibility("default")))
# define ELF_VISIBILITY __attribute__ ((visibility("default")))
# endif
#endif

View File

@ -41,7 +41,7 @@
#include "../lib/logging/CBasicLogConfigurator.h"
#include "../lib/CondSh.h"
#ifdef _WIN32
#ifdef VCMI_WINDOWS
#include "SDL_syswm.h"
#endif
#include "../lib/UnlockGuard.h"
@ -52,6 +52,7 @@
#endif
namespace po = boost::program_options;
namespace bfs = boost::filesystem;
/*
* CMT.cpp, part of VCMI engine
@ -73,13 +74,12 @@ int preferredDriverIndex = -1;
SDL_Window * mainWindow = nullptr;
SDL_Renderer * mainRenderer = nullptr;
SDL_Texture * screenTexture = nullptr;
#endif // VCMI_SDL1
extern boost::thread_specific_ptr<bool> inGuiThread;
SDL_Surface *screen = nullptr, //main screen surface
*screen2 = nullptr,//and hlp surface (used to store not-active interfaces layer)
*screen2 = nullptr, //and hlp surface (used to store not-active interfaces layer)
*screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
std::queue<SDL_Event> events;
@ -100,31 +100,29 @@ static void mainLoop();
void startGame(StartInfo * options, CConnection *serv = nullptr);
void endGame();
#ifndef _WIN32
#ifndef VCMI_WINDOWS
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <getopt.h>
#endif
void startGameFromFile(const std::string &fname)
void startGameFromFile(const bfs::path &fname)
{
StartInfo si;
try //attempt retrieving start info from given file
{
if(!fname.size() || !boost::filesystem::exists(fname))
throw std::runtime_error("Startfile \"" + fname + "\" does not exist!");
if(fname.empty() || !bfs::exists(fname))
throw std::runtime_error("Startfile \"" + fname.string() + "\" does not exist!");
CLoadFile out(fname);
if(!out.sfile || !*out.sfile)
{
throw std::runtime_error("Cannot read from startfile \"" + fname + "\"!");
}
if (!out.sfile || !*out.sfile)
throw std::runtime_error("Cannot read from startfile \"" + fname.string() +"\"!");
out >> si;
}
catch(std::exception &e)
{
logGlobal->errorStream() << "Failed to start from the file: " + fname << ". Error: " << e.what()
logGlobal->errorStream() << "Failed to start from the file: " << fname << ". Error: " << e.what()
<< " Falling back to main menu.";
GH.curInt = CGPreGame::create();
return;
@ -184,19 +182,19 @@ static void prog_help(const po::options_description &opts)
// printf(" -v, --version display version information and exit\n");
}
#ifdef __APPLE__
#ifdef VCMI_APPLE
void OSX_checkForUpdates();
#endif
#if defined(_WIN32) && !defined (__GNUC__)
#if defined(VCMI_WINDOWS) && !defined (__GNUC__)
int wmain(int argc, wchar_t* argv[])
#elif defined(__APPLE__)
#elif defined(VCMI_APPLE)
int SDL_main(int argc, char *argv[])
#else
int main(int argc, char** argv)
#endif
{
#ifdef __APPLE__
#ifdef VCMI_APPLE
// Correct working dir executable folder (not bundle folder) so we can use executable relative paths
std::string executablePath = argv[0];
std::string workDir = executablePath.substr(0, executablePath.rfind('/'));
@ -206,7 +204,7 @@ int main(int argc, char** argv)
OSX_checkForUpdates();
// Check that game data is prepared. Otherwise run vcmibuilder helper application
FILE* check = fopen((VCMIDirs::get().userDataPath() + "/game_data_prepared").c_str(), "r");
FILE* check = fopen((VCMIDirs::get().userDataPath() / "game_data_prepared").string().c_str(), "r");
if (check == nullptr) {
system("open ./vcmibuilder.app");
return 0;
@ -219,7 +217,7 @@ int main(int argc, char** argv)
("help,h", "display help and exit")
("version,v", "display version information and exit")
("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only")
("start", po::value<std::string>(), "starts game from saved StartInfo file")
("start", po::value<bfs::path>(), "starts game from saved StartInfo file")
("onlyAI", "runs without human player, all players will be default AI")
("noGUI", "runs without GUI, implies --onlyAI")
("ai", po::value<std::vector<std::string>>(), "AI to be used for the player, can be specified several times for the consecutive players")
@ -272,17 +270,17 @@ int main(int argc, char** argv)
CStopWatch total, pomtime;
std::cout.flags(std::ios::unitbuf);
console = new CConsoleHandler;
*console->cb = std::bind(&processCommand, _1);
*console->cb = processCommand;
console->start();
atexit(dispose);
const auto logPath = VCMIDirs::get().userCachePath() + "/VCMI_Client_log.txt";
const bfs::path logPath = VCMIDirs::get().userCachePath() / "VCMI_Client_log.txt";
CBasicLogConfigurator logConfig(logPath, console);
logConfig.configureDefault();
logGlobal->infoStream() << "Creating console and configuring logger: " << pomtime.getDiff();
logGlobal->infoStream() << "The log file will be saved to " << logPath;
#ifdef __ANDROID__
#ifdef VCMI_ANDROID
// boost will crash without this
setenv("LANG", "C", 1);
#endif
@ -388,7 +386,7 @@ int main(int argc, char** argv)
logGlobal->infoStream()<<"\tInitializing video: "<<pomtime.getDiff();
#if defined(__ANDROID__)
#if defined(VCMI_ANDROID)
//on Android threaded init is broken
#define VCMI_NO_THREADED_LOAD
#endif // defined
@ -430,15 +428,15 @@ int main(int argc, char** argv)
session["autoSkip"].Bool() = vm.count("autoSkip");
session["oneGoodAI"].Bool() = vm.count("oneGoodAI");
std::string fileToStartFrom; //none by default
bfs::path fileToStartFrom; //none by default
if(vm.count("start"))
fileToStartFrom = vm["start"].as<std::string>();
fileToStartFrom = vm["start"].as<bfs::path>();
if(fileToStartFrom.size() && boost::filesystem::exists(fileToStartFrom))
if(!fileToStartFrom.empty() && bfs::exists(fileToStartFrom))
startGameFromFile(fileToStartFrom); //ommit pregame and start the game using settings from file
else
{
if(fileToStartFrom.size())
if(!fileToStartFrom.empty())
{
logGlobal->warnStream() << "Warning: cannot find given file to start from (" << fileToStartFrom
<< "). Falling back to main menu.";
@ -584,7 +582,8 @@ void processCommand(const std::string &message)
{
std::cout<<"Command accepted.\t";
std::string outPath = VCMIDirs::get().userCachePath() + "/extracted/";
const bfs::path outPath =
VCMIDirs::get().userCachePath() / "extracted";
auto list = CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident)
{
@ -593,18 +592,18 @@ void processCommand(const std::string &message)
for (auto & filename : list)
{
std::string outName = outPath + filename.getName();
const bfs::path filePath = outPath / (filename.getName() + ".TXT");
bfs::create_directories(filePath.parent_path());
boost::filesystem::create_directories(outName.substr(0, outName.find_last_of("/")));
std::ofstream file(outName + ".TXT");
bfs::ofstream file(filePath);
auto text = CResourceHandler::get()->load(filename)->readAll();
file.write((char*)text.first.get(), text.second);
}
std::cout << "\rExtracting done :)\n";
std::cout << " Extracted files can be found in " << outPath << " directory\n";
std::cout << " Extracted files can be found in " << outPath << " directory\n";
}
else if(cn=="crash")
{
@ -710,15 +709,13 @@ void processCommand(const std::string &message)
{
CDefEssential * cde = CDefHandler::giveDefEss(URI);
std::string outName = URI;
std::string outPath = VCMIDirs::get().userCachePath() + "/extracted/";
const bfs::path outPath = VCMIDirs::get().userCachePath() / "extracted" / URI;
bfs::create_directories(outPath);
boost::filesystem::create_directories(outPath + outName);
for (size_t i=0; i<cde->ourImages.size(); i++)
for (size_t i = 0; i < cde->ourImages.size(); ++i)
{
std::string filename = outPath + outName + '/' + boost::lexical_cast<std::string>(i) + ".bmp";
SDL_SaveBMP(cde->ourImages[i].bitmap, filename.c_str());
const bfs::path filePath = outPath / (boost::lexical_cast<std::string>(i)+".bmp");
SDL_SaveBMP(cde->ourImages[i].bitmap, filePath.string().c_str());
}
}
else
@ -731,14 +728,12 @@ void processCommand(const std::string &message)
if (CResourceHandler::get()->existsResource(ResourceID(URI)))
{
std::string outName = URI;
std::string outPath = VCMIDirs::get().userCachePath() + "/extracted/";
std::string fullPath = outPath + outName;
const bfs::path outPath = VCMIDirs::get().userCachePath() / "extracted" / URI;
auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
boost::filesystem::create_directories(fullPath.substr(0, fullPath.find_last_of("/")));
std::ofstream outFile(outPath + outName, std::ofstream::binary);
bfs::create_directories(outPath.parent_path());
bfs::ofstream outFile(outPath, bfs::ofstream::binary);
outFile.write((char*)data.first.get(), data.second);
}
else
@ -1013,7 +1008,7 @@ static void setScreenRes(int w, int h, int bpp, bool fullscreen, bool resetVideo
SDL_ShowCursor(SDL_DISABLE);
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
#ifdef _WIN32
#ifdef VCMI_WINDOWS
SDL_SysWMinfo wm;
SDL_VERSION(&wm.version);
int getwm = SDL_GetWMInfo(&wm);

View File

@ -42,13 +42,6 @@
#include "../lib/UnlockGuard.h"
#include <SDL.h>
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
/*
* CPlayerInterface.cpp, part of VCMI engine
*
@ -1622,22 +1615,20 @@ int CPlayerInterface::getLastIndex( std::string namePrefix)
path gamesDir = VCMIDirs::get().userSavePath();
std::map<std::time_t, int> dates; //save number => datestamp
directory_iterator enddir;
const directory_iterator enddir;
if(!exists(gamesDir))
create_directory(gamesDir);
for (directory_iterator dir(gamesDir); dir!=enddir; dir++)
else
for (directory_iterator dir(gamesDir); dir != enddir; ++dir)
{
if(is_regular(dir->status()))
{
std::string name = dir->path().leaf().string();
std::string name = dir->path().filename().string();
if(starts_with(name, namePrefix) && ends_with(name, ".vcgm1"))
{
char nr = name[namePrefix.size()];
if(std::isdigit(nr))
{
dates[last_write_time(dir->path())] = boost::lexical_cast<int>(nr);
}
}
}
}

View File

@ -23,7 +23,7 @@ static bool keyDown()
}
#endif
#if defined(_WIN32) && (_MSC_VER < 1800 || !defined(USE_FFMPEG))
#if defined(VCMI_WINDOWS) && (_MSC_VER < 1800 || !defined(USE_FFMPEG))
void checkForError(bool throwing = true)
{

View File

@ -43,9 +43,8 @@ public:
};
#if defined(_WIN32) && (_MSC_VER < 1800 || !defined(USE_FFMPEG))
#if defined(VCMI_WINDOWS) && (_MSC_VER < 1800 || !defined(USE_FFMPEG))
#define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing
#include <windows.h>
#pragma pack(push,1)

View File

@ -20,7 +20,7 @@
#include "../lib/CBuildingHandler.h"
#include "../lib/CSpellHandler.h"
#include "../lib/Connection.h"
#ifndef __ANDROID__
#ifndef VCMI_ANDROID
#include "../lib/Interprocess.h"
#endif
#include "../lib/NetPacks.h"
@ -40,7 +40,7 @@
#include "CMT.h"
extern std::string NAME;
#ifndef __ANDROID__
#ifndef VCMI_ANDROID
namespace intpr = boost::interprocess;
#endif
@ -780,8 +780,9 @@ std::string CClient::aiNameForPlayer(const PlayerSettings &ps, bool battleAI)
{
if(ps.name.size())
{
std::string filename = VCMIDirs::get().libraryPath() + "/AI/" + VCMIDirs::get().libraryName(ps.name);
if(boost::filesystem::exists(filename))
const boost::filesystem::path aiPath =
VCMIDirs::get().libraryPath() / "AI" / VCMIDirs::get().libraryName(ps.name);
if (boost::filesystem::exists(aiPath))
return ps.name;
}
@ -814,7 +815,7 @@ void CServerHandler::waitForServer()
startServer();
th.update();
#ifndef __ANDROID__
#ifndef VCMI_ANDROID
intpr::scoped_lock<intpr::interprocess_mutex> slock(shared->sr->mutex);
while(!shared->sr->ready)
{
@ -827,7 +828,7 @@ void CServerHandler::waitForServer()
CConnection * CServerHandler::connectToServer()
{
#ifndef __ANDROID__
#ifndef VCMI_ANDROID
if(!shared->sr->ready)
waitForServer();
#else
@ -850,7 +851,7 @@ CServerHandler::CServerHandler(bool runServer /*= false*/)
port = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
verbose = true;
#ifndef __ANDROID__
#ifndef VCMI_ANDROID
boost::interprocess::shared_memory_object::remove("vcmi_memory"); //if the application has previously crashed, the memory may not have been removed. to avoid problems - try to destroy it
try
{
@ -868,8 +869,8 @@ CServerHandler::~CServerHandler()
void CServerHandler::callServer()
{
setThreadName("CServerHandler::callServer");
std::string logName = VCMIDirs::get().userCachePath() + "/server_log.txt";
std::string comm = VCMIDirs::get().serverPath() + " --port=" + port + " > " + logName;
const std::string logName = (VCMIDirs::get().userCachePath() / "server_log.txt").string();
const std::string comm = VCMIDirs::get().serverPath().string() + " --port=" + port + " > \"" + logName + '\"';
int result = std::system(comm.c_str());
if (result == 0)
logNetwork->infoStream() << "Server closed correctly";

View File

@ -13,7 +13,7 @@ Editor::Editor(QWidget *parent)
{
// Setup default logging(enough for now)
console = new CConsoleHandler;
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Editor_log.txt", console);
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() / "VCMI_Editor_log.txt", console);
logConfig.configureDefault();
preinitDLL(console);

View File

@ -8,4 +8,13 @@
#include <QVector>
#include <QList>
#include <QString>
#include <QFile>
#include <QFile>
inline QString pathToQString(const boost::filesystem::path & path)
{
#ifdef VCMI_WINDOWS
return QString::fromStdWString(path.wstring());
#else
return QString::fromStdString(path.string());
#endif
}

View File

@ -18,10 +18,10 @@ CLauncherDirs & CLauncherDirs::get()
QString CLauncherDirs::downloadsPath()
{
return QString::fromUtf8(VCMIDirs::get().userCachePath().c_str()) + "/downloads";
return pathToQString(VCMIDirs::get().userCachePath() / "downloads");
}
QString CLauncherDirs::modsPath()
{
return QString::fromUtf8(VCMIDirs::get().userDataPath().c_str()) + "/Mods";
return pathToQString(VCMIDirs::get().userDataPath() / "Mods");
}

View File

@ -13,15 +13,15 @@
void MainWindow::load()
{
console = new CConsoleHandler;
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Launcher_log.txt", console);
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() / "VCMI_Launcher_log.txt", console);
logConfig.configureDefault();
CResourceHandler::initialize();
CResourceHandler::load("config/filesystem.json");
for (auto & string : VCMIDirs::get().dataPaths())
QDir::addSearchPath("icons", QString::fromUtf8(string.c_str()) + "/launcher/icons");
QDir::addSearchPath("icons", QString::fromUtf8(VCMIDirs::get().userDataPath().c_str()) + "/launcher/icons");
QDir::addSearchPath("icons", pathToQString(string / "launcher" / "icons"));
QDir::addSearchPath("icons", pathToQString(VCMIDirs::get().userDataPath() / "launcher" / "icons"));
settings.init();
}
@ -46,7 +46,7 @@ MainWindow::~MainWindow()
void MainWindow::on_startGameButon_clicked()
{
startExecutable(QString::fromUtf8(VCMIDirs::get().clientPath().c_str()));
startExecutable(pathToQString(VCMIDirs::get().clientPath()));
}
void MainWindow::startExecutable(QString name)

View File

@ -39,7 +39,7 @@ CModManager::CModManager(CModList * modList):
QString CModManager::settingsPath()
{
return QString::fromUtf8(VCMIDirs::get().userConfigPath().c_str()) + "/modSettings.json";
return pathToQString(VCMIDirs::get().userConfigPath() / "modSettings.json");
}
void CModManager::loadModSettings()

View File

@ -46,9 +46,9 @@ void CSettingsView::loadSettings()
for (auto entry : urls.Vector())
ui->plainTextEditRepos->appendPlainText(QString::fromUtf8(entry.String().c_str()));
ui->lineEditUserDataDir->setText(QString::fromUtf8(VCMIDirs::get().userDataPath().c_str()));
ui->lineEditGameDir->setText(QString::fromUtf8(M_DATA_DIR));
ui->lineEditTempDir->setText(QString::fromUtf8(VCMIDirs::get().userCachePath().c_str()));
ui->lineEditUserDataDir->setText(pathToQString(VCMIDirs::get().userDataPath()));
ui->lineEditGameDir->setText(pathToQString(VCMIDirs::get().binaryPath()));
ui->lineEditTempDir->setText(pathToQString(VCMIDirs::get().userCachePath()));
std::string encoding = settings["general"]["encoding"].String();
size_t encodingIndex = boost::range::find(knownEncodingsList, encoding) - knownEncodingsList;

View File

@ -44,18 +44,6 @@ BattleHex& BattleHex::moveInDir(EDir dir, bool hasToBeValid)
return *this;
}
void BattleHex::operator+=(EDir dir)
{
moveInDir(dir);
}
BattleHex BattleHex::operator+(EDir dir) const
{
BattleHex ret(*this);
ret += dir;
return ret;
}
std::vector<BattleHex> BattleHex::neighbouringTiles() const
{
std::vector<BattleHex> ret;
@ -93,17 +81,18 @@ char BattleHex::getDistance(BattleHex hex1, BattleHex hex2)
{
int y1 = hex1.getY(),
y2 = hex2.getY();
int x1 = hex1.getX() + y1 / 2.0,
x2 = hex2.getX() + y2 / 2.0;
// FIXME: Omit floating point arithmetics
int x1 = (int)(hex1.getX() + y1 * 0.5),
x2 = (int)(hex2.getX() + y2 * 0.5);
int xDst = x2 - x1,
yDst = y2 - y1;
if ((xDst >= 0 && yDst >= 0) || (xDst < 0 && yDst < 0))
return std::max(std::abs(xDst), std::abs(yDst));
else
return std::abs(xDst) + std::abs(yDst);
return std::abs(xDst) + std::abs(yDst);
}
void BattleHex::checkAndPush(BattleHex tile, std::vector<BattleHex> & ret)

View File

@ -17,22 +17,16 @@
struct DLL_LINKAGE BattleHex
{
static const si16 INVALID = -1;
enum EDir{RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, LEFT, TOP_LEFT, TOP_RIGHT};
enum EDir { RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, LEFT, TOP_LEFT, TOP_RIGHT };
si16 hex;
BattleHex() : hex(INVALID) {}
BattleHex(si16 _hex) : hex(_hex) {}
operator si16() const
{
return hex;
}
operator si16() const { return hex; }
bool isValid() const
{
return hex >= 0 && hex < GameConstants::BFIELD_SIZE;
}
bool isValid() const { return hex >= 0 && hex < GameConstants::BFIELD_SIZE; }
template<typename inttype>
BattleHex(inttype x, inttype y)
@ -61,9 +55,7 @@ struct DLL_LINKAGE BattleHex
void setXY(si16 x, si16 y, bool hasToBeValid = true)
{
if(hasToBeValid)
{
assert(x >= 0 && x < GameConstants::BFIELD_WIDTH && y >= 0 && y < GameConstants::BFIELD_HEIGHT);
}
assert(x >= 0 && x < GameConstants::BFIELD_WIDTH && y >= 0 && y < GameConstants::BFIELD_HEIGHT);
hex = x + y * GameConstants::BFIELD_WIDTH;
}
@ -73,28 +65,23 @@ struct DLL_LINKAGE BattleHex
setXY(xy.first, xy.second);
}
si16 getY() const
{
return hex / GameConstants::BFIELD_WIDTH;
}
si16 getY() const { return hex / GameConstants::BFIELD_WIDTH; }
si16 getX() const { return hex % GameConstants::BFIELD_WIDTH; }
si16 getX() const
{
int pos = hex - getY() * GameConstants::BFIELD_WIDTH;
return pos;
}
std::pair<si16, si16> getXY() const
{
return std::make_pair(getX(), getY());
}
std::pair<si16, si16> getXY() const { return std::make_pair(getX(), getY()); }
//moving to direction
BattleHex& moveInDir(EDir dir, bool hasToBeValid = true);
void operator+=(EDir dir); //sugar for above
BattleHex& operator+=(EDir dir) { return moveInDir(dir); } //sugar for above
//generates new BattleHex moved by given dir
BattleHex operator+(EDir dir) const;
BattleHex movedInDir(EDir dir, bool hasToBeValid = true) const
{
BattleHex result(*this);
result.moveInDir(dir, hasToBeValid);
return result;
}
BattleHex operator+(EDir dir) const { return movedInDir(dir); }
std::vector<BattleHex> neighbouringTiles() const;

View File

@ -17,7 +17,7 @@ boost::mutex CConsoleHandler::smx;
DLL_LINKAGE CConsoleHandler * console = nullptr;
#ifndef _WIN32
#ifndef VCMI_WINDOWS
typedef std::string TColor;
#define CONSOLE_GREEN "\x1b[1;32m"
#define CONSOLE_RED "\x1b[1;31m"
@ -27,7 +27,6 @@ DLL_LINKAGE CConsoleHandler * console = nullptr;
#define CONSOLE_GRAY "\x1b[1;30m"
#define CONSOLE_TEAL "\x1b[1;36m"
#else
#define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing
#include <Windows.h>
#ifndef __MINGW32__
#include <dbghelp.h>
@ -36,6 +35,7 @@ DLL_LINKAGE CConsoleHandler * console = nullptr;
typedef WORD TColor;
HANDLE handleIn;
HANDLE handleOut;
HANDLE handleErr;
#define CONSOLE_GREEN FOREGROUND_GREEN | FOREGROUND_INTENSITY
#define CONSOLE_RED FOREGROUND_RED | FOREGROUND_INTENSITY
#define CONSOLE_MAGENTA FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY
@ -43,11 +43,13 @@ DLL_LINKAGE CConsoleHandler * console = nullptr;
#define CONSOLE_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
#define CONSOLE_GRAY FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
#define CONSOLE_TEAL FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
static TColor defErrColor;
#endif
static TColor defColor;
#ifdef _WIN32
#ifdef VCMI_WINDOWS
void printWinError()
{
@ -178,8 +180,11 @@ void CConsoleHandler::setColor(EConsoleTextColor::EConsoleTextColor color)
colorCode = defColor;
break;
}
#ifdef _WIN32
#ifdef VCMI_WINDOWS
SetConsoleTextAttribute(handleOut, colorCode);
if (color == EConsoleTextColor::DEFAULT)
colorCode = defErrColor;
SetConsoleTextAttribute(handleErr, colorCode);
#else
std::cout << colorCode;
#endif
@ -194,7 +199,7 @@ int CConsoleHandler::run()
while ( std::cin.good() )
{
#ifndef _WIN32
#ifndef VCMI_WINDOWS
//check if we have some unreaded symbols
if (std::cin.rdbuf()->in_avail())
{
@ -216,12 +221,17 @@ int CConsoleHandler::run()
}
CConsoleHandler::CConsoleHandler() : thread(nullptr)
{
#ifdef _WIN32
#ifdef VCMI_WINDOWS
handleIn = GetStdHandle(STD_INPUT_HANDLE);
handleOut = GetStdHandle(STD_OUTPUT_HANDLE);
handleErr = GetStdHandle(STD_ERROR_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(handleOut,&csbi);
defColor = csbi.wAttributes;
GetConsoleScreenBufferInfo(handleErr, &csbi);
defErrColor = csbi.wAttributes;
#ifndef _DEBUG
SetUnhandledExceptionFilter(onUnhandledException);
#endif
@ -241,7 +251,7 @@ void CConsoleHandler::end()
{
if (thread)
{
#ifndef _WIN32
#ifndef VCMI_WINDOWS
thread->interrupt();
#else
TerminateThread(thread->native_handle(),0);

View File

@ -38,7 +38,7 @@ public:
template<typename T> void print(const T &data, bool addNewLine = false, EConsoleTextColor::EConsoleTextColor color = EConsoleTextColor::DEFAULT, bool printToStdErr = false)
{
TLockGuard _(smx);
#ifndef _WIN32
#ifndef VCMI_WINDOWS
// with love from ffmpeg - library is trying to print some warnings from separate thread
// this results in broken console on Linux. Lock stdout to print all our data at once
flockfile(stdout);
@ -70,7 +70,7 @@ public:
}
if(color != EConsoleTextColor::DEFAULT) setColor(EConsoleTextColor::DEFAULT);
#ifndef _WIN32
#ifndef VCMI_WINDOWS
funlockfile(stdout);
#endif
}

View File

@ -4,8 +4,7 @@
#include "BattleState.h"
#include "VCMIDirs.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing
#ifdef VCMI_WINDOWS
#include <windows.h> //for .dll libs
#else
#include <dlfcn.h>
@ -22,7 +21,7 @@
*
*/
#ifdef __ANDROID__
#ifdef VCMI_ANDROID
// we can't use shared libraries on Android so here's a hack
extern "C" DLL_EXPORT void VCAI_GetAiName(char* name);
extern "C" DLL_EXPORT void VCAI_GetNewAI(shared_ptr<CGlobalAI> &out);
@ -35,7 +34,7 @@ extern "C" DLL_EXPORT void BattleAI_GetNewBattleAI(shared_ptr<CBattleGameInterfa
#endif
template<typename rett>
shared_ptr<rett> createAny(std::string dllname, std::string methodName)
shared_ptr<rett> createAny(const boost::filesystem::path& libpath, const std::string& methodName)
{
typedef void(*TGetAIFun)(shared_ptr<rett>&);
typedef void(*TGetNameFun)(char*);
@ -45,56 +44,60 @@ shared_ptr<rett> createAny(std::string dllname, std::string methodName)
TGetAIFun getAI = nullptr;
TGetNameFun getName = nullptr;
#ifdef __ANDROID__
#ifdef VCMI_ANDROID
// this is awful but it seems using shared libraries on some devices is even worse
if (dllname.find("libVCAI.so") != std::string::npos) {
const std::string filename = libpath.filename().string();
if (filename == "libVCAI.so")
{
getName = (TGetNameFun)VCAI_GetAiName;
getAI = (TGetAIFun)VCAI_GetNewAI;
} else if (dllname.find("libStupidAI.so") != std::string::npos) {
}
else if (filename == "libStupidAI.so")
{
getName = (TGetNameFun)StupidAI_GetAiName;
getAI = (TGetAIFun)StupidAI_GetNewBattleAI;
} else if (dllname.find("libBattleAI.so") != std::string::npos) {
}
else if (filename == "libBattleAI.so")
{
getName = (TGetNameFun)BattleAI_GetAiName;
getAI = (TGetAIFun)BattleAI_GetNewBattleAI;
} else {
throw std::runtime_error("Don't know what to do with " + dllname + " and method " + methodName);
}
#else
#ifdef _WIN32
HINSTANCE dll = LoadLibraryA(dllname.c_str());
else
throw std::runtime_error("Don't know what to do with " + libpath.string() + " and method " + methodName);
#else // !VCMI_ANDROID
#ifdef VCMI_WINDOWS
HMODULE dll = LoadLibraryW(libpath.c_str());
if (dll)
{
getName = (TGetNameFun)GetProcAddress(dll,"GetAiName");
getAI = (TGetAIFun)GetProcAddress(dll,methodName.c_str());
getName = (TGetNameFun)GetProcAddress(dll, "GetAiName");
getAI = (TGetAIFun)GetProcAddress(dll, methodName.c_str());
}
#else
void *dll = dlopen(dllname.c_str(), RTLD_LOCAL | RTLD_LAZY);
#else // !VCMI_WINDOWS
void *dll = dlopen(libpath.string().c_str(), RTLD_LOCAL | RTLD_LAZY);
if (dll)
{
getName = (TGetNameFun)dlsym(dll,"GetAiName");
getAI = (TGetAIFun)dlsym(dll,methodName.c_str());
getName = (TGetNameFun)dlsym(dll, "GetAiName");
getAI = (TGetAIFun)dlsym(dll, methodName.c_str());
}
else
logGlobal->errorStream() << "Error: " << dlerror();
#endif
#endif // VCMI_WINDOWS
if (!dll)
{
logGlobal->errorStream() << "Cannot open dynamic library ("<<dllname<<"). Throwing...";
logGlobal->errorStream() << "Cannot open dynamic library ("<<libpath<<"). Throwing...";
throw std::runtime_error("Cannot open dynamic library");
}
else if(!getName || !getAI)
{
logGlobal->errorStream() << dllname << " does not export method " << methodName;
#ifdef _WIN32
logGlobal->errorStream() << libpath << " does not export method " << methodName;
#ifdef VCMI_WINDOWS
FreeLibrary(dll);
#else
dlclose(dll);
#endif
throw std::runtime_error("Cannot find method " + methodName);
}
#endif // __ANDROID__
#endif // VCMI_ANDROID
getName(temp);
logGlobal->infoStream() << "Loaded " << temp;
@ -108,13 +111,13 @@ shared_ptr<rett> createAny(std::string dllname, std::string methodName)
}
template<typename rett>
shared_ptr<rett> createAnyAI(std::string dllname, std::string methodName)
shared_ptr<rett> createAnyAI(std::string dllname, const std::string& methodName)
{
logGlobal->infoStream() << "Opening " << dllname;
std::string filename = VCMIDirs::get().libraryName(dllname);
auto ret = createAny<rett>(VCMIDirs::get().libraryPath() + "/AI/" + filename, methodName);
ret->dllName = dllname;
logGlobal->infoStream() << "Opening " << dllname;
const boost::filesystem::path filePath =
VCMIDirs::get().libraryPath() / "AI" / VCMIDirs::get().libraryName(dllname);
auto ret = createAny<rett>(filePath, methodName);
ret->dllName = std::move(dllname);
return ret;
}

View File

@ -1,9 +1,9 @@
#include "StdInc.h"
#include "CThreadHelper.h"
#ifdef _WIN32
#ifdef VCMI_WINDOWS
#include <windows.h>
#elif !defined(__APPLE__)
#elif !defined(VCMI_APPLE)
#include <sys/prctl.h>
#endif
/*
@ -49,7 +49,7 @@ void CThreadHelper::processTasks()
// NOTE: on *nix string will be trimmed to 16 symbols
void setThreadName(const std::string &name)
{
#ifdef _WIN32
#ifdef VCMI_WINDOWS
#ifndef __GNUC__
//follows http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
const DWORD MS_VC_EXCEPTION=0x406D1388;

View File

@ -17,50 +17,48 @@ template <typename T> struct CondSh
boost::condition_variable cond;
boost::mutex mx;
CondSh()
{}
CondSh(T t)
{
data = t;
}
CondSh() {}
CondSh(T t) : data(t) {}
// set data
void set(T t)
{
boost::unique_lock<boost::mutex> lock(mx);
data=t;
data = t;
}
void setn(T t) //set data and notify
// set data and notify
void setn(T t)
{
{
boost::unique_lock<boost::mutex> lock(mx);
data=t;
}
set(t);
cond.notify_all();
};
T get() //get stored value
// get stored value
T get()
{
boost::unique_lock<boost::mutex> lock(mx);
return data;
}
void waitWhileTrue() //waits until data is set to false
// waits until data is set to false
void waitWhileTrue()
{
boost::unique_lock<boost::mutex> un(mx);
while(data)
cond.wait(un);
}
void waitWhile(const T &t) //waits while data is set to arg
// waits while data is set to arg
void waitWhile(const T & t)
{
boost::unique_lock<boost::mutex> un(mx);
while(data == t)
cond.wait(un);
}
void waitUntil(const T &t) //waits until data is set to arg
// waits until data is set to arg
void waitUntil(const T & t)
{
boost::unique_lock<boost::mutex> un(mx);
while(data != t)

View File

@ -347,7 +347,7 @@ void CSaveFile::putMagicBytes( const std::string &text )
write(text.c_str(), text.length());
}
CLoadFile::CLoadFile(const std::string &fname, int minimalVersion /*= version*/)
CLoadFile::CLoadFile(const boost::filesystem::path & fname, int minimalVersion /*= version*/)
{
registerTypes(*this);
openNextFile(fname, minimalVersion);
@ -363,33 +363,33 @@ int CLoadFile::read(void * data, unsigned size)
return size;
}
void CLoadFile::openNextFile(const std::string &fname, int minimalVersion)
void CLoadFile::openNextFile(const boost::filesystem::path & fname, int minimalVersion)
{
assert(!reverseEndianess);
assert(minimalVersion <= version);
try
{
fName = fname;
sfile = make_unique<std::ifstream>(fname, std::ios::binary);
fName = fname.string();
sfile = make_unique<boost::filesystem::ifstream>(fname, std::ios::binary);
sfile->exceptions(std::ifstream::failbit | std::ifstream::badbit); //we throw a lot anyway
if(!(*sfile))
THROW_FORMAT("Error: cannot open to read %s!", fname);
THROW_FORMAT("Error: cannot open to read %s!", fName);
//we can read
char buffer[4];
sfile->read(buffer, 4);
if(std::memcmp(buffer,"VCMI",4))
THROW_FORMAT("Error: not a VCMI file(%s)!", fname);
THROW_FORMAT("Error: not a VCMI file(%s)!", fName);
*this >> fileVersion;
if(fileVersion < minimalVersion)
THROW_FORMAT("Error: too old file format (%s)!", fname);
THROW_FORMAT("Error: too old file format (%s)!", fName);
if(fileVersion > version)
{
logGlobal->warnStream() << boost::format("Warning format version mismatch: found %d when current is %d! (file %s)\n") % fileVersion % version % fname;
logGlobal->warnStream() << boost::format("Warning format version mismatch: found %d when current is %d! (file %s)\n") % fileVersion % version % fName;
auto versionptr = (char*)&fileVersion;
std::reverse(versionptr, versionptr + 4);
@ -401,7 +401,7 @@ void CLoadFile::openNextFile(const std::string &fname, int minimalVersion)
reverseEndianess = true;
}
else
THROW_FORMAT("Error: too new file format (%s)!", fname);
THROW_FORMAT("Error: too new file format (%s)!", fName);
}
}
catch(...)

View File

@ -1530,17 +1530,17 @@ class DLL_LINKAGE CLoadFile
public:
std::string fName;
unique_ptr<std::ifstream> sfile;
unique_ptr<boost::filesystem::ifstream> sfile;
CLoadFile(const std::string &fname, int minimalVersion = version); //throws!
CLoadFile(const boost::filesystem::path & fname, int minimalVersion = version); //throws!
~CLoadFile();
int read(void * data, unsigned size); //throws!
void openNextFile(const std::string &fname, int minimalVersion); //throws!
void openNextFile(const boost::filesystem::path & fname, int minimalVersion); //throws!
void clear();
void reportState(CLogger * out);
void checkMagicBytes(const std::string &text);
void checkMagicBytes(const std::string & text);
};
class DLL_LINKAGE CLoadIntegrityValidator : public CISer<CLoadIntegrityValidator>

View File

@ -1,6 +1,3 @@
#include "StdInc.h"
#include "VCMIDirs.h"
/*
* VCMIDirs.cpp, part of VCMI engine
*
@ -11,216 +8,504 @@
*
*/
static VCMIDirs VCMIDirsGlobal;
#include "StdInc.h"
#include "VCMIDirs.h"
VCMIDirs::VCMIDirs()
namespace bfs = boost::filesystem;
bfs::path IVCMIDirs::userSavePath() const { return userDataPath() / "Saves"; }
void IVCMIDirs::init()
{
// initialize local directory and create folders to which VCMI needs write access
boost::filesystem::create_directory(userDataPath());
boost::filesystem::create_directory(userCachePath());
boost::filesystem::create_directory(userConfigPath());
boost::filesystem::create_directory(userSavePath());
// TODO: Log errors
bfs::create_directory(userDataPath());
bfs::create_directory(userCachePath());
bfs::create_directory(userConfigPath());
bfs::create_directory(userSavePath());
}
VCMIDirs & VCMIDirs::get()
#ifdef VCMI_WINDOWS
#include <Windows.h>
#include <Shlobj.h>
#include <Shellapi.h>
// Generates script file named _temp.bat in 'to' directory and runs it
// Script will:
// - Wait util 'exeName' ends.
// - Copy all files from 'from' to 'to'
// - Ask user to replace files existed in 'to'.
// - Run 'exeName'
// - Delete itself.
bool StartBatchCopyDataProgram(
const bfs::path& from, const bfs::path& to, const bfs::path& exeName,
const bfs::path& currentPath = bfs::current_path())
{
return VCMIDirsGlobal;
static const char base[] =
"@echo off" "\n"
"echo Preparing to move VCMI data system." "\n"
":CLIENT_RUNNING_LOOP" "\n"
"TASKLIST | FIND /I %1% > nul" "\n"
"IF ERRORLEVEL 1 (" "\n"
"GOTO CLIENT_NOT_RUNNING" "\n"
") ELSE (" "\n"
"echo %1% is still running..." "\n"
"echo Waiting until process ends..." "\n"
"ping 1.1.1.1 -n 1 -w 3000 > nul" "\n" // Sleep ~3 seconds. I love Windows :)
"goto :CLIENT_RUNNING_LOOP" "\n"
")" "\n"
":CLIENT_NOT_RUNNING" "\n"
"echo %1% turned off..." "\n"
"echo Attempt to move datas." "\n"
"echo From: %2%" "\n"
"echo To: %4%" "\n"
"echo Please resolve any conflicts..." "\n"
"move /-Y %3% %4%" "\n" // Move all files from %3% to %4%.
// /-Y ask what to do when file exists in %4%
":REMOVE_OLD_DIR" "\n"
"rd %2% || rem" "\n" // Remove empty directory. Sets error flag if fail.
"IF ERRORLEVEL 145 (" "\n" // Directory not empty
"echo Directory %2% is not empty." "\n"
"echo Please move rest of files manually now." "\n"
"pause" "\n" // Press any key to continue...
"goto REMOVE_OLD_DIR" "\n"
")" "\n"
"echo Game data updated succefully." "\n"
"echo Please update your shortcuts." "\n"
"echo Press any key to start a game . . ." "\n"
"pause > nul" "\n"
"%5%" "\n"
"del \"%%~f0\"&exit" "\n" // Script deletes itself
;
const auto startGameString =
bfs::equivalent(currentPath, from) ?
(boost::format("start \"\" %1%") % (to / exeName)) : // Start game in new path.
(boost::format("start \"\" /D %1% %2%") % currentPath % (to / exeName)); // Start game in 'currentPath"
const bfs::path bathFilename = to / "_temp.bat";
bfs::ofstream bathFile(bathFilename, bfs::ofstream::trunc | bfs::ofstream::out);
if (!bathFile.is_open())
return false;
bathFile << (boost::format(base) % exeName % from % (from / "*.*") % to % startGameString.str()).str();
bathFile.close();
std::system(("start \"Updating VCMI datas\" /D \"" + to.string() + "\" \"" + bathFilename.string() + '\"').c_str());
// start won't block std::system
// /D start bat in other directory insteand of current directory.
return true;
}
//FIXME: find way to at least decrease size of this ifdef (along with cleanup in CMake)
#if defined(_WIN32)
std::string VCMIDirs::userCachePath() const
class VCMIDirsWIN32 : public IVCMIDirs
{
return userDataPath();
public:
boost::filesystem::path userDataPath() const override;
boost::filesystem::path userCachePath() const override;
boost::filesystem::path userConfigPath() const override;
std::vector<boost::filesystem::path> dataPaths() const override;
boost::filesystem::path clientPath() const override;
boost::filesystem::path serverPath() const override;
boost::filesystem::path libraryPath() const override;
boost::filesystem::path binaryPath() const override;
std::string libraryName(const std::string& basename) const override;
std::string genHelpString() const override;
void init() override;
protected:
boost::filesystem::path oldUserDataPath() const;
boost::filesystem::path oldUserSavePath() const;
};
void VCMIDirsWIN32::init()
{
// Call base (init dirs)
IVCMIDirs::init();
// Moves one directory (from) contents to another directory (to)
// Shows user the "moving file dialog" and ask to resolve conflits.
// If necessary updates current directory.
auto moveDirIfExists = [](const bfs::path& from, const bfs::path& to) -> bool
{
if (!bfs::is_directory(from))
return true; // Nothing to do here. Flies away.
if (bfs::is_empty(from))
{
if (bfs::current_path() == from)
bfs::current_path(to);
bfs::remove(from);
return true; // Nothing to do here. Flies away.
}
if (!bfs::is_directory(to))
{
// IVCMIDirs::init() should create all destination directories.
// TODO: Log fact, that we shouldn't be here.
bfs::create_directory(to);
}
// Why the hell path strings should be end with double null :/
auto makeDoubleNulled = [](const bfs::path& path) -> std::unique_ptr<wchar_t[]>
{
const std::wstring& pathStr = path.native();
std::unique_ptr<wchar_t[]> result(new wchar_t[pathStr.length() + 2]);
size_t i = 0;
for (const wchar_t ch : pathStr)
result[i++] = ch;
result[i++] = L'\0';
result[i++] = L'\0';
return result;
};
auto fromDNulled = makeDoubleNulled(from / L"*.*");
auto toDNulled = makeDoubleNulled(to);
SHFILEOPSTRUCTW fileOp;
fileOp.hwnd = GetConsoleWindow();
fileOp.wFunc = FO_MOVE;
fileOp.pFrom = fromDNulled.get();
fileOp.pTo = toDNulled.get();
fileOp.fFlags = 0;
fileOp.hNameMappings = nullptr;
fileOp.lpszProgressTitle = nullptr;
const int errorCode = SHFileOperationW(&fileOp);
if (errorCode != 0) // TODO: Log error. User should try to move files.
return false;
else if (fileOp.fAnyOperationsAborted) // TODO: Log warn. User aborted operation. User should move files.
return false;
else if (!bfs::is_empty(from)) // TODO: Log warn. Some files not moved. User should try to move files.
return false;
if (bfs::current_path() == from)
bfs::current_path(to);
// TODO: Log fact that we moved files succefully.
bfs::remove(from);
return true;
};
// Retrieves the fully qualified path for the file that contains the specified module.
// The module must have been loaded by the current process.
// If this parameter is nullptr, retrieves the path of the executable file of the current process.
auto getModulePath = [](HMODULE hModule) -> bfs::path
{
wchar_t exePathW[MAX_PATH];
DWORD nSize = GetModuleFileNameW(hModule, exePathW, MAX_PATH);
DWORD error = GetLastError();
// WARN: Windows XP don't set ERROR_INSUFFICIENT_BUFFER error.
if (nSize != 0 && error != ERROR_INSUFFICIENT_BUFFER)
return bfs::path(std::wstring(exePathW, nSize));
// TODO: Error handling
return bfs::path();
};
// Moves one directory contents to another directory
// Shows user the "moving file dialog" and ask to resolve conflicts.
// It takes into account that 'from' path can contain current executable.
// If necessary closes program and starts update script.
auto advancedMoveDirIfExists = [getModulePath, moveDirIfExists](const bfs::path& from, const bfs::path& to) -> bool
{
const bfs::path executablePath = getModulePath(nullptr);
// VCMI cann't determine executable path.
// Use standard way to move directory and exit function.
if (executablePath.empty())
return moveDirIfExists(from, to);
const bfs::path executableName = executablePath.filename();
// Current executabl isn't in 'from' path.
// Use standard way to move directory and exit function.
if (!bfs::equivalent(executablePath, from / executableName))
return moveDirIfExists(from, to);
// Try standard way to move directory.
// I don't know how other systems, but Windows 8.1 allow to move running executable.
if (moveDirIfExists(from, to))
return true;
// Start copying script and exit program.
if (StartBatchCopyDataProgram(from, to, executableName))
exit(ERROR_SUCCESS);
// Everything failed :C
return false;
};
moveDirIfExists(oldUserSavePath(), userSavePath());
advancedMoveDirIfExists(oldUserDataPath(), userDataPath());
}
std::string VCMIDirs::userConfigPath() const
bfs::path VCMIDirsWIN32::userDataPath() const
{
return userDataPath() + "/config";
}
wchar_t profileDir[MAX_PATH];
std::string VCMIDirs::userSavePath() const
{
return userDataPath() + "/Games";
}
std::string VCMIDirs::userDataPath() const
{
const std::string homeDir = std::getenv("userprofile");
return homeDir + "\\vcmi";
//return dataPaths()[0];
}
std::string VCMIDirs::libraryPath() const
{
if (SHGetSpecialFolderPathW(nullptr, profileDir, CSIDL_MYDOCUMENTS, FALSE) != FALSE)
return bfs::path(profileDir) / "My Games\\vcmi";
return ".";
}
std::string VCMIDirs::clientPath() const
bfs::path VCMIDirsWIN32::oldUserDataPath() const
{
return libraryPath() + "\\" + "VCMI_client.exe";
wchar_t profileDir[MAX_PATH];
if (SHGetSpecialFolderPathW(nullptr, profileDir, CSIDL_PROFILE, FALSE) == FALSE) // WinAPI way failed
{
#if defined(_MSC_VER) && _MSC_VER >= 1700
wchar_t* buffer;
size_t bufferSize;
errno_t result = _wdupenv_s(&buffer, &bufferSize, L"userprofile");
if (result == 0)
{
bfs::path result(std::wstring(buffer, bufferSize));
free(buffer);
return result;
}
#else
const char* profileDirA;
if (profileDirA = std::getenv("userprofile")) // STL way succeed
return bfs::path(profileDirA) / "vcmi";
#endif
else
return "."; // Every thing failed, return current directory.
}
else
return bfs::path(profileDir) / "vcmi";
//return dataPaths()[0] ???;
}
bfs::path VCMIDirsWIN32::oldUserSavePath() const { return userDataPath() / "Games"; }
bfs::path VCMIDirsWIN32::userCachePath() const { return userDataPath(); }
bfs::path VCMIDirsWIN32::userConfigPath() const { return userDataPath() / "config"; }
std::vector<bfs::path> VCMIDirsWIN32::dataPaths() const
{
return std::vector<bfs::path>(1, bfs::path("."));
}
std::string VCMIDirs::serverPath() const
bfs::path VCMIDirsWIN32::clientPath() const { return binaryPath() / "VCMI_client.exe"; }
bfs::path VCMIDirsWIN32::serverPath() const { return binaryPath() / "VCMI_server.exe"; }
bfs::path VCMIDirsWIN32::libraryPath() const { return "."; }
bfs::path VCMIDirsWIN32::binaryPath() const { return "."; }
std::string VCMIDirsWIN32::genHelpString() const
{
return libraryPath() + "\\" + "VCMI_server.exe";
std::vector<std::string> tempVec;
for (const bfs::path& path : dataPaths())
tempVec.push_back(path.string());
std::string gdStringA = boost::algorithm::join(tempVec, ";");
return
" game data: " + gdStringA + "\n"
" libraries: " + libraryPath().string() + "\n"
" server: " + serverPath().string() + "\n"
"\n"
" user data: " + userDataPath().string() + "\n"
" user cache: " + userCachePath().string() + "\n"
" user config: " + userConfigPath().string() + "\n"
" user saves: " + userSavePath().string() + "\n"; // Should end without new-line?
}
std::vector<std::string> VCMIDirs::dataPaths() const
std::string VCMIDirsWIN32::libraryName(const std::string& basename) const { return basename + ".dll"; }
#elif defined(VCMI_UNIX)
class IVCMIDirsUNIX : public IVCMIDirs
{
return std::vector<std::string>(1, ".");
public:
boost::filesystem::path clientPath() const override;
boost::filesystem::path serverPath() const override;
std::string genHelpString() const override;
};
bfs::path IVCMIDirsUNIX::clientPath() const { return binaryPath() / "vcmiclient"; }
bfs::path IVCMIDirsUNIX::serverPath() const { return binaryPath() / "vcmiserver"; }
std::string IVCMIDirsUNIX::genHelpString() const
{
std::vector<std::string> tempVec;
for (const bfs::path& path : dataPaths())
tempVec.push_back(path.string());
std::string gdStringA = boost::algorithm::join(tempVec, ":");
return
" game data: " + gdStringA + "\n"
" libraries: " + libraryPath().string() + "\n"
" server: " + serverPath().string() + "\n"
"\n"
" user data: " + userDataPath().string() + "\n"
" user cache: " + userCachePath().string() + "\n"
" user config: " + userConfigPath().string() + "\n"
" user saves: " + userSavePath().string() + "\n"; // Should end without new-line?
}
std::string VCMIDirs::libraryName(std::string basename) const
#ifdef VCMI_APPLE
class VCMIDirsOSX : public IVCMIDirsUNIX
{
return basename + ".dll";
public:
boost::filesystem::path userDataPath() const override;
boost::filesystem::path userCachePath() const override;
boost::filesystem::path userConfigPath() const override;
std::vector<boost::filesystem::path> dataPaths() const override;
boost::filesystem::path libraryPath() const override;
boost::filesystem::path binaryPath() const override;
std::string libraryName(const std::string& basename) const override;
void init() override;
};
void VCMIDirsOSX::init()
{
// Call base (init dirs)
IVCMIDirsUNIX::init();
auto moveDirIfExists = [](const bfs::path& from, const bfs::path& to)
{
if (!bfs::is_directory(from))
return; // Nothing to do here. Flies away.
if (bfs::is_empty(from))
{
bfs::remove(from);
return; // Nothing to do here. Flies away.
}
if (!bfs::is_directory(to))
{
// IVCMIDirs::init() should create all destination directories.
// TODO: Log fact, that we shouldn't be here.
bfs::create_directory(to);
}
for (bfs::directory_iterator file(from); file != bfs::directory_iterator(); ++file)
{
const boost::filesystem::path& srcFilePath = file->path();
const boost::filesystem::path dstFilePath = to / srcFilePath.filename();
// TODO: Aplication should ask user what to do when file exists:
// replace/ignore/stop process/replace all/ignore all
if (!boost::filesystem::exists(dstFilePath))
bfs::rename(srcFilePath, dstFilePath);
}
if (!bfs::is_empty(from)); // TODO: Log warn. Some files not moved. User should try to move files.
else
bfs::remove(from);
};
moveDirIfExists(userDataPath() / "Games", userSavePath());
}
#elif defined(__APPLE__)
std::string VCMIDirs::userCachePath() const
{
return userDataPath();
}
std::string VCMIDirs::userConfigPath() const
{
return userDataPath() + "/config";
}
std::string VCMIDirs::userSavePath() const
{
return userDataPath() + "/Games";
}
std::string VCMIDirs::userDataPath() const
bfs::path VCMIDirsOSX::userDataPath() const
{
// This is Cocoa code that should be normally used to get path to Application Support folder but can't use it here for now...
// NSArray* urls = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask];
// UserPath = path([urls[0] path] + "/vcmi").string();
// ...so here goes a bit of hardcode instead
std::string home_dir = ".";
if (getenv("HOME") != nullptr )
home_dir = getenv("HOME");
return boost::filesystem::path(home_dir + "/Library/Application Support/vcmi").string();
const char* homeDir = getenv("HOME"); // Should be std::getenv?
if (homeDir == nullptr)
homeDir = ".";
return bfs::path(homeDir) / "Library" / "Application Support" / "vcmi";
}
bfs::path VCMIDirsOSX::userCachePath() const { return userDataPath(); }
bfs::path VCMIDirsOSX::userConfigPath() const { return userDataPath() / "config"; }
std::vector<bfs::path> VCMIDirsOSX::dataPaths() const
{
return std::vector<bfs::path>(1, "../Data");
}
std::string VCMIDirs::libraryPath() const
bfs::path VCMIDirsOSX::libraryPath() const { return "."; }
bfs::path VCMIDirsOSX::binaryPath() const { return "."; }
std::string libraryName(const std::string& basename) { return "lib" + basename + ".dylib"; }
#elif defined(VCMI_LINUX)
class VCMIDirsLinux : public IVCMIDirsUNIX
{
return ".";
public:
boost::filesystem::path userDataPath() const override;
boost::filesystem::path userCachePath() const override;
boost::filesystem::path userConfigPath() const override;
std::vector<boost::filesystem::path> dataPaths() const override;
boost::filesystem::path libraryPath() const override;
boost::filesystem::path binaryPath() const override;
std::string libraryName(const std::string& basename) const override;
};
bfs::path VCMIDirsLinux::userDataPath() const
{
// $XDG_DATA_HOME, default: $HOME/.local/share
const char* homeDir;
if ((homeDir = getenv("XDG_DATA_HOME")))
return homeDir;
else if ((homeDir = getenv("HOME")))
return bfs::path(homeDir) / ".local" / "share" / "vcmi";
else
return ".";
}
bfs::path VCMIDirsLinux::userCachePath() const
{
// $XDG_CACHE_HOME, default: $HOME/.cache
const char* tempResult;
if ((tempResult = getenv("XDG_CACHE_HOME")))
return bfs::path(tempResult) / "vcmi";
else if ((tempResult = getenv("HOME")))
return bfs::path(tempResult) / ".cache" / "vcmi";
else
return ".";
}
bfs::path VCMIDirsLinux::userConfigPath() const
{
// $XDG_CONFIG_HOME, default: $HOME/.config
const char* tempResult;
if ((tempResult = getenv("XDG_CONFIG_HOME")))
return bfs::path(tempResult) / "vcmi";
else if ((tempResult = getenv("HOME")))
return bfs::path(tempResult) / ".config" / "vcmi";
else
return ".";
}
std::string VCMIDirs::clientPath() const
std::vector<bfs::path> VCMIDirsLinux::dataPaths() const
{
return "./vcmiclient";
}
// $XDG_DATA_DIRS, default: /usr/local/share/:/usr/share/
std::string VCMIDirs::serverPath() const
{
return "./vcmiserver";
}
std::vector<std::string> VCMIDirs::dataPaths() const
{
return std::vector<std::string>(1, "../Data");
}
std::string VCMIDirs::libraryName(std::string basename) const
{
return "lib" + basename + ".dylib";
}
#else
std::string VCMIDirs::libraryName(std::string basename) const
{
return "lib" + basename + ".so";
}
std::string VCMIDirs::libraryPath() const
{
return M_LIB_DIR;
}
std::string VCMIDirs::clientPath() const
{
return std::string(M_BIN_DIR) + "/" + "vcmiclient";
}
std::string VCMIDirs::serverPath() const
{
return std::string(M_BIN_DIR) + "/" + "vcmiserver";
}
// $XDG_DATA_HOME, default: $HOME/.local/share
std::string VCMIDirs::userDataPath() const
{
#ifdef __ANDROID__
// on Android HOME will be set to something like /sdcard/data/Android/is.xyz.vcmi/files/
return std::string(getenv("HOME"));
#else
if (getenv("XDG_DATA_HOME") != nullptr )
return std::string(getenv("XDG_DATA_HOME")) + "/vcmi";
if (getenv("HOME") != nullptr )
return std::string(getenv("HOME")) + "/.local/share" + "/vcmi";
return ".";
#endif
}
std::string VCMIDirs::userSavePath() const
{
return userDataPath() + "/Saves";
}
// $XDG_CACHE_HOME, default: $HOME/.cache
std::string VCMIDirs::userCachePath() const
{
#ifdef __ANDROID__
return userDataPath() + "/cache";
#else
if (getenv("XDG_CACHE_HOME") != nullptr )
return std::string(getenv("XDG_CACHE_HOME")) + "/vcmi";
if (getenv("HOME") != nullptr )
return std::string(getenv("HOME")) + "/.cache" + "/vcmi";
return ".";
#endif
}
// $XDG_CONFIG_HOME, default: $HOME/.config
std::string VCMIDirs::userConfigPath() const
{
#ifdef __ANDROID__
return userDataPath() + "/config";
#else
if (getenv("XDG_CONFIG_HOME") != nullptr )
return std::string(getenv("XDG_CONFIG_HOME")) + "/vcmi";
if (getenv("HOME") != nullptr )
return std::string(getenv("HOME")) + "/.config" + "/vcmi";
return ".";
#endif
}
// $XDG_DATA_DIRS, default: /usr/local/share/:/usr/share/
std::vector<std::string> VCMIDirs::dataPaths() const
{
// construct list in reverse.
// in specification first directory has highest priority
// in vcmi fs last directory has highest priority
std::vector<bfs::path> ret;
std::vector<std::string> ret;
#ifdef __ANDROID__
ret.push_back(userDataPath());
#else
if (getenv("HOME") != nullptr ) // compatibility, should be removed after 0.96
ret.push_back(std::string(getenv("HOME")) + "/.vcmi");
const char* tempResult;
ret.push_back(M_DATA_DIR);
if (getenv("XDG_DATA_DIRS") != nullptr)
if ((tempResult = getenv("XDG_DATA_DIRS")) != nullptr)
{
std::string dataDirsEnv = getenv("XDG_DATA_DIRS");
std::string dataDirsEnv = tempResult;
std::vector<std::string> dataDirs;
boost::split(dataDirs, dataDirsEnv, boost::is_any_of(":"));
for (auto & entry : boost::adaptors::reverse(dataDirs))
@ -231,21 +516,61 @@ std::vector<std::string> VCMIDirs::dataPaths() const
ret.push_back("/usr/share/");
ret.push_back("/usr/local/share/");
}
#endif
return ret;
}
#endif
bfs::path VCMIDirsLinux::libraryPath() const { return M_LIB_DIR; }
bfs::path VCMIDirsLinux::binaryPath() const { return M_BIN_DIR; }
std::string VCMIDirs::genHelpString() const
std::string VCMIDirsLinux::libraryName(const std::string& basename) const { return "lib" + basename + ".so"; }
#ifdef VCMI_ANDROID
class VCMIDirsAndroid : public VCMIDirsLinux
{
return
" game data: " + boost::algorithm::join(dataPaths(), ":") + "\n" +
" libraries: " + libraryPath() + "\n" +
" server: " + serverPath() + "\n" +
"\n" +
" user data: " + userDataPath() + "\n" +
" user cache: " + userCachePath() + "\n" +
" user config: " + userConfigPath() + "\n" +
" user saves: " + userSavePath() + "\n";
public:
boost::filesystem::path userDataPath() const override;
boost::filesystem::path userCachePath() const override;
boost::filesystem::path userConfigPath() const override;
std::vector<boost::filesystem::path> dataPaths() const override;
};
// on Android HOME will be set to something like /sdcard/data/Android/is.xyz.vcmi/files/
bfs::path VCMIDirsAndroid::userDataPath() const { return getenv("HOME"); }
bfs::path VCMIDirsAndroid::userCachePath() const { return userDataPath() / "cache"; }
bfs::path VCMIDirsAndroid::userConfigPath() const { return userDataPath() / "config"; }
std::vector<bfs::path> VCMIDirsAndroid::dataPaths() const
{
return std::vector<bfs::path>(1, userDataPath());
}
#endif // VCMI_ANDROID
#endif // VCMI_APPLE, VCMI_LINUX
#endif // VCMI_WINDOWS, VCMI_UNIX
// Getters for interfaces are separated for clarity.
namespace VCMIDirs
{
const IVCMIDirs& get()
{
#ifdef VCMI_WINDOWS
static VCMIDirsWIN32 singleton;
#elif defined(VCMI_ANDROID)
static VCMIDirsAndroid singleton;
#elif defined(VCMI_LINUX)
static VCMIDirsLinux singleton;
#elif defined(VCMI_APPLE)
static VCMIDirsOSX singleton;
#endif
static bool initialized = false;
if (!initialized)
{
std::locale::global(boost::locale::generator().generate("en_US.UTF-8"));
boost::filesystem::path::imbue(std::locale());
singleton.init();
initialized = true;
}
return singleton;
}
}

View File

@ -1,52 +1,58 @@
/*
* VCMIDirs.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "GameConstants.h"
/*
* VCMIDirs.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Where to find the various VCMI files. This is mostly useful for linux.
class DLL_LINKAGE VCMIDirs
class DLL_LINKAGE IVCMIDirs
{
public:
VCMIDirs();
public:
// Path to user-specific data directory
virtual boost::filesystem::path userDataPath() const = 0;
/// get singleton instance
static VCMIDirs & get();
// Path to "cache" directory, can be used for any non-essential files
virtual boost::filesystem::path userCachePath() const = 0;
/// Path to user-specific data directory
std::string userDataPath() const;
// Path to writeable directory with user configs
virtual boost::filesystem::path userConfigPath() const = 0;
/// Path to "cache" directory, can be used for any non-essential files
std::string userCachePath() const;
// Path to saved games
virtual boost::filesystem::path userSavePath() const;
/// Path to writeable directory with user configs
std::string userConfigPath() const;
// Paths to global system-wide data directories. First items have higher priority
virtual std::vector<boost::filesystem::path> dataPaths() const = 0;
/// Path to saved games
std::string userSavePath() const;
// Full path to client executable, including server name (e.g. /usr/bin/vcmiclient)
virtual boost::filesystem::path clientPath() const = 0;
/// Paths to global system-wide data directories. First items have higher priority
std::vector<std::string> dataPaths() const;
// Full path to server executable, including server name (e.g. /usr/bin/vcmiserver)
virtual boost::filesystem::path serverPath() const = 0;
/// Full path to client executable, including server name (e.g. /usr/bin/vcmiclient)
std::string clientPath() const;
// Path where vcmi libraries can be found (in AI and Scripting subdirectories)
virtual boost::filesystem::path libraryPath() const = 0;
/// Full path to server executable, including server name (e.g. /usr/bin/vcmiserver)
std::string serverPath() const;
// Path where vcmi binaries can be found
virtual boost::filesystem::path binaryPath() const = 0;
/// Path where vcmi libraries can be found (in AI and Scripting subdirectories)
std::string libraryPath() const;
// Returns system-specific name for dynamic libraries ( StupidAI => "libStupidAI.so" or "StupidAI.dll")
virtual std::string libraryName(const std::string& basename) const = 0;
// virtual std::string libraryName(const char* basename) const = 0; ?
// virtual std::string libraryName(std::string&& basename) const = 0;?
/// Returns system-specific name for dynamic libraries ( StupidAI => "libStupidAI.so" or "StupidAI.dll")
std::string libraryName(std::string basename) const;
std::string genHelpString() const;
virtual std::string genHelpString() const = 0;
// Creates not existed, but required directories.
// Updates directories what change name/path between versions.
// Function called automatically.
virtual void init();
};
namespace VCMIDirs
{
extern DLL_LINKAGE const IVCMIDirs& get();
}

View File

@ -13,9 +13,9 @@ ArchiveEntry::ArchiveEntry()
}
CArchiveLoader::CArchiveLoader(const std::string &mountPoint, const std::string & archive):
archive(archive),
mountPoint(mountPoint)
CArchiveLoader::CArchiveLoader(std::string _mountPoint, boost::filesystem::path _archive) :
archive(std::move(_archive)),
mountPoint(std::move(_mountPoint))
{
// Open archive file(.snd, .vid, .lod)
CFileInputStream fileStream(archive);
@ -25,28 +25,19 @@ CArchiveLoader::CArchiveLoader(const std::string &mountPoint, const std::string
return;
// Retrieve file extension of archive in uppercase
CFileInfo fileInfo(archive);
std::string ext = fileInfo.getExtension();
boost::to_upper(ext);
const std::string ext = boost::to_upper_copy(archive.extension().string());
// Init the specific lod container format
if(ext == ".LOD" || ext == ".PAC")
{
initLODArchive(mountPoint, fileStream);
}
else if(ext == ".VID")
{
initVIDArchive(mountPoint, fileStream);
}
else if(ext == ".SND")
{
initSNDArchive(mountPoint, fileStream);
}
else
{
throw std::runtime_error("LOD archive format unknown. Cannot deal with " + archive);
}
logGlobal->traceStream() << ext << "Archive loaded, " << entries.size() << " files found";
throw std::runtime_error("LOD archive format unknown. Cannot deal with " + archive.string());
logGlobal->traceStream() << ext << "Archive \""<<archive.filename()<<"\" loaded (" << entries.size() << " files found).";
}
void CArchiveLoader::initLODArchive(const std::string &mountPoint, CFileInputStream & fileStream)
@ -61,7 +52,7 @@ void CArchiveLoader::initLODArchive(const std::string &mountPoint, CFileInputStr
fileStream.seek(0x5c);
// Insert entries to list
for(ui32 i = 0; i < totalFiles; i++)
for(ui32 i = 0; i < totalFiles; ++i)
{
char filename[16];
reader.read(reinterpret_cast<ui8*>(filename), 16);
@ -90,7 +81,7 @@ void CArchiveLoader::initVIDArchive(const std::string &mountPoint, CFileInputStr
std::set<int> offsets;
// Insert entries to list
for(ui32 i = 0; i < totalFiles; i++)
for(ui32 i = 0; i < totalFiles; ++i)
{
char filename[40];
reader.read(reinterpret_cast<ui8*>(filename), 40);
@ -122,7 +113,7 @@ void CArchiveLoader::initSNDArchive(const std::string &mountPoint, CFileInputStr
ui32 totalFiles = reader.readUInt32();
// Insert entries to list
for(ui32 i = 0; i < totalFiles; i++)
for(ui32 i = 0; i < totalFiles; ++i)
{
char filename[40];
reader.read(reinterpret_cast<ui8*>(filename), 40);

View File

@ -55,7 +55,7 @@ public:
*
* @throws std::runtime_error if the archive wasn't found or if the archive isn't supported
*/
explicit CArchiveLoader(const std::string & mountPoint, const std::string & archive);
CArchiveLoader(std::string mountPoint, boost::filesystem::path archive);
/// Interface implementation
/// @see ISimpleResourceLoader
@ -87,7 +87,7 @@ private:
void initSNDArchive(const std::string &mountPoint, CFileInputStream & fileStream);
/** The file path to the archive which is scanned and indexed. */
std::string archive;
boost::filesystem::path archive;
std::string mountPoint;

View File

@ -41,17 +41,17 @@ std::string CFileInfo::getPath() const
std::string CFileInfo::getExtension() const
{
// Get position of file extension dot
size_t dotPos = name.find_last_of("/.");
size_t dotPos = name.find_last_of('.');
if(dotPos != std::string::npos && name[dotPos] == '.')
if(dotPos != std::string::npos)
return name.substr(dotPos);
else
return "";
return "";
}
std::string CFileInfo::getFilename() const
{
size_t found = name.find_last_of("/\\");
const size_t found = name.find_last_of("/\\");
return name.substr(found + 1);
}
@ -60,9 +60,9 @@ std::string CFileInfo::getStem() const
std::string rslt = name;
// Remove file extension
size_t dotPos = name.find_last_of("/.");
const size_t dotPos = name.find_last_of('.');
if(dotPos != std::string::npos && name[dotPos] == '.')
if(dotPos != std::string::npos)
rslt.erase(dotPos);
return rslt;
@ -70,18 +70,19 @@ std::string CFileInfo::getStem() const
std::string CFileInfo::getBaseName() const
{
size_t begin = name.find_last_of("/");
size_t end = name.find_last_of("/.");
if(end != std::string::npos && name[end] == '/')
end = std::string::npos;
size_t begin = name.find_last_of("/\\");
size_t end = name.find_last_of(".");
if(begin == std::string::npos)
begin = 0;
else
begin++;
++begin;
if (end < begin)
end = std::string::npos;
return name.substr(begin, end - begin);
size_t len = (end == std::string::npos ? std::string::npos : end - begin);
return name.substr(begin, len);
}
EResType::Type CFileInfo::getType() const

View File

@ -3,7 +3,7 @@
#include "CFileInfo.h"
CFileInputStream::CFileInputStream(const std::string & file, si64 start, si64 size)
CFileInputStream::CFileInputStream(const boost::filesystem::path & file, si64 start, si64 size)
{
open(file, start, size);
}
@ -18,14 +18,12 @@ CFileInputStream::~CFileInputStream()
fileStream.close();
}
void CFileInputStream::open(const std::string & file, si64 start, si64 size)
void CFileInputStream::open(const boost::filesystem::path & file, si64 start, si64 size)
{
fileStream.open(file.c_str(), std::ios::in | std::ios::binary);
fileStream.open(file, std::ios::in | std::ios::binary);
if (fileStream.fail())
{
throw std::runtime_error("File " + file + " isn't available.");
}
throw std::runtime_error("File " + file.string() + " isn't available.");
dataStart = start;
dataSize = size;

View File

@ -25,7 +25,7 @@ public:
*
* @see CFileInputStream::open
*/
CFileInputStream(const std::string & file, si64 start=0, si64 size=0);
CFileInputStream(const boost::filesystem::path & file, si64 start = 0, si64 size = 0);
/**
* C-tor. Opens the specified file.
@ -88,11 +88,11 @@ private:
*
* @throws std::runtime_error if file wasn't found
*/
void open(const std::string & file, si64 start, si64 size);
void open(const boost::filesystem::path & file, si64 start, si64 size);
si64 dataStart;
si64 dataSize;
/** Native c++ input file stream object. */
std::ifstream fileStream;
boost::filesystem::ifstream fileStream;
};

View File

@ -4,9 +4,11 @@
#include "CFileInfo.h"
#include "CFileInputStream.h"
CFilesystemLoader::CFilesystemLoader(const std::string &mountPoint, const std::string & baseDirectory, size_t depth, bool initial):
baseDirectory(baseDirectory),
mountPoint(mountPoint),
namespace bfs = boost::filesystem;
CFilesystemLoader::CFilesystemLoader(std::string _mountPoint, bfs::path baseDirectory, size_t depth, bool initial):
baseDirectory(std::move(baseDirectory)),
mountPoint(std::move(_mountPoint)),
fileList(listFiles(mountPoint, depth, initial))
{
logGlobal->traceStream() << "Filesystem loaded, " << fileList.size() << " files found";
@ -16,7 +18,7 @@ std::unique_ptr<CInputStream> CFilesystemLoader::load(const ResourceID & resourc
{
assert(fileList.count(resourceName));
std::unique_ptr<CInputStream> stream(new CFileInputStream(baseDirectory + '/' + fileList.at(resourceName)));
std::unique_ptr<CInputStream> stream(new CFileInputStream(baseDirectory / fileList.at(resourceName)));
return stream;
}
@ -34,7 +36,7 @@ boost::optional<std::string> CFilesystemLoader::getResourceName(const ResourceID
{
assert(existsResource(resourceName));
return baseDirectory + '/' + fileList.at(resourceName);
return (baseDirectory / fileList.at(resourceName)).string();
}
std::unordered_set<ResourceID> CFilesystemLoader::getFilteredFiles(std::function<bool(const ResourceID &)> filter) const
@ -45,7 +47,8 @@ std::unordered_set<ResourceID> CFilesystemLoader::getFilteredFiles(std::function
{
if (filter(file.first))
foundID.insert(file.first);
} return foundID;
}
return foundID;
}
bool CFilesystemLoader::createResource(std::string filename, bool update)
@ -65,7 +68,7 @@ bool CFilesystemLoader::createResource(std::string filename, bool update)
if (!update)
{
std::ofstream newfile (baseDirectory + "/" + filename);
bfs::ofstream newfile(baseDirectory / filename);
if (!newfile.good())
return false;
}
@ -73,49 +76,72 @@ bool CFilesystemLoader::createResource(std::string filename, bool update)
return true;
}
std::unordered_map<ResourceID, std::string> CFilesystemLoader::listFiles(const std::string &mountPoint, size_t depth, bool initial) const
std::unordered_map<ResourceID, bfs::path> CFilesystemLoader::listFiles(const std::string &mountPoint, size_t depth, bool initial) const
{
std::set<EResType::Type> initialTypes;
initialTypes.insert(EResType::DIRECTORY);
initialTypes.insert(EResType::TEXT);
initialTypes.insert(EResType::ARCHIVE_LOD);
initialTypes.insert(EResType::ARCHIVE_VID);
initialTypes.insert(EResType::ARCHIVE_SND);
initialTypes.insert(EResType::ARCHIVE_ZIP);
static const EResType::Type initArray[] = {
EResType::DIRECTORY,
EResType::TEXT,
EResType::ARCHIVE_LOD,
EResType::ARCHIVE_VID,
EResType::ARCHIVE_SND,
EResType::ARCHIVE_ZIP };
static const std::set<EResType::Type> initialTypes(initArray, initArray + ARRAY_COUNT(initArray));
assert(boost::filesystem::is_directory(baseDirectory));
std::unordered_map<ResourceID, std::string> fileList;
assert(bfs::is_directory(baseDirectory));
std::unordered_map<ResourceID, bfs::path> fileList;
std::vector<std::string> path;//vector holding relative path to our file
std::vector<bfs::path> path; //vector holding relative path to our file
boost::filesystem::recursive_directory_iterator enddir;
boost::filesystem::recursive_directory_iterator it(baseDirectory, boost::filesystem::symlink_option::recurse);
bfs::recursive_directory_iterator enddir;
bfs::recursive_directory_iterator it(baseDirectory, bfs::symlink_option::recurse);
for(; it != enddir; ++it)
{
EResType::Type type;
if (boost::filesystem::is_directory(it->status()))
if (bfs::is_directory(it->status()))
{
path.resize(it.level()+1);
path.back() = it->path().leaf().string();
path.resize(it.level() + 1);
path.back() = it->path().filename();
// don't iterate into directory if depth limit reached
it.no_push(depth <= it.level());
type = EResType::DIRECTORY;
}
else
type = EResTypeHelper::getTypeFromExtension(boost::filesystem::extension(*it));
type = EResTypeHelper::getTypeFromExtension(it->path().extension().string());
if (!initial || vstd::contains(initialTypes, type))
{
//reconstruct relative filename (not possible via boost AFAIK)
std::string filename;
for (size_t i=0; i<it.level() && i<path.size(); i++)
filename += path[i] + '/';
filename += it->path().leaf().string();
bfs::path filename;
const size_t iterations = std::min((size_t)it.level(), path.size());
if (iterations)
{
filename = path.front();
for (size_t i = 1; i < iterations; ++i)
filename /= path[i];
filename /= it->path().filename();
}
else
filename = it->path().filename();
fileList[ResourceID(mountPoint + filename, type)] = filename;
std::string resName;
if (bfs::path::preferred_separator != '/')
{
// resource names are using UNIX slashes (/)
resName.reserve(resName.size() + filename.native().size());
resName = mountPoint;
for (const char c : filename.string())
if (c != bfs::path::preferred_separator)
resName.push_back(c);
else
resName.push_back('/');
}
else
resName = mountPoint + filename.string();
fileList[ResourceID(resName, type)] = std::move(filename);
}
}

View File

@ -30,7 +30,7 @@ public:
*
* @throws std::runtime_error if the base directory is not a directory or if it is not available
*/
explicit CFilesystemLoader(const std::string & mountPoint, const std::string & baseDirectory, size_t depth = 16, bool initial = false);
explicit CFilesystemLoader(std::string mountPoint, boost::filesystem::path baseDirectory, size_t depth = 16, bool initial = false);
/// Interface implementation
/// @see ISimpleResourceLoader
@ -39,11 +39,11 @@ public:
std::string getMountPoint() const override;
bool createResource(std::string filename, bool update = false) override;
boost::optional<std::string> getResourceName(const ResourceID & resourceName) const override;
std::unordered_set<ResourceID> getFilteredFiles(std::function<bool(const ResourceID &)> filter) const;
std::unordered_set<ResourceID> getFilteredFiles(std::function<bool(const ResourceID &)> filter) const override;
private:
/** The base directory which is scanned and indexed. */
std::string baseDirectory;
boost::filesystem::path baseDirectory;
std::string mountPoint;
@ -51,7 +51,7 @@ private:
* key = ResourceID for resource loader
* value = name that can be used to access file
*/
std::unordered_map<ResourceID, std::string> fileList;
std::unordered_map<ResourceID, boost::filesystem::path> fileList;
/**
* Returns a list of pathnames denoting the files in the directory denoted by this pathname.
@ -62,5 +62,5 @@ private:
* @return a list of pathnames denoting the files and directories in the directory denoted by this pathname
* The array will be empty if the directory is empty. Ptr is null if the directory doesn't exist or if it isn't a directory.
*/
std::unordered_map<ResourceID, std::string> listFiles(const std::string &mountPoint, size_t depth, bool initial) const;
std::unordered_map<ResourceID, boost::filesystem::path> listFiles(const std::string &mountPoint, size_t depth, bool initial) const;
};

View File

@ -69,7 +69,7 @@ void CFilesystemGenerator::loadDirectory(const std::string &mountPoint, const Js
std::string URI = prefix + config["path"].String();
int depth = 16;
if (!config["depth"].isNull())
depth = config["depth"].Float();
depth = (int)config["depth"].Float();
ResourceID resID(URI, EResType::DIRECTORY);
@ -130,7 +130,7 @@ ISimpleResourceLoader * CResourceHandler::createInitial()
auto filename = loader->getResourceName(ID);
if (filename)
{
auto dir = new CFilesystemLoader(URI + "/", *filename, depth, true);
auto dir = new CFilesystemLoader(URI + '/', *filename, depth, true);
initialLoader->addLoader(dir, false);
}
}

View File

@ -94,11 +94,11 @@ public:
}
//returns squared distance on Oxy plane (z coord is not used)
si32 dist2dSQ(const int3 & o) const
ui32 dist2dSQ(const int3 & o) const
{
const si32 dx = (x - o.x);
const si32 dy = (y - o.y);
return dx*dx + dy*dy;
return (ui32)(dx*dx) + (ui32)(dy*dy);
}
//returns distance on Oxy plane (z coord is not used)
double dist2d(const int3 & o) const
@ -157,15 +157,17 @@ struct ShashInt3
static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),
int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) };
//FIXME: make sure it's <int3> container and not just any
template<typename Container>
int3 findClosestTile (Container & container, int3 dest)
{
int3 result(-1,-1,-1);
static_assert(std::is_same<typename Container::value_type, int3>::value,
"findClosestTile requires <int3> container.");
int3 result(-1, -1, -1);
ui32 distance = std::numeric_limits<ui32>::max();
for (int3 tile : container)
for (const int3& tile : container)
{
ui32 currentDistance = dest.dist2dSQ(tile);
const ui32 currentDistance = dest.dist2dSQ(tile);
if (currentDistance < distance)
{
result = tile;

View File

@ -3,11 +3,8 @@
#include "../CConfigHandler.h"
CBasicLogConfigurator::CBasicLogConfigurator(const std::string & filePath, CConsoleHandler * console) : filePath(filePath),
console(console), appendToLogFile(false)
{
}
CBasicLogConfigurator::CBasicLogConfigurator(boost::filesystem::path filePath, CConsoleHandler * const console) :
filePath(std::move(filePath)), console(console), appendToLogFile(false) {}
void CBasicLogConfigurator::configureDefault()
{
@ -21,7 +18,8 @@ void CBasicLogConfigurator::configure()
try
{
const JsonNode & loggingNode = settings["logging"];
if(loggingNode.isNull()) throw std::runtime_error("Settings haven't been loaded.");
if(loggingNode.isNull())
throw std::runtime_error("Settings haven't been loaded.");
// Configure loggers
const JsonNode & loggers = loggingNode["loggers"];
@ -87,7 +85,7 @@ void CBasicLogConfigurator::configure()
logGlobal->infoStream() << "Initialized logging system based on settings successfully.";
}
ELogLevel::ELogLevel CBasicLogConfigurator::getLogLevel(const std::string & level) const
ELogLevel::ELogLevel CBasicLogConfigurator::getLogLevel(const std::string & level)
{
static const std::map<std::string, ELogLevel::ELogLevel> levelMap = boost::assign::map_list_of
("trace", ELogLevel::TRACE)
@ -95,18 +93,15 @@ ELogLevel::ELogLevel CBasicLogConfigurator::getLogLevel(const std::string & leve
("info", ELogLevel::INFO)
("warn", ELogLevel::WARN)
("error", ELogLevel::ERROR);
const auto & levelPair = levelMap.find(level);
if(levelPair != levelMap.end())
{
return levelPair->second;
}
else
{
throw std::runtime_error("Log level " + level + " unknown.");
}
}
EConsoleTextColor::EConsoleTextColor CBasicLogConfigurator::getConsoleColor(const std::string & colorName) const
EConsoleTextColor::EConsoleTextColor CBasicLogConfigurator::getConsoleColor(const std::string & colorName)
{
static const std::map<std::string, EConsoleTextColor::EConsoleTextColor> colorMap = boost::assign::map_list_of
("default", EConsoleTextColor::DEFAULT)
@ -117,13 +112,10 @@ EConsoleTextColor::EConsoleTextColor CBasicLogConfigurator::getConsoleColor(cons
("white", EConsoleTextColor::WHITE)
("gray", EConsoleTextColor::GRAY)
("teal", EConsoleTextColor::TEAL);
const auto & colorPair = colorMap.find(colorName);
if(colorPair != colorMap.end())
{
return colorPair->second;
}
else
{
throw std::runtime_error("Color " + colorName + " unknown.");
}
}

View File

@ -22,7 +22,7 @@ class JsonNode;
class DLL_LINKAGE CBasicLogConfigurator
{
public:
CBasicLogConfigurator(const std::string & filePath, CConsoleHandler * console);
CBasicLogConfigurator(boost::filesystem::path filePath, CConsoleHandler * const console);
/// Configures the logging system by parsing the logging settings. It adds the console target and the file target to the global logger.
/// Doesn't throw, but logs on success or fault.
@ -30,12 +30,15 @@ public:
/// Configures a default logging system by adding the console target and the file target to the global logger.
void configureDefault();
private:
ELogLevel::ELogLevel getLogLevel(const std::string & level) const;
EConsoleTextColor::EConsoleTextColor getConsoleColor(const std::string & colorName) const;
// Gets ELogLevel enum from string. (Should be moved to CLogger as a separate function?)
// Throws: std::runtime_error
static ELogLevel::ELogLevel getLogLevel(const std::string & level);
// Gets EConsoleTextColor enum from strings. (Should be moved to CLogger as a separate function?)
// Throws: std::runtime_error
static EConsoleTextColor::EConsoleTextColor getConsoleColor(const std::string & colorName);
std::string filePath;
boost::filesystem::path filePath;
CConsoleHandler * console;
bool appendToLogFile;
};

View File

@ -1,46 +1,51 @@
#ifdef __ANDROID__
#include <android/log.h>
#endif
#include "StdInc.h"
#include "CLogger.h"
#ifdef VCMI_ANDROID
#include <android/log.h>
namespace ELogLevel
{
int toAndroid(ELogLevel logLevel)
{
switch (logLevel)
{
case TRACE: return ANDROID_LOG_VERBOSE;
case DEBUG: return ANDROID_LOG_DEBUG;
case INFO: return ANDROID_LOG_INFO;
case WARN: return ANDROID_LOG_WARN;
case ERROR: return ANDROID_LOG_ERROR;
default:;
}
return ANDROID_LOG_UNKNOWN;
}
}
#endif
const std::string CLoggerDomain::DOMAIN_GLOBAL = "global";
CLoggerDomain::CLoggerDomain(const std::string & name) : name(name)
CLoggerDomain::CLoggerDomain(std::string name) : name(std::move(name))
{
if(name.empty()) throw std::runtime_error("Logger domain cannot be empty.");
if (this->name.empty())
throw std::runtime_error("Logger domain cannot be empty.");
}
CLoggerDomain CLoggerDomain::getParent() const
{
if(isGlobalDomain()) return *this;
if(isGlobalDomain())
return *this;
size_t pos = name.find_last_of(".");
const size_t pos = name.find_last_of(".");
if(pos != std::string::npos)
{
return CLoggerDomain(name.substr(0, pos));
}
else
{
return CLoggerDomain(DOMAIN_GLOBAL);
}
return CLoggerDomain(DOMAIN_GLOBAL);
}
bool CLoggerDomain::isGlobalDomain() const
{
return name == DOMAIN_GLOBAL;
}
bool CLoggerDomain::isGlobalDomain() const { return name == DOMAIN_GLOBAL; }
std::string CLoggerDomain::getName() const
{
return name;
}
const std::string& CLoggerDomain::getName() const { return name; }
CLoggerStream::CLoggerStream(const CLogger & logger, ELogLevel::ELogLevel level) : logger(logger), level(level), sbuffer(nullptr)
{
}
CLoggerStream::CLoggerStream(const CLogger & logger, ELogLevel::ELogLevel level) : logger(logger), level(level), sbuffer(nullptr) {}
CLoggerStream::~CLoggerStream()
{
@ -67,20 +72,14 @@ CLogger * CLogger::getLogger(const CLoggerDomain & domain)
TLockGuardRec _(smx);
CLogger * logger = CLogManager::get().getLogger(domain);
if(logger)
{
return logger;
}
else
if(!logger) // Create new logger
{
logger = new CLogger(domain);
if(domain.isGlobalDomain())
{
logger->setLevel(ELogLevel::TRACE);
}
CLogManager::get().addLogger(logger);
return logger;
}
return logger;
}
CLogger * CLogger::getGlobalLogger()
@ -102,62 +101,22 @@ CLogger::CLogger(const CLoggerDomain & domain) : domain(domain)
}
}
void CLogger::trace(const std::string & message) const
{
log(ELogLevel::TRACE, message);
}
void CLogger::trace(const std::string & message) const { log(ELogLevel::TRACE, message); }
void CLogger::debug(const std::string & message) const { log(ELogLevel::DEBUG, message); }
void CLogger::info(const std::string & message) const { log(ELogLevel::INFO, message); }
void CLogger::warn(const std::string & message) const { log(ELogLevel::WARN, message); }
void CLogger::error(const std::string & message) const { log(ELogLevel::ERROR, message); }
CLoggerStream CLogger::traceStream() const
{
return CLoggerStream(*this, ELogLevel::TRACE);
}
void CLogger::debug(const std::string & message) const
{
log(ELogLevel::DEBUG, message);
}
CLoggerStream CLogger::debugStream() const
{
return CLoggerStream(*this, ELogLevel::DEBUG);
}
void CLogger::info(const std::string & message) const
{
log(ELogLevel::INFO, message);
}
CLoggerStream CLogger::infoStream() const
{
return CLoggerStream(*this, ELogLevel::INFO);
}
void CLogger::warn(const std::string & message) const
{
log(ELogLevel::WARN, message);
}
CLoggerStream CLogger::warnStream() const
{
return CLoggerStream(*this, ELogLevel::WARN);
}
void CLogger::error(const std::string & message) const
{
log(ELogLevel::ERROR, message);
}
CLoggerStream CLogger::errorStream() const
{
return CLoggerStream(*this, ELogLevel::ERROR);
}
CLoggerStream CLogger::traceStream() const { return CLoggerStream(*this, ELogLevel::TRACE); }
CLoggerStream CLogger::debugStream() const { return CLoggerStream(*this, ELogLevel::DEBUG); }
CLoggerStream CLogger::infoStream() const { return CLoggerStream(*this, ELogLevel::INFO); }
CLoggerStream CLogger::warnStream() const { return CLoggerStream(*this, ELogLevel::WARN); }
CLoggerStream CLogger::errorStream() const { return CLoggerStream(*this, ELogLevel::ERROR); }
void CLogger::log(ELogLevel::ELogLevel level, const std::string & message) const
{
if(getEffectiveLevel() <= level)
{
callTargets(LogRecord(domain, level, message));
}
}
ELogLevel::ELogLevel CLogger::getLevel() const
@ -169,14 +128,11 @@ ELogLevel::ELogLevel CLogger::getLevel() const
void CLogger::setLevel(ELogLevel::ELogLevel level)
{
TLockGuard _(mx);
if(domain.isGlobalDomain() && level == ELogLevel::NOT_SET) return;
this->level = level;
if (!domain.isGlobalDomain() || level != ELogLevel::NOT_SET)
this->level = level;
}
const CLoggerDomain & CLogger::getDomain() const
{
return domain;
}
const CLoggerDomain & CLogger::getDomain() const { return domain; }
void CLogger::addTarget(unique_ptr<ILogTarget> && target)
{
@ -187,9 +143,8 @@ void CLogger::addTarget(unique_ptr<ILogTarget> && target)
ELogLevel::ELogLevel CLogger::getEffectiveLevel() const
{
for(const CLogger * logger = this; logger != nullptr; logger = logger->parent)
{
if(logger->getLevel() != ELogLevel::NOT_SET) return logger->getLevel();
}
if(logger->getLevel() != ELogLevel::NOT_SET)
return logger->getLevel();
// This shouldn't be reached, as the root logger must have set a log level
return ELogLevel::INFO;
@ -199,12 +154,8 @@ void CLogger::callTargets(const LogRecord & record) const
{
TLockGuard _(mx);
for(const CLogger * logger = this; logger != nullptr; logger = logger->parent)
{
for(auto & target : logger->targets)
{
target->write(record);
}
}
}
void CLogger::clearTargets()
@ -213,26 +164,15 @@ void CLogger::clearTargets()
targets.clear();
}
bool CLogger::isDebugEnabled() const
{
return getEffectiveLevel() <= ELogLevel::DEBUG;
}
bool CLogger::isTraceEnabled() const
{
return getEffectiveLevel() <= ELogLevel::TRACE;
}
bool CLogger::isDebugEnabled() const { return getEffectiveLevel() <= ELogLevel::DEBUG; }
bool CLogger::isTraceEnabled() const { return getEffectiveLevel() <= ELogLevel::TRACE; }
CTraceLogger::CTraceLogger(const CLogger * logger, const std::string & beginMessage, const std::string & endMessage)
: logger(logger), endMessage(endMessage)
{
logger->traceStream() << beginMessage;
}
CTraceLogger::~CTraceLogger()
{
logger->traceStream() << endMessage;
logger->trace(beginMessage);
}
CTraceLogger::~CTraceLogger() { logger->trace(std::move(endMessage)); }
CLogManager & CLogManager::get()
{
@ -241,17 +181,11 @@ CLogManager & CLogManager::get()
return instance;
}
CLogManager::CLogManager()
{
}
CLogManager::CLogManager() { }
CLogManager::~CLogManager()
{
for(auto & i : loggers)
{
delete i.second;
}
}
void CLogManager::addLogger(CLogger * logger)
@ -265,34 +199,30 @@ CLogger * CLogManager::getLogger(const CLoggerDomain & domain)
TLockGuard _(mx);
auto it = loggers.find(domain.getName());
if(it != loggers.end())
{
return it->second;
}
else
{
return nullptr;
}
}
CLogFormatter::CLogFormatter() : pattern("%m")
CLogFormatter::CLogFormatter() : CLogFormatter("%m") { }
CLogFormatter::CLogFormatter(const std::string & pattern) : pattern(pattern)
{
boost::posix_time::time_facet * facet = new boost::posix_time::time_facet("%H:%M:%S");
dateStream.imbue(std::locale(dateStream.getloc(), facet));
}
CLogFormatter::CLogFormatter(const std::string & pattern)
{
setPattern(pattern);
}
CLogFormatter::CLogFormatter(const CLogFormatter & c) : pattern(c.pattern) { }
CLogFormatter::CLogFormatter(CLogFormatter && m) : pattern(std::move(m.pattern)) { }
CLogFormatter::CLogFormatter(const CLogFormatter & other)
CLogFormatter & CLogFormatter::operator=(const CLogFormatter & c)
{
*this = other;
pattern = c.pattern;
return *this;
}
CLogFormatter & CLogFormatter::operator=(const CLogFormatter & other)
CLogFormatter & CLogFormatter::operator=(CLogFormatter && m)
{
pattern = other.pattern;
pattern = std::move(m.pattern);
return *this;
}
@ -336,15 +266,10 @@ std::string CLogFormatter::format(const LogRecord & record) const
return message;
}
void CLogFormatter::setPattern(const std::string & pattern)
{
this->pattern = pattern;
}
void CLogFormatter::setPattern(const std::string & pattern) { this->pattern = pattern; }
void CLogFormatter::setPattern(std::string && pattern) { this->pattern = std::move(pattern); }
const std::string & CLogFormatter::getPattern() const
{
return pattern;
}
const std::string & CLogFormatter::getPattern() const { return pattern; }
CColorMapping::CColorMapping()
{
@ -365,30 +290,24 @@ void CColorMapping::setColorFor(const CLoggerDomain & domain, ELogLevel::ELogLev
EConsoleTextColor::EConsoleTextColor CColorMapping::getColorFor(const CLoggerDomain & domain, ELogLevel::ELogLevel level) const
{
std::string name = domain.getName();
CLoggerDomain currentDomain = domain;
while(true)
{
const auto & loggerPair = map.find(name);
const auto & loggerPair = map.find(currentDomain.getName());
if(loggerPair != map.end())
{
const auto & levelMap = loggerPair->second;
const auto & levelPair = levelMap.find(level);
if(levelPair != levelMap.end())
{
return levelPair->second;
}
}
CLoggerDomain currentDomain(name);
if(!currentDomain.isGlobalDomain())
{
name = currentDomain.getParent().getName();
}
else
{
if (currentDomain.isGlobalDomain())
break;
}
currentDomain = currentDomain.getParent();
}
throw std::runtime_error("failed to find color for requested domain/level pair");
}
@ -399,103 +318,56 @@ CLogConsoleTarget::CLogConsoleTarget(CConsoleHandler * console) : console(consol
void CLogConsoleTarget::write(const LogRecord & record)
{
if(threshold > record.level) return;
if(threshold > record.level)
return;
std::string message = formatter.format(record);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "VCMI", "%s", message.c_str());
#ifdef VCMI_ANDROID
__android_log_write(ELogLevel::toAndroid(record.level), "VCMI", message.c_str());
#endif
bool printToStdErr = record.level >= ELogLevel::WARN;
const bool printToStdErr = record.level >= ELogLevel::WARN;
if(console)
{
if(coloredOutputEnabled)
{
console->print(message, true, colorMapping.getColorFor(record.domain, record.level));
}
else
{
console->print(message, true, EConsoleTextColor::DEFAULT, printToStdErr);
}
const EConsoleTextColor::EConsoleTextColor textColor =
coloredOutputEnabled ? colorMapping.getColorFor(record.domain, record.level) : EConsoleTextColor::DEFAULT;
console->print(message, true, textColor, printToStdErr);
}
else
{
TLockGuard _(mx);
if(printToStdErr)
{
std::cerr << message << std::endl;
}
else
{
std::cout << message << std::endl;
}
}
}
bool CLogConsoleTarget::isColoredOutputEnabled() const
{
return coloredOutputEnabled;
}
bool CLogConsoleTarget::isColoredOutputEnabled() const { return coloredOutputEnabled; }
void CLogConsoleTarget::setColoredOutputEnabled(bool coloredOutputEnabled) { this->coloredOutputEnabled = coloredOutputEnabled; }
void CLogConsoleTarget::setColoredOutputEnabled(bool coloredOutputEnabled)
{
this->coloredOutputEnabled = coloredOutputEnabled;
}
ELogLevel::ELogLevel CLogConsoleTarget::getThreshold() const { return threshold; }
void CLogConsoleTarget::setThreshold(ELogLevel::ELogLevel threshold) { this->threshold = threshold; }
ELogLevel::ELogLevel CLogConsoleTarget::getThreshold() const
{
return threshold;
}
const CLogFormatter & CLogConsoleTarget::getFormatter() const { return formatter; }
void CLogConsoleTarget::setFormatter(const CLogFormatter & formatter) { this->formatter = formatter; }
void CLogConsoleTarget::setThreshold(ELogLevel::ELogLevel threshold)
{
this->threshold = threshold;
}
const CColorMapping & CLogConsoleTarget::getColorMapping() const { return colorMapping; }
void CLogConsoleTarget::setColorMapping(const CColorMapping & colorMapping) { this->colorMapping = colorMapping; }
const CLogFormatter & CLogConsoleTarget::getFormatter() const
{
return formatter;
}
void CLogConsoleTarget::setFormatter(const CLogFormatter & formatter)
{
this->formatter = formatter;
}
const CColorMapping & CLogConsoleTarget::getColorMapping() const
{
return colorMapping;
}
void CLogConsoleTarget::setColorMapping(const CColorMapping & colorMapping)
{
this->colorMapping = colorMapping;
}
CLogFileTarget::CLogFileTarget(const std::string & filePath, bool append /*= true*/)
: file(filePath, append ? std::ios_base::app : std::ios_base::out)
CLogFileTarget::CLogFileTarget(boost::filesystem::path filePath, bool append /*= true*/)
: file(std::move(filePath), append ? std::ios_base::app : std::ios_base::out)
{
formatter.setPattern("%d %l %n [%t] - %m");
}
CLogFileTarget::~CLogFileTarget()
{
file.close();
}
void CLogFileTarget::write(const LogRecord & record)
{
TLockGuard _(mx);
file << formatter.format(record) << std::endl;
}
const CLogFormatter & CLogFileTarget::getFormatter() const
{
return formatter;
}
void CLogFileTarget::setFormatter(const CLogFormatter & formatter)
{
this->formatter = formatter;
}
const CLogFormatter & CLogFileTarget::getFormatter() const { return formatter; }
void CLogFileTarget::setFormatter(const CLogFormatter & formatter) { this->formatter = formatter; }

View File

@ -19,15 +19,19 @@ class ILogTarget;
namespace ELogLevel
{
enum ELogLevel
{
NOT_SET = 0,
TRACE,
DEBUG,
INFO,
WARN,
ERROR
};
enum ELogLevel
{
NOT_SET = 0,
TRACE,
DEBUG,
INFO,
WARN,
ERROR
};
#ifdef VCMI_ANDROID
int toAndroid(ELogLevel logLevel);
#endif
}
/// The class CLoggerDomain provides convenient access to super domains from a sub domain.
@ -36,9 +40,9 @@ class DLL_LINKAGE CLoggerDomain
public:
/// Constructs a CLoggerDomain with the domain designated by name.
/// Sub-domains can be specified by separating domains by a dot, e.g. "ai.battle". The global domain is named "global".
explicit CLoggerDomain(const std::string & name);
explicit CLoggerDomain(std::string name);
std::string getName() const;
const std::string& getName() const;
CLoggerDomain getParent() const;
bool isGlobalDomain() const;
@ -58,8 +62,11 @@ public:
template<typename T>
CLoggerStream & operator<<(const T & data)
{
if(!sbuffer) sbuffer = new std::stringstream();
if(!sbuffer)
sbuffer = new std::stringstream(std::ios_base::out);
(*sbuffer) << data;
return *this;
}
@ -84,18 +91,16 @@ public:
/// Log methods for various log levels
void trace(const std::string & message) const;
CLoggerStream traceStream() const;
void debug(const std::string & message) const;
CLoggerStream debugStream() const;
void info(const std::string & message) const;
CLoggerStream infoStream() const;
void warn(const std::string & message) const;
CLoggerStream warnStream() const;
void error(const std::string & message) const;
/// Log streams for various log levels
CLoggerStream traceStream() const;
CLoggerStream debugStream() const;
CLoggerStream infoStream() const;
CLoggerStream warnStream() const;
CLoggerStream errorStream() const;
inline void log(ELogLevel::ELogLevel level, const std::string & message) const;
@ -184,10 +189,7 @@ struct DLL_LINKAGE LogRecord
{
LogRecord(const CLoggerDomain & domain, ELogLevel::ELogLevel level, const std::string & message)
: domain(domain), level(level), message(message), timeStamp(boost::posix_time::second_clock::local_time()),
threadId(boost::this_thread::get_id())
{
}
threadId(boost::this_thread::get_id()) { }
CLoggerDomain domain;
ELogLevel::ELogLevel level;
@ -208,12 +210,17 @@ class DLL_LINKAGE CLogFormatter
{
public:
CLogFormatter();
CLogFormatter(const std::string & pattern);
CLogFormatter(const CLogFormatter & copy);
CLogFormatter(CLogFormatter && move);
CLogFormatter(const CLogFormatter & other);
CLogFormatter & operator=(const CLogFormatter & other);
CLogFormatter(const std::string & pattern);
CLogFormatter & operator=(const CLogFormatter & copy);
CLogFormatter & operator=(CLogFormatter && move);
void setPattern(const std::string & pattern);
void setPattern(std::string && pattern);
const std::string & getPattern() const;
std::string format(const LogRecord & record) const;
@ -284,8 +291,7 @@ class DLL_LINKAGE CLogFileTarget : public ILogTarget
public:
/// Constructs a CLogFileTarget and opens the file designated by filePath. If the append parameter is true, the file
/// will be appended to. Otherwise the file designated by filePath will be truncated before being opened.
explicit CLogFileTarget(const std::string & filePath, bool append = true);
~CLogFileTarget();
explicit CLogFileTarget(boost::filesystem::path filePath, bool append = true);
const CLogFormatter & getFormatter() const;
void setFormatter(const CLogFormatter & formatter);
@ -293,7 +299,7 @@ public:
void write(const LogRecord & record) override;
private:
std::ofstream file;
boost::filesystem::ofstream file;
CLogFormatter formatter;
mutable boost::mutex mx;
};

View File

@ -13,7 +13,7 @@
*
*/
class BattleInfo;
struct BattleInfo;
class CGameState;
class DLL_LINKAGE CArmedInstance: public CGObjectInstance, public CBonusSystemNode, public CCreatureSet

View File

@ -13,7 +13,7 @@
*
*/
class BankConfig;
struct BankConfig;
class CBankInstanceConstructor;
class DLL_LINKAGE CBank : public CArmedInstance

View File

@ -19,7 +19,7 @@
class CHero;
class CGBoat;
class CGTownInstance;
class TerrainTile;
struct TerrainTile;
class CGHeroPlaceholder : public CGObjectInstance
{

View File

@ -14,7 +14,7 @@
*
*/
class InfoWindow;
struct InfoWindow;
class DLL_LINKAGE CGPandoraBox : public CArmedInstance
{

View File

@ -19,7 +19,7 @@
class CGHeroInstance;
class IGameCallback;
class CGObjectInstance;
class MetaString;
struct MetaString;
struct BattleResult;
class DLL_LINKAGE IObjectInterface

View File

@ -10,75 +10,103 @@
*
*/
// FIXME: Class doesn't contain three float values. Update name and description.
/// Class which consists of three float values. Represents position virtual RMG (0;1) area.
class float3
{
public:
float x, y;
si32 z;
inline float3():x(0),y(0),z(0){}; //c-tor, x/y/z initialized to 0
inline float3(const float X, const float Y, const si32 Z):x(X),y(Y),z(Z){}; //c-tor
inline float3(const float3 & val) : x(val.x), y(val.y), z(val.z){} //copy c-tor
inline float3 & operator=(const float3 & val) {x = val.x; y = val.y; z = val.z; return *this;} //assignemt operator
~float3() {} // d-tor - does nothing
inline float3 operator+(const float3 & i) const //returns float3 with coordinates increased by corresponding coordinate of given float3
{return float3(x+i.x,y+i.y,z+i.z);}
inline float3 operator+(const float i) const //returns float3 with coordinates increased by given numer
{return float3(x+i,y+i,z+i);}
inline float3 operator-(const float3 & i) const //returns float3 with coordinates decreased by corresponding coordinate of given float3
{return float3(x-i.x,y-i.y,z-i.z);}
inline float3 operator-(const float i) const //returns float3 with coordinates decreased by given numer
{return float3(x-i,y-i,z-i);}
inline float3 operator*(const float i) const //returns float3 with plane coordinates decreased by given numer
{return float3(x*i, y*i, z);}
inline float3 operator/(const float i) const //returns float3 with plane coordinates decreased by given numer
{return float3(x/i, y/i, z);}
inline float3 operator-() const //returns opposite position
{return float3(-x,-y,-z);}
inline double dist2d(const float3 &other) const //distance (z coord is not used)
{return std::sqrt((double)(x-other.x)*(x-other.x) + (y-other.y)*(y-other.y));}
inline bool areNeighbours(const float3 &other) const
{return dist2d(other) < 2. && z == other.z;}
inline void operator+=(const float3 & i)
float3() : x(0), y(0), z(0) {}
float3(const float X, const float Y, const si32 Z): x(X), y(Y), z(Z) {}
float3(const float3 & copy) : x(copy.x), y(copy.y), z(copy.z) {}
float3 & operator=(const float3 & copy) { x = copy.x; y = copy.y; z = copy.z; return *this; }
// returns float3 with coordinates increased by corresponding coordinate of given float3
float3 operator+(const float3 & i) const { return float3(x + i.x, y + i.y, z + i.z); }
// returns float3 with coordinates increased by given numer
float3 operator+(const float i) const { return float3(x + i, y + i, z + (si32)i); }
// returns float3 with coordinates decreased by corresponding coordinate of given float3
float3 operator-(const float3 & i) const { return float3(x - i.x, y - i.y, z - i.z); }
// returns float3 with coordinates decreased by given numer
float3 operator-(const float i) const { return float3(x - i, y - i, z - (si32)i); }
// returns float3 with plane coordinates decreased by given numer
float3 operator*(const float i) const {return float3(x * i, y * i, z);}
// returns float3 with plane coordinates decreased by given numer
float3 operator/(const float i) const {return float3(x / i, y / i, z);}
// returns opposite position
float3 operator-() const { return float3(-x, -y, -z); }
// returns squared distance on Oxy plane (z coord is not used)
double dist2dSQ(const float3 & o) const
{
x+=i.x;
y+=i.y;
z+=i.z;
const double dx = (x - o.x);
const double dy = (y - o.y);
return dx*dx + dy*dy;
}
inline void operator+=(const float & i)
// returns distance on Oxy plane (z coord is not used)
double dist2d(const float3 &other) const { return std::sqrt(dist2dSQ(other)); }
bool areNeighbours(const float3 &other) const { return (dist2dSQ(other) < 4.0) && z == other.z; }
float3& operator+=(const float3 & i)
{
x+=i;
y+=i;
z+=i;
x += i.x;
y += i.y;
z += i.z;
return *this;
}
inline void operator-=(const float3 & i)
float3& operator+=(const float & i)
{
x-=i.x;
y-=i.y;
z-=i.z;
x += i;
y += i;
z += (si32)i;
return *this;
}
inline void operator-=(const float & i)
float3& operator-=(const float3 & i)
{
x+=i;
y+=i;
z+=i;
x -= i.x;
y -= i.y;
z -= i.z;
return *this;
}
inline void operator*=(const float & i) //scale on plane
float3& operator-=(const float & i)
{
x*=i;
y*=i;
}
inline void operator/=(const float & i) //scale on plane
{
x/=i;
y/=i;
x += i;
y += i;
z += (si32)i;
return *this;
}
inline bool operator==(const float3 & i) const
{return (x==i.x) && (y==i.y) && (z==i.z);}
inline bool operator!=(const float3 & i) const
{return !(*this==i);}
inline bool operator<(const float3 & i) const
// scale on plane
float3& operator*=(const float & i)
{
x *= i;
y *= i;
return *this;
}
// scale on plane
float3& operator/=(const float & i)
{
x /= i;
y /= i;
return *this;
}
bool operator==(const float3 & i) const { return (x == i.x) && (y == i.y) && (z == i.z); }
bool operator!=(const float3 & i) const { return (x != i.x) || (y != i.y) || (z != i.z); }
bool operator<(const float3 & i) const
{
if (z<i.z)
return true;
@ -92,32 +120,35 @@ public:
return true;
if (x>i.x)
return false;
return false;
}
inline std::string operator ()() const
std::string operator ()() const
{
return "(" + boost::lexical_cast<std::string>(x) +
" " + boost::lexical_cast<std::string>(y) +
" " + boost::lexical_cast<std::string>(z) + ")";
}
inline bool valid() const
bool valid() const
{
return z >= 0; //minimal condition that needs to be fulfilled for tiles in the map
}
template <typename Handler> void serialize(Handler &h, const float version)
{
h & x & y & z;
}
};
inline std::istream & operator>>(std::istream & str, float3 & dest)
{
str>>dest.x>>dest.y>>dest.z;
return str;
return str >> dest.x >> dest.y >> dest.z;
}
inline std::ostream & operator<<(std::ostream & str, const float3 & sth)
{
return str<<sth.x<<' '<<sth.y<<' '<<sth.z;
return str << sth.x << ' ' << sth.y << ' ' << sth.z;
}
struct Shashfloat3

View File

@ -368,19 +368,19 @@ void ERMInterpreter::scanForScripts()
{
using namespace boost::filesystem;
//parser checking
if(!exists(VCMIDirs::get().dataPaths().back() + "/Data/s/"))
const path dataPath = VCMIDirs::get().dataPaths().back() / "Data" / "s";
if(!exists(dataPath))
{
logGlobal->warnStream() << "Warning: Folder " << VCMIDirs::get().dataPaths().back() << "/Data/s/ doesn't exist!";
logGlobal->warnStream() << "Warning: Folder " << dataPath << " doesn't exist!";
return;
}
directory_iterator enddir;
for (directory_iterator dir(VCMIDirs::get().dataPaths().back() + "/Data/s"); dir!=enddir; dir++)
for (directory_iterator dir(dataPath); dir!=enddir; dir++)
{
if(is_regular(dir->status()))
{
std::string name = dir->path().leaf().string();
if( boost::algorithm::ends_with(name, ".erm") ||
boost::algorithm::ends_with(name, ".verm") )
const std::string ext = boost::to_upper_copy(dir->path().extension().string());
if (ext == ".ERM" || ext == ".VERM")
{
ERMParser ep(dir->path().string());
FileInfo * finfo = new FileInfo;

View File

@ -18,7 +18,7 @@
#include "CVCMIServer.h"
#include "../lib/StartInfo.h"
#include "../lib/mapping/CMap.h"
#ifndef __ANDROID__
#ifndef VCMI_ANDROID
#include "../lib/Interprocess.h"
#endif
#include "../lib/VCMI_Lib.h"
@ -32,7 +32,7 @@
#include "../lib/UnlockGuard.h"
#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(__ANDROID__)
#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(VCMI_ANDROID)
#include <execinfo.h>
#endif
@ -41,7 +41,7 @@ std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX
using namespace boost;
using namespace boost::asio;
using namespace boost::asio::ip;
#ifndef __ANDROID__
#ifndef VCMI_ANDROID
namespace intpr = boost::interprocess;
#endif
bool end2 = false;
@ -393,7 +393,7 @@ void CVCMIServer::newPregame()
void CVCMIServer::start()
{
#ifndef __ANDROID__
#ifndef VCMI_ANDROID
ServerReady *sr = nullptr;
intpr::mapped_region *mr;
try
@ -416,7 +416,7 @@ void CVCMIServer::start()
logNetwork->infoStream()<<"Listening for connections at port " << acceptor->local_endpoint().port();
auto s = new tcp::socket(acceptor->get_io_service());
boost::thread acc(std::bind(vaccept,acceptor,s,&error));
#ifndef __ANDROID__
#ifndef VCMI_ANDROID
sr->setToTrueAndNotify();
delete mr;
#endif
@ -560,7 +560,7 @@ static void handleCommandOptions(int argc, char *argv[])
}
}
#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(__ANDROID__)
#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(VCMI_ANDROID)
void handleLinuxSignal(int sig)
{
const int STACKTRACE_SIZE = 100;
@ -591,12 +591,12 @@ int main(int argc, char** argv)
{
// Installs a sig sev segmentation violation handler
// to log stacktrace
#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(__ANDROID__)
#if defined(__GNUC__) && !defined (__MINGW32__) && !defined(VCMI_ANDROID)
signal(SIGSEGV, handleLinuxSignal);
#endif
console = new CConsoleHandler;
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Server_log.txt", console);
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() / "VCMI_Server_log.txt", console);
logConfig.configureDefault();
preinitDLL(console);

View File

@ -22,7 +22,7 @@
CVcmiTestConfig::CVcmiTestConfig()
{
console = new CConsoleHandler;
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Test_log.txt", console);
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() / "VCMI_Test_log.txt", console);
logConfig.configureDefault();
preinitDLL(console);
settings.init();