Selaa lähdekoodia

- moved all system-specific handling of filesystem to VCMIDirs.cpp (new file)
- fixed #1128, artifact constituents are now stored as pointers

Ivan Savenko 12 vuotta sitten
vanhempi
sitoutus
b5fcefe455

+ 7 - 7
client/CMT.cpp

@@ -155,9 +155,9 @@ void init()
 static void prog_version(void)
 {
 	printf("%s\n", GameConstants::VCMI_VERSION.c_str());
-	printf("  data directory:    %s\n", GameConstants::DATA_DIR.c_str());
-	printf("  library directory: %s\n", GameConstants::LIB_DIR.c_str());
-	printf("  binary directory:  %s\n", GameConstants::BIN_DIR.c_str());
+	printf("  data directory:    %s\n", VCMIDirs::get().dataPath().c_str());
+	printf("  library directory: %s\n", VCMIDirs::get().libraryPath().c_str());
+	printf("  path to server:    %s\n", VCMIDirs::get().serverPath().c_str());
 }
 
 static void prog_help(const po::options_description &opts)
@@ -195,7 +195,7 @@ int main(int argc, char** argv)
     OSX_checkForUpdates();
 
     // Check that game data is prepared. Otherwise run vcmibuilder helper application
-    FILE* check = fopen((GVCMIDirs.UserPath + "/game_data_prepared").c_str(), "r");
+    FILE* check = fopen((VCMIDirs::get().localPath() + "/game_data_prepared").c_str(), "r");
     if (check == NULL) {
         system("open ./vcmibuilder.app");
         return 0;
@@ -253,7 +253,7 @@ int main(int argc, char** argv)
 
 	CStopWatch total, pomtime;
 	std::cout.flags(std::ios::unitbuf);
-	logfile = new std::ofstream((GVCMIDirs.UserPath + "/VCMI_Client_log.txt").c_str());
+	logfile = new std::ofstream((VCMIDirs::get().localPath() + "/VCMI_Client_log.txt").c_str());
 	console = new CConsoleHandler;
 	*console->cb = boost::bind(&processCommand, _1);
 	console->start();
@@ -287,8 +287,8 @@ int main(int argc, char** argv)
 	{
 		tlog0 << "Fatal error: failed to load settings!\n";
 		tlog0 << "Possible reasons:\n";
-		tlog0 << "\tCorrupted local configuration file at " << GVCMIDirs.UserPath << "/config/settings.json\n";
-		tlog0 << "\tMissing or corrupted global configuration file at " << GameConstants::DATA_DIR << "/config/defaultSettings.json\n";
+		tlog0 << "\tCorrupted local configuration file at " << VCMIDirs::get().localPath() << "/config/settings.json\n";
+		tlog0 << "\tMissing or corrupted global configuration file at " << VCMIDirs::get().dataPath() << "/config/defaultSettings.json\n";
 		tlog0 << "VCMI will now exit...\n";
 		exit(EXIT_FAILURE);
 	}

+ 1 - 1
client/CPlayerInterface.cpp

@@ -1590,7 +1590,7 @@ int CPlayerInterface::getLastIndex( std::string namePrefix)
 	using namespace boost::filesystem;
 	using namespace boost::algorithm;
 
-	path gamesDir = GVCMIDirs.UserPath + "/Games";
+	path gamesDir = VCMIDirs::get().localPath() + "/Games";
 	std::map<std::time_t, int> dates; //save number => datestamp
 
 	directory_iterator enddir;

+ 2 - 2
client/Client.cpp

@@ -763,8 +763,8 @@ CServerHandler::~CServerHandler()
 void CServerHandler::callServer()
 {
 	setThreadName("CServerHandler::callServer");
-	std::string logName = GVCMIDirs.UserPath + "/server_log.txt";
-	std::string comm = GameConstants::BIN_DIR + GameConstants::PATH_SEPARATOR + GameConstants::SERVER_NAME + " " + port + " > " + logName;
+	std::string logName = VCMIDirs::get().localPath() + "/server_log.txt";
+	std::string comm = VCMIDirs::get().serverPath() + " " + port + " > " + logName;
 	int result = std::system(comm.c_str());
 	if (result == 0)
 		tlog1 << "Server closed correctly\n";

+ 10 - 17
lib/CArtHandler.cpp

@@ -359,26 +359,20 @@ void CArtHandler::loadArtifactJson(CArtifact * art, const JsonNode & artifact)
 
 	if (!artifact["components"].isNull())
 	{
-		art->constituents.reset(new std::vector<ArtifactID>());
+		art->constituents.reset(new std::vector<CArtifact *>());
 		BOOST_FOREACH (auto component, artifact["components"].Vector())
 		{
-			VLC->modh->identifiers.requestIdentifier("artifact." + component.String(), [art](si32 id)
+			VLC->modh->identifiers.requestIdentifier("artifact." + component.String(), [=](si32 id)
 			{
 				// when this code is called both combinational art as well as component are loaded
 				// so it is safe to access any of them
-				art->addConstituent(ArtifactID(id));
-				VLC->arth->artifacts[id]->constituentOf.push_back(art->id);
+				art->constituents->push_back(VLC->arth->artifacts[id]);
+				VLC->arth->artifacts[id]->constituentOf.push_back(art);
 			});
 		}
 	}
 }
 
-void CArtifact::addConstituent (ArtifactID component)
-{
-	assert (constituents); // not a combinational art
-	constituents->push_back (component);
-}
-
 ArtifactID CArtHandler::creatureToMachineID(CreatureID id)
 {
 	int dif = 142;
@@ -745,15 +739,14 @@ std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CA
 	if(artType->constituents) //combined artifact already: no combining of combined artifacts... for now.
 		return ret;
 
-	BOOST_FOREACH(ui32 possibleCombinedArt, artType->constituentOf)
+	BOOST_FOREACH(const CArtifact * artifact, artType->constituentOf)
 	{
-		const CArtifact * const artifact = VLC->arth->artifacts[possibleCombinedArt];
 		assert(artifact->constituents);
 		bool possible = true;
 
-		BOOST_FOREACH(ui32 constituentID, *artifact->constituents) //check if all constituents are available
+		BOOST_FOREACH(const CArtifact * constituent, *artifact->constituents) //check if all constituents are available
 		{
-			if(!h->hasArt(constituentID, true)) //constituent must be equipped
+			if(!h->hasArt(constituent->id, true)) //constituent must be equipped
 			{
 				possible = false;
 				break;
@@ -876,15 +869,15 @@ void CCombinedArtifactInstance::createConstituents()
 	assert(artType);
 	assert(artType->constituents);
 
-	BOOST_FOREACH(ui32 a, *artType->constituents)
+	BOOST_FOREACH(const CArtifact * art, *artType->constituents)
 	{
-		addAsConstituent(CArtifactInstance::createNewArtifactInstance(a), ArtifactPosition::PRE_FIRST);
+		addAsConstituent(CArtifactInstance::createNewArtifactInstance(art->id), ArtifactPosition::PRE_FIRST);
 	}
 }
 
 void CCombinedArtifactInstance::addAsConstituent(CArtifactInstance *art, ArtifactPosition slot)
 {
-	assert(vstd::contains(*artType->constituents, art->artType->id));
+	assert(vstd::contains(*artType->constituents, art->artType.get()));
 	assert(art->getParentNodes().size() == 1  &&  art->getParentNodes().front() == art->artType);
 	constituentsInfo.push_back(ConstituentInfo(art, slot));
 	attachTo(art);

+ 2 - 3
lib/CArtHandler.h

@@ -57,7 +57,6 @@ public:
 	const std::string &EventText() const;
 
 	bool isBig () const;
-	void addConstituent (ArtifactID component);
 
 	int getArtClassSerial() const; //0 - treasure, 1 - minor, 2 - major, 3 - relic, 4 - spell scroll, 5 - other
 	std::string nodeName() const override;
@@ -67,8 +66,8 @@ public:
 
 	ui32 price;
 	bmap<ArtBearer::ArtBearer, std::vector<ArtifactPosition> > possibleSlots; //Bearer Type => ids of slots where artifact can be placed
-	std::unique_ptr<std::vector<ArtifactID> > constituents; // Artifacts IDs a combined artifact consists of, or NULL.
-	std::vector<ArtifactID> constituentOf; // Reverse map of constituents - combined arts that include this art
+	std::unique_ptr<std::vector<CArtifact *> > constituents; // Artifacts IDs a combined artifact consists of, or NULL.
+	std::vector<CArtifact *> constituentOf; // Reverse map of constituents - combined arts that include this art
 	EartClass aClass;
 	ArtifactID id;
 

+ 3 - 17
lib/CGameInterface.cpp

@@ -2,7 +2,7 @@
 #include "CGameInterface.h"
 
 #include "BattleState.h"
-#include "GameConstants.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
@@ -72,26 +72,12 @@ rett * createAny(std::string dllname, std::string methodName)
 	return ret;
 }
 
-//Currently AI libraries use "lib" prefix only on non-win systems.
-//May be applied to Win systems as well to remove this ifdef
-#ifdef _WIN32
-std::string getAIFileName(std::string input)
-{
-	return input + '.' + GameConstants::LIB_EXT;
-}
-#else
-std::string getAIFileName(std::string input)
-{
-	return "lib" + input + '.' + GameConstants::LIB_EXT;
-}
-#endif
-
 template<typename rett>
 rett * createAnyAI(std::string dllname, std::string methodName)
 {
 	tlog1<<"Opening "<<dllname<<"\n";
-	std::string filename = getAIFileName(dllname);
-	rett* ret = createAny<rett>(GameConstants::LIB_DIR + "/AI/" + filename, methodName);
+	std::string filename = VCMIDirs::get().libraryName(dllname);
+	rett* ret = createAny<rett>(VCMIDirs::get().libraryPath() + "/AI/" + filename, methodName);
 	ret->dllName = dllname;
 	return ret;
 }

+ 1 - 0
lib/CMakeLists.txt

@@ -52,6 +52,7 @@ set(lib_SRCS
 		ResourceSet.cpp
 		RegisterTypes.cpp
 		VCMI_Lib.cpp
+		VCMIDirs.cpp
 )
 
 set(lib_HEADERS

+ 3 - 3
lib/Filesystem/CResourceLoader.cpp

@@ -321,16 +321,16 @@ void CResourceHandler::initialize()
 	initialLoader = new CResourceLoader;
 	resourceLoader = new CResourceLoader;
 
-	shared_ptr<ISimpleResourceLoader> rootDir(new CFilesystemLoader(GameConstants::DATA_DIR, 0, true));
+	shared_ptr<ISimpleResourceLoader> rootDir(new CFilesystemLoader(VCMIDirs::get().dataPath(), 0, true));
 	initialLoader->addLoader("GLOBAL/", rootDir, false);
 	initialLoader->addLoader("ALL/", rootDir, false);
 
 	auto userDir = rootDir;
 
 	//add local directory to "ALL" but only if it differs from root dir (true for linux)
-	if (GameConstants::DATA_DIR != GVCMIDirs.UserPath)
+	if (VCMIDirs::get().dataPath() != VCMIDirs::get().localPath())
 	{
-		userDir = shared_ptr<ISimpleResourceLoader>(new CFilesystemLoader(GVCMIDirs.UserPath, 0, true));
+		userDir = shared_ptr<ISimpleResourceLoader>(new CFilesystemLoader(VCMIDirs::get().localPath(), 0, true));
 		initialLoader->addLoader("ALL/", userDir, false);
 	}
 

+ 1 - 41
lib/GameConstants.h

@@ -16,46 +16,6 @@ namespace GameConstants
 {
 	const std::string VCMI_VERSION = "VCMI 0.92";
 
-	/*
-	 * DATA_DIR contains the game data (Data/, MP3/, ...).
-	 * BIN_DIR is where the vcmiclient/vcmiserver binaries reside
-	 * LIB_DIR is where the AI libraries reside (linux only)
-	 */
-	#if defined(_WIN32)
-		const std::string DATA_DIR = ".";
-		const std::string BIN_DIR = ".";
-		const std::string LIB_DIR = ".";
-		const std::string SERVER_NAME = "VCMI_server.exe";
-		const std::string LIB_EXT = "dll";
-		const std::string PATH_SEPARATOR = "\\";
-	#elif defined(__APPLE__)
-		const std::string DATA_DIR = "../Data";
-        const std::string BIN_DIR = ".";
-        const std::string LIB_DIR = ".";
-        const std::string SERVER_NAME = "./vcmiserver";
-        const std::string LIB_EXT = "dylib";
-        const std::string PATH_SEPARATOR = "/";
-    #else
-        #ifndef M_DATA_DIR
-		#error M_DATA_DIR undefined.
-		#else
-		const std::string DATA_DIR = M_DATA_DIR;
-		#endif
-		#ifndef M_BIN_DIR
-		#error M_BIN_DIR undefined.
-		#else
-		const std::string BIN_DIR = M_BIN_DIR;
-		#endif
-		#ifndef M_LIB_DIR
-		#error M_LIB_DIR undefined.
-		#else
-		const std::string LIB_DIR = M_LIB_DIR;
-		#endif
-		const std::string SERVER_NAME = "vcmiserver";
-		const std::string LIB_EXT = "so";
-		const std::string PATH_SEPARATOR = "/";
-	#endif
-
 	const int BFIELD_WIDTH = 17;
 	const int BFIELD_HEIGHT = 11;
 	const int BFIELD_SIZE = BFIELD_WIDTH * BFIELD_HEIGHT;
@@ -73,13 +33,13 @@ namespace GameConstants
 	const ui16 BACKPACK_START = 19;
 	const int CREATURES_PER_TOWN = 7; //without upgrades
 	const int SPELL_LEVELS = 5;
+	const int CRE_LEVELS = 10; // number of creature experience levels
 
 	const int SPELLBOOK_GOLD_COST = 500;
 	const int BATTLE_PENALTY_DISTANCE = 10; //if the distance is > than this, then shooting stack has distance penalty
 	const int ARMY_SIZE = 7;
 	const int SKILL_PER_HERO=8;
 
-	const int CRE_LEVELS = 10;
 	const int SKILL_QUANTITY=28;
 	const int PRIMARY_SKILLS=4;
 	const int TERRAIN_TYPES=10;

+ 2 - 2
lib/NetPacksLib.cpp

@@ -829,9 +829,9 @@ DLL_LINKAGE void AssembledArtifact::applyGs( CGameState *gs )
 	CCombinedArtifactInstance *combinedArt = new CCombinedArtifactInstance(builtArt);
 	gs->map->addNewArtifactInstance(combinedArt);
 	//retrieve all constituents
-	BOOST_FOREACH(si32 constituentID, *builtArt->constituents)
+	BOOST_FOREACH(const CArtifact * constituent, *builtArt->constituents)
 	{
-		ArtifactPosition pos = artSet->getArtPos(constituentID);
+		ArtifactPosition pos = artSet->getArtPos(constituent->id);
 		assert(pos >= 0);
 		CArtifactInstance *constituentInstance = artSet->getArt(pos);
 

+ 122 - 0
lib/VCMIDirs.cpp

@@ -0,0 +1,122 @@
+#include "StdInc.h"
+#include "VCMIDirs.h"
+
+/*
+ * VCMIDirs.cpp, 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
+ *
+ */
+
+static VCMIDirs VCMIDirsGlobal;
+
+VCMIDirs::VCMIDirs()
+{
+	// initialize local directory and create folders to which VCMI needs write access
+	boost::filesystem::create_directory(localPath());
+	boost::filesystem::create_directory(localPath() + "/config");
+	boost::filesystem::create_directory(localPath() + "/Games");
+}
+
+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::localPath() const
+{
+	return dataPath();
+}
+
+std::string VCMIDirs::libraryPath() const
+{
+	return dataPath();
+}
+
+std::string VCMIDirs::serverPath() const
+{
+	return dataPath() + "\\" + "VCMI_server.exe";
+}
+
+std::string VCMIDirs::dataPath() const
+{
+	return ".";
+}
+
+std::string VCMIDirs::libraryName(std::string basename) const
+{
+	return basename + ".dll";
+}
+
+#elif defined(__APPLE__)
+
+std::string VCMIDirs::localPath() 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") != NULL )
+		home_dir = getenv("HOME");
+
+	return path(home_dir + "/Library/Application Support/vcmi").string();
+}
+
+std::string VCMIDirs::libraryPath() const
+{
+	return ".";
+}
+
+std::string VCMIDirs::serverPath() const
+{
+	return "./vcmiserver";
+}
+
+std::string VCMIDirs::dataPath() const
+{
+	return "../Data";
+}
+
+std::string VCMIDirs::libraryName(std::string basename) const
+{
+	return "lib" + basename + ".dylib";
+}
+
+#else
+
+std::string VCMIDirs::localPath() const
+{
+	if (getenv("HOME") != NULL )
+		return std::string(getenv("HOME")) + "/.vcmi";
+	return ".";
+}
+
+std::string VCMIDirs::libraryPath() const
+{
+	return M_LIB_DIR;
+}
+
+std::string VCMIDirs::serverPath() const
+{
+	return std::string(M_BIN_DIR) + "/" + "vcmiserver";
+}
+
+std::string VCMIDirs::dataPath() const
+{
+	return M_DATA_DIR;
+}
+
+std::string VCMIDirs::libraryName(std::string basename) const
+{
+	return "lib" + basename + ".so";
+}
+
+#endif

+ 18 - 46
lib/VCMIDirs.h

@@ -12,55 +12,27 @@
  *
  */
 
-#ifndef _WIN32 //we need boost here only on non-win platforms
-	#include <boost/filesystem.hpp> 
-	using namespace boost::filesystem;
-#endif
-
 /// Where to find the various VCMI files. This is mostly useful for linux. 
-class VCMIDirs {
+class DLL_LINKAGE VCMIDirs
+{
 public:
-	std::string UserPath;
+	VCMIDirs();
 
-	VCMIDirs()
-	{
-#ifdef _WIN32
-		UserPath = GameConstants::DATA_DIR;
-#else
-		try {
-#ifdef ANDROID
-			UserPath = DATA_DIR;
-#elif defined(__APPLE__)
-            // 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") != NULL )
-				home_dir = getenv("HOME");
-            
-			UserPath = path(home_dir + "/Library/Application Support/vcmi").string();
-#else
-			// Find vcmi user directory and create it if necessary
-			std::string home_dir = ".";
-			if (getenv("HOME") != NULL )
-				home_dir = getenv("HOME");
+	/// get singleton instance
+	static VCMIDirs & get();
 
-			UserPath = path(home_dir + "/.vcmi").string();
-#endif
-			create_directory(UserPath);
-			create_directory(UserPath + "/config");
-			create_directory(UserPath + "/Games");
+	/// Path to local, user-specific directory (e.g. ~/.vcmi on *nix systems)
+	std::string localPath() const;
 
-			/* Home directory can contain some extra maps. */
-			create_directory(UserPath + "/Maps");
-		}
-		catch(const std::exception & e)
-		{
-		}
-#endif
-	}
-};
+	/// Path where vcmi libraries can be found (in AI and Scripting subdirectories)
+	std::string libraryPath() const;
+
+	/// Path to vcmiserver, including server name (e.g. /usr/bin/vcmiserver)
+	std::string serverPath() const;
 
-extern DLL_LINKAGE VCMIDirs GVCMIDirs;
+	/// Path to global system-wide data directory
+	std::string dataPath() const;
+
+	/// Returns system-specific name for dynamic libraries ("libStupidAI.so" or "StupidAI.dll")
+	std::string libraryName(std::string basename) const;
+};

+ 0 - 2
lib/VCMI_Lib.cpp

@@ -29,8 +29,6 @@
 
 LibClasses * VLC = NULL;
 
-DLL_LINKAGE VCMIDirs GVCMIDirs;
-
 DLL_LINKAGE void preinitDLL(CConsoleHandler *Console, std::ostream *Logfile)
 {
 	console = Console;

+ 1 - 1
server/CVCMIServer.cpp

@@ -505,7 +505,7 @@ int _tmain(int argc, _TCHAR* argv[])
 int main(int argc, char** argv)
 #endif
 {
-	logfile = new std::ofstream((GVCMIDirs.UserPath + "/VCMI_Server_log.txt").c_str());
+	logfile = new std::ofstream((VCMIDirs::get().localPath() + "/VCMI_Server_log.txt").c_str());
 	console = new CConsoleHandler;
 	//boost::thread t(boost::bind(&CConsoleHandler::run,::console));
 	if(argc > 1)