瀏覽代碼

VCMIDirs update #1

- Class VCMIDirs is now deprecated.
- VCMIDirs now is an namespace, not an singletone.
- VCMIDirs uses now boost::filesystem::path, not a std::string.
Karol 11 年之前
父節點
當前提交
ebc8c9d077
共有 2 個文件被更改,包括 539 次插入247 次删除
  1. 436 210
      lib/VCMIDirs.cpp
  2. 103 37
      lib/VCMIDirs.h

+ 436 - 210
lib/VCMIDirs.cpp

@@ -1,6 +1,3 @@
-#include "StdInc.h"
-#include "VCMIDirs.h"
-
 /*
  * VCMIDirs.cpp, part of VCMI engine
  *
@@ -11,241 +8,470 @@
  *
  */
 
-static VCMIDirs VCMIDirsGlobal;
-
-VCMIDirs::VCMIDirs()
-{
-	// 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());
-}
-
-VCMIDirs & VCMIDirs::get()
-{
-	return VCMIDirsGlobal;
-}
-
-//FIXME: find way to at least decrease size of this ifdef (along with cleanup in CMake)
-#if defined(_WIN32)
-
-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
-{
-	const std::string homeDir = std::getenv("userprofile");
-	return homeDir + "\\vcmi";
-	//return dataPaths()[0];
-}
-
-std::string VCMIDirs::libraryPath() const
-{
-	return ".";
-}
-
-std::string VCMIDirs::clientPath() const
-{
-	return libraryPath() + "\\" + "VCMI_client.exe";
-}
-
-std::string VCMIDirs::serverPath() const
-{
-	return libraryPath() + "\\" + "VCMI_server.exe";
-}
-
-std::vector<std::string> VCMIDirs::dataPaths() const
-{
-	return std::vector<std::string>(1, ".");
-}
-
-std::string VCMIDirs::libraryName(std::string basename) const
-{
-	return basename + ".dll";
-}
-
-#elif defined(__APPLE__)
-
-std::string VCMIDirs::userCachePath() const
-{
-	return userDataPath();
-}
-
-std::string VCMIDirs::userConfigPath() const
-{
-	return userDataPath() + "/config";
-}
+#include "StdInc.h"
+#include "VCMIDirs.h"
 
-std::string VCMIDirs::userSavePath() const
-{
-	return userDataPath() + "/Games";
-}
+namespace bfs = boost::filesystem;
 
-std::string VCMIDirs::userDataPath() const
+namespace VCMIDirs
 {
-	// 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();
-}
+	namespace detail
+	{
+		bfs::path g_user_data_path;
+		bfs::path g_user_cache_path;
+		bfs::path g_user_config_path;
+		bfs::path g_user_save_path;
+		
+		bfs::path g_library_path;
+		bfs::path g_client_path;
+		bfs::path g_server_path;
+
+		std::vector<bfs::path> g_data_paths;
+
+		std::string g_help_string;
+
+		extern bfs::path GetDataPath();
+		extern bfs::path GetCachePath();
+		extern bfs::path GetConfigPath();
+		extern bfs::path GetUserSavePath();
+		
+		extern bfs::path GetLibraryPath();
+		extern bfs::path GetClientPath();
+		extern bfs::path GetServerPath();
+		extern std::vector<bfs::path> GetDataPaths();
+	
+		extern std::string GetHelpString();
+	}
+	
+	void InitAllPathes(void)
+	{
+		detail::g_user_data_path = detail::GetDataPath();
+		detail::g_user_cache_path = detail::GetCachePath();
+		detail::g_user_config_path = detail::GetConfigPath();
+		detail::g_user_save_path = detail::GetUserSavePath();
 
-std::string VCMIDirs::libraryPath() const
-{
-	return ".";
-}
+		detail::g_library_path = detail::GetLibraryPath();
+		detail::g_client_path = detail::GetClientPath();
+		detail::g_server_path = detail::GetServerPath();
 
-std::string VCMIDirs::clientPath() const
-{
-	return "./vcmiclient";
-}
+		detail::g_data_paths = detail::GetDataPaths();
 
-std::string VCMIDirs::serverPath() const
-{
-	return "./vcmiserver";
-}
+		detail::g_help_string = detail::GetHelpString();
 
-std::vector<std::string> VCMIDirs::dataPaths() const
-{
-	return std::vector<std::string>(1, "../Data");
-}
+		// initialize local directory and create folders to which VCMI needs write access
+		bfs::create_directory(detail::g_user_data_path);
+		bfs::create_directory(detail::g_user_cache_path);
+		bfs::create_directory(detail::g_user_config_path);
+		bfs::create_directory(detail::g_user_save_path);
+	}
 
-std::string VCMIDirs::libraryName(std::string basename) const
-{
-	return "lib" + basename + ".dylib";
+	namespace detail
+	{
+		struct InitAllPathes_ctor
+		{
+			InitAllPathes_ctor() { InitAllPathes(); }
+		} InitAllPathes_ctor_global_obj;
+	};
+
+	// TODO: Remove _VCMIDirs
+	static _VCMIDirs _VCMIDirsGlobal;
+	_VCMIDirs & get()
+	{
+		puts("VCMIDirs::get() - used of deprecated function :#");
+		return _VCMIDirsGlobal;
+	}
 }
 
-#else
+// FIXME: find way to at least decrease size of this ifdef (along with cleanup in CMake)
+#ifdef _WIN32
+// This part should be moved into separate file (for example: VCMIDirs_win32.cpp)
+// WinAPI
+#include <Windows.h>
+#include <Shlobj.h>
 
-std::string VCMIDirs::libraryName(std::string basename) const
+namespace VCMIDirs
 {
-	return "lib" + basename + ".so";
-}
+	namespace detail
+	{
+		bfs::path GetDataPath()
+		{
+			const char* profile_dir_a;
+			wchar_t profile_dir_w[MAX_PATH];
+
+			// The user's profile folder. A typical path is C:\Users\username.
+			// FIXME: Applications should not create files or folders at this level;
+			// they should put their data under the locations referred to by CSIDL_APPDATA or CSIDL_LOCAL_APPDATA.
+			if (SHGetSpecialFolderPathW(nullptr, profile_dir_w, CSIDL_PROFILE, FALSE) == FALSE) // WinAPI way failed
+			{
+				if (profile_dir_a = std::getenv("userprofile")) // STL way succeed
+					return bfs::path(profile_dir_a) / "vcmi";
+				else
+					return "."; // Every thing failed, return current directory.
+			}
+			else
+				return bfs::path(profile_dir_w) / "vcmi";
+
+			//return dataPaths()[0] ???;
+		}
+
+		bfs::path GetCachePath()
+		{
+			return GetDataPath();
+		}
+
+		bfs::path GetConfigPath()
+		{
+			return GetDataPath() / "config";
+		}
+
+		bfs::path GetUserSavePath()
+		{
+			return GetDataPath() / "Games";
+		}
+
+		bfs::path GetLibraryPath()
+		{
+			return ".";
+		}
+
+		bfs::path GetClientPath()
+		{
+			return GetLibraryPath() / "VCMI_client.exe";
+		}
+
+		bfs::path GetServerPath()
+		{
+			return GetLibraryPath() / "VCMI_server.exe";
+		}
+	
+		std::vector<bfs::path> GetDataPaths()
+		{
+			return std::vector<bfs::path>(1, bfs::path("."));
+		}
+
+		std::string GetHelpString()
+		{
+			// I think this function should have multiple versions
+			// 1. For various arguments
+			// 2. Inverse functions
+			// and should be moved to vstd
+			// or use http://utfcpp.sourceforge.net/
+			auto utf8_convert = [](const bfs::path& path) -> std::string
+			{
+				const auto& path_string = path.native();
+				auto perform_convert = [&path_string](LPSTR output, int output_size)
+				{
+					return WideCharToMultiByte(
+						CP_UTF8,				// Use wchar_t -> utf8 char_t
+						WC_ERR_INVALID_CHARS,	// Fails when invalid char occur
+						path_string.c_str(),	// String to convert
+						path_string.size(),		// String to convert size
+						output,					// Result
+						output_size,			// Result size
+						nullptr, nullptr);		// For the ... CP_UTF8 settings for CodePage, this parameter must be set to NULL
+				};
+
+				int char_count = perform_convert(nullptr, 0); // Result size (0 - obtain size)
+				if (char_count > 0)
+				{
+					std::unique_ptr<char[]> buffer(new char[char_count]);
+					if ((char_count = perform_convert(buffer.get(), char_count)) > 0)
+						return std::string(buffer.get(), char_count);
+				}
+
+				// Conversion failed :C
+				return path.string();
+			};
+
+			std::vector<std::string> temp_vec;
+			for (const bfs::path& path : GetDataPaths())
+				temp_vec.push_back(utf8_convert(path));
+			std::string gd_string_a = boost::algorithm::join(temp_vec, L";");
+
+			
+			return
+				"  game data:   " + gd_string_a + "\n" +
+				"  libraries:   " + utf8_convert(GetLibraryPath()) + "\n" +
+				"  server:      " + utf8_convert(GetServerPath()) + "\n" +
+				"\n" +
+				"  user data:   " + utf8_convert(GetDataPath()) + "\n" +
+				"  user cache:  " + utf8_convert(GetCachePath()) + "\n" +
+				"  user config: " + utf8_convert(GetConfigPath()) + "\n" +
+				"  user saves:  " + utf8_convert(GetUserSavePath()) + "\n"; // Should end without new-line?
+		}
+	}
 
-std::string VCMIDirs::libraryPath() const
-{
-	return M_LIB_DIR;
+	std::string libraryName(const std::string& basename)
+	{
+		return basename + ".dll";
+	}
 }
 
-std::string VCMIDirs::clientPath() const
-{
-	return std::string(M_BIN_DIR) + "/" + "vcmiclient";
-}
+#elif defined (__APPLE__)
+// This part should be moved to separate file (for example: VCMIDirs_apple.cpp)
 
-std::string VCMIDirs::serverPath() const
+namespace VCMIDirs
 {
-	return std::string(M_BIN_DIR) + "/" + "vcmiserver";
-}
+	namespace detail
+	{
+		bfs::path GetDataPath()
+		{
+			// 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
+
+			const char* home_dir = getenv("HOME"); // Should be std::getenv?
+			if (home_dir == nullptr)
+				home_dir = ".";
+			return bfs::path(home_dir) / "Library" / "Application Support" / "vcmi";
+		}
+
+		bfs::path GetCachePath()
+		{
+			return GetDataPath();
+		}
+
+		bfs::path GetConfigPath()
+		{
+			return GetDataPath() / "config";
+		}
+
+		bfs::path GetUserSavePath()
+		{
+			return GetDataPath() / "Games";
+		}
+
+		bfs::path GetLibraryPath()
+		{
+			return ".";
+		}
+
+		bfs::path GetClientPath()
+		{
+			return "./vcmiclient";
+		}
+
+		bfs::path GetServerPath()
+		{
+			return "./vcmiserver";
+		}
+
+		std::vector<bfs::path> GetDataPaths()
+		{
+			return std::vector<std::string>(1, "../Data");
+		}
+
+		std::string GetHelpString()
+		{
+			std::vector<std::string> temp_vec;
+			for (const bfs::path& path : GetDataPaths())
+				temp_vec.push_back(path.string());
+
+			return
+				"  game data:   " + boost::algorithm::join(temp_vec, ":") + "\n" +
+				"  libraries:   " + GetLibraryPath().string() + "\n" +
+				"  server:      " + GetServerPath().string() + "\n" +
+				"\n" +
+				"  user data:   " + GetDataPath().string() + "\n" +
+				"  user cache:  " + GetCachePath().string() + "\n" +
+				"  user config: " + GetConfigPath().string() + "\n" +
+				"  user saves:  " + GetUserSavePath().string() + "\n"; // Should end without new-line?
+		}
+	}
 
-// $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 libraryName(const std::string& basename)
+	{
+		return "lib" + basename + ".dylib";
+	}
 }
+#elif defined __ANDROID__
+// This part should be moved to separate file (for example: VCMIDirs_android.cpp)
 
-std::string VCMIDirs::userSavePath() const
+namespace VCMIDirs
 {
-	return userDataPath() + "/Saves";
-}
+	namespace detail
+	{
+		bfs::path GetDataPath()
+		{
+			// on Android HOME will be set to something like /sdcard/data/Android/is.xyz.vcmi/files/
+			return getenv("HOME");
+		}
+
+		bfs::path GetCachePath()
+		{
+			return GetDataPath() / "cache";
+		}
+
+		bfs::path GetConfigPath()
+		{
+			return GetDataPath() / "config";
+		}
+
+		bfs::path GetUserSavePath()
+		{
+			return GetDataPath() / "Saves"; // Why different than other platforms???
+		}
+
+		bfs::path GetLibraryPath()
+		{
+			return M_LIB_DIR;
+		}
+
+		bfs::path GetClientPath()
+		{
+			return bfs::path(M_BIN_DIR) / "vcmiclient";
+		}
+
+		bfs::path GetServerPath()
+		{
+			return bfs::path(M_BIN_DIR) / "vcmiserver";
+		}
+
+		std::vector<bfs::path> GetDataPaths()
+		{
+			return std::vector<bfs::path>(1, GetDataPath());
+		}
+
+		std::string GetHelpString()
+		{
+			std::vector<std::string> temp_vec;
+			for (const bfs::path& path : GetDataPaths())
+				temp_vec.push_back(path.string());
+
+			return
+				"  game data:   " + boost::algorithm::join(temp_vec, ":") + "\n" +
+				"  libraries:   " + GetLibraryPath().string() + "\n" +
+				"  server:      " + GetServerPath().string() + "\n" +
+				"\n" +
+				"  user data:   " + GetDataPath().string() + "\n" +
+				"  user cache:  " + GetCachePath().string() + "\n" +
+				"  user config: " + GetConfigPath().string() + "\n" +
+				"  user saves:  " + GetUserSavePath().string() + "\n"; // Should end without new-line?
+		}
+	}
 
-// $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
+	std::string libraryName(const std::string& basename)
+	{
+		return "lib" + basename + ".so";
+	}
 }
-
-// $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
-}
+// This part should be moved to separate file (for example: VCMIDirs_default.cpp)
 
-// $XDG_DATA_DIRS, default: /usr/local/share/:/usr/share/
-std::vector<std::string> VCMIDirs::dataPaths() const
+namespace VCMIDirs
 {
-	// construct list in reverse.
-	// in specification first directory has highest priority
-	// in vcmi fs last directory has highest priority
-
-	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");
-	ret.push_back(M_DATA_DIR);
-
-	if (getenv("XDG_DATA_DIRS") != nullptr)
+	namespace detail
 	{
-		std::string dataDirsEnv = getenv("XDG_DATA_DIRS");
-		std::vector<std::string> dataDirs;
-		boost::split(dataDirs, dataDirsEnv, boost::is_any_of(":"));
-		for (auto & entry : boost::adaptors::reverse(dataDirs))
-			ret.push_back(entry + "/vcmi");
+		// $XDG_DATA_HOME, default: $HOME/.local/share
+		bfs::path GetDataPath()
+		{
+			const char* home_dir;
+			if (home_dir = getenv("XDG_DATA_HOME"))
+				return = home_dir;
+			else if (home_dir = getenv("HOME"))
+				return = bfs::path(home_dir) / ".local" / "share" / "vcmi";
+			else
+				return ".";
+		}
+		
+		// $XDG_CACHE_HOME, default: $HOME/.cache
+		bfs::path GetCachePath()
+		{
+			const char* home_dir;
+			if (home_dir = getenv("XDG_CACHE_HOME"))
+				return bfs::path(home_dir) / "vcmi";
+			else if (home_dir = getenv("HOME"))
+				return bfs::path(home_dir) / ".cache" / "vcmi";
+			else
+				return ".";
+		}
+
+		// $XDG_CONFIG_HOME, default: $HOME/.config
+		bfs::path GetConfigPath()
+		{
+			const char* home_dir;
+			if (home_dir = getenv("XDG_CONFIG_HOME"))
+				return bfs:path(home_dir) / "vcmi";
+			else if (home_dir = getenv("HOME"))
+				return bfs::path(home_dir) / ".config" / "vcmi";
+			else
+				return ".";
+		}
+
+		bfs::path GetUserSavePath()
+		{
+			return GetDataPath() / "Saves"; // Why different than other platforms???
+		}
+
+		bfs::path GetLibraryPath()
+		{
+			return M_LIB_DIR;
+		}
+
+		bfs::path GetClientPath()
+		{
+			return bfs::path(M_BIN_DIR) / "vcmiclient";
+		}
+
+		bfs::path GetServerPath()
+		{
+			return bfs::path(M_BIN_DIR) / "vcmiserver";
+		}
+
+		std::vector<bfs::path> GetDataPaths()
+		{
+			// $XDG_DATA_DIRS, default: /usr/local/share/:/usr/share/
+
+			// construct list in reverse.
+			// in specification first directory has highest priority
+			// in vcmi fs last directory has highest priority
+			std::vector<bfs::path> ret;
+
+			const char* home_dir;
+			if (home_dir = getenv("HOME")) // compatibility, should be removed after 0.96
+				ret.push_back(bfs::path(home_dir) / ".vcmi");
+			ret.push_back(M_DATA_DIR);
+
+			if (home_dir = getenv("XDG_DATA_DIRS") != nullptr)
+			{
+				std::string dataDirsEnv = home_dir;
+				std::vector<std::string> dataDirs;
+				boost::split(dataDirs, dataDirsEnv, boost::is_any_of(":"));
+				for (auto & entry : boost::adaptors::reverse(dataDirs))
+					ret.push_back(entry + "/vcmi");
+			}
+			else
+			{
+				ret.push_back("/usr/share/");
+				ret.push_back("/usr/local/share/");
+			}
+
+			return ret;
+		}
+
+		std::string GetHelpString()
+		{
+			std::vector<std::string> temp_vec;
+			for (const bfs::path& path : GetDataPaths())
+				temp_vec.push_back(path.string());
+
+			return
+				"  game data:   " + boost::algorithm::join(temp_vec, ":") + "\n" +
+				"  libraries:   " + GetLibraryPath().string() + "\n" +
+				"  server:      " + GetServerPath().string() + "\n" +
+				"\n" +
+				"  user data:   " + GetDataPath().string() + "\n" +
+				"  user cache:  " + GetCachePath().string() + "\n" +
+				"  user config: " + GetConfigPath().string() + "\n" +
+				"  user saves:  " + GetUserSavePath().string() + "\n"; // Should end without new-line?
+		}
 	}
-	else
+
+	std::string libraryName(const std::string& basename)
 	{
-		ret.push_back("/usr/share/");
-		ret.push_back("/usr/local/share/");
+		return "lib" + basename + ".so";
 	}
-#endif
-	return ret;
-}
-
-#endif
-
-std::string VCMIDirs::genHelpString() const
-{
-	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";
 }
+#endif

+ 103 - 37
lib/VCMIDirs.h

@@ -1,52 +1,118 @@
+/*
+* 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"
+// Boost
+#include <boost/filesystem/path.hpp>
 
-/*
- * 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
+// STL C++
+#include <string>
+#include <vector>
+
+// TODO: Remove _VCMIDirs
+class _VCMIDirs;
+
+// Where to find the various VCMI files. This is mostly useful for linux. 
+namespace VCMIDirs
 {
-public:
-	VCMIDirs();
+	namespace detail
+	{
+		extern DLL_LINKAGE boost::filesystem::path g_user_data_path;
+		extern DLL_LINKAGE boost::filesystem::path g_user_cache_path;
+		extern DLL_LINKAGE boost::filesystem::path g_user_config_path;
+		extern DLL_LINKAGE boost::filesystem::path g_user_save_path;
+
+		extern DLL_LINKAGE boost::filesystem::path g_library_path;
+		extern DLL_LINKAGE boost::filesystem::path g_client_path;
+		extern DLL_LINKAGE boost::filesystem::path g_server_path;
+
+		extern DLL_LINKAGE std::vector<boost::filesystem::path> g_data_paths;
+
+		extern DLL_LINKAGE std::string g_help_string;
+	}
+
+	/// deprecated: get singleton instance
+	extern DLL_LINKAGE _VCMIDirs & get();
+
+	// Path to user-specific data directory
+	inline const boost::filesystem::path& userDataPath() { return detail::g_user_data_path; }
 
-	/// get singleton instance
-	static VCMIDirs & get();
+	// Path to "cache" directory, can be used for any non-essential files
+	inline const boost::filesystem::path& userCachePath() { return detail::g_user_cache_path; }
 
-	/// Path to user-specific data directory
-	std::string userDataPath() const;
+	// Path to writeable directory with user configs
+	inline const boost::filesystem::path& userConfigPath() { return detail::g_user_config_path; }
+
+	// Path to saved games
+	inline const boost::filesystem::path& userSavePath() { return detail::g_user_save_path; }
+
+	// Paths to global system-wide data directories. First items have higher priority
+	inline const std::vector<boost::filesystem::path>& dataPaths() { return detail::g_data_paths; }
+
+	// Full path to client executable, including server name (e.g. /usr/bin/vcmiclient)
+	inline const boost::filesystem::path& clientPath() { return detail::g_client_path; }
+
+	// Full path to server executable, including server name (e.g. /usr/bin/vcmiserver)
+	inline const boost::filesystem::path& serverPath() { return detail::g_server_path; }
+
+	// Path where vcmi libraries can be found (in AI and Scripting subdirectories)
+	inline const boost::filesystem::path& libraryPath() { return detail::g_library_path; }
+
+	// Returns system-specific name for dynamic libraries ( StupidAI => "libStupidAI.so" or "StupidAI.dll")
+	extern DLL_LINKAGE std::string libraryName(const std::string& basename);
+	//extern DLL_LINKAGE std::string libraryName(const char* basename);
+	//extern DLL_LINKAGE std::string libraryName(std::string&& basename);
+
+
+	inline const std::string& genHelpString() { return detail::g_help_string; }
+}
+
+// TODO: Remove _VCMIDirs
+// This class is deprecated
+class DLL_LINKAGE _VCMIDirs
+{
+public:
+	/// deprecated: Path to user-specific data directory
+	std::string userDataPath() const { return VCMIDirs::userDataPath().string(); }
 
-	/// Path to "cache" directory, can be used for any non-essential files
-	std::string userCachePath() const;
+	/// deprecated: Path to "cache" directory, can be used for any non-essential files
+	std::string userCachePath() const { return VCMIDirs::userCachePath().string(); }
 
-	/// Path to writeable directory with user configs
-	std::string userConfigPath() const;
+	/// deprecated: Path to writeable directory with user configs
+	std::string userConfigPath() const { return VCMIDirs::userConfigPath().string(); }
 
-	/// Path to saved games
-	std::string userSavePath() const;
+	/// deprecated: Path to saved games
+	std::string userSavePath() const { return VCMIDirs::userSavePath().string(); }
 
-	/// Paths to global system-wide data directories. First items have higher priority
-	std::vector<std::string> dataPaths() const;
+	/// deprecated: Paths to global system-wide data directories. First items have higher priority
+	std::vector<std::string> dataPaths() const
+	{
+		std::vector<std::string> result;
+		for (const auto& path : VCMIDirs::dataPaths())
+			result.push_back(path.string());
+		return result;
+	}
 
-	/// Full path to client executable, including server name (e.g. /usr/bin/vcmiclient)
-	std::string clientPath() const;
+	/// deprecated: Full path to client executable, including server name (e.g. /usr/bin/vcmiclient)
+	std::string clientPath() const { return VCMIDirs::clientPath().string(); }
 
-	/// Full path to server executable, including server name (e.g. /usr/bin/vcmiserver)
-	std::string serverPath() const;
+	/// deprecated: Full path to server executable, including server name (e.g. /usr/bin/vcmiserver)
+	std::string serverPath() const { return VCMIDirs::serverPath().string(); }
 
-	/// Path where vcmi libraries can be found (in AI and Scripting subdirectories)
-	std::string libraryPath() const;
+	/// deprecated: Path where vcmi libraries can be found (in AI and Scripting subdirectories)
+	std::string libraryPath() const { return VCMIDirs::libraryPath().string(); }
 
-	/// Returns system-specific name for dynamic libraries ( StupidAI => "libStupidAI.so" or "StupidAI.dll")
-	std::string libraryName(std::string basename) const;
+	/// deprecated: Returns system-specific name for dynamic libraries ( StupidAI => "libStupidAI.so" or "StupidAI.dll")
+	std::string libraryName(std::string basename) const { return VCMIDirs::libraryName(basename); }
 
-	std::string genHelpString() const;
-};
+	/// deprecated:
+	std::string genHelpString() const { return VCMIDirs::genHelpString(); }
+};