Browse Source

- files in local directories (saves & configs) now always have higher
priority than mods. Fixes #1685 and #1733
- fixed possible crash on exit in dispose() function
- (vcmibuilder) fixes problem with partial mp3 -> ogg conversion

Ivan Savenko 11 years ago
parent
commit
d2ae847ecf

+ 2 - 2
client/CGameInfo.cpp

@@ -14,7 +14,7 @@
  */
 
 const CGameInfo * CGI; //game info for general use
-CClientState * CCS;
+CClientState * CCS = nullptr;
 
 CGameInfo::CGameInfo()
 {
@@ -32,4 +32,4 @@ void CGameInfo::setFromLib()
 	objh = VLC->objh;
 	spellh = VLC->spellh;
 	dobjinfo = VLC->dobjinfo;
-}
+}

+ 5 - 2
client/CMT.cpp

@@ -751,8 +751,11 @@ void dispose()
 
 	// cleanup, mostly to remove false leaks from analyzer
 	CResourceHandler::clear();
-	CCS->musich->release();
-	CCS->soundh->release();
+	if (CCS)
+	{
+		CCS->musich->release();
+		CCS->soundh->release();
+	}
 	CMessage::dispose();
 }
 

+ 3 - 3
client/CMessage.cpp

@@ -63,7 +63,7 @@ struct ComponentsToBlit
 
 namespace
 {
-	CDefHandler * ok, *cancel;
+	CDefHandler * ok = nullptr, *cancel = nullptr;
 	std::vector<std::vector<SDL_Surface*> > piecesOfBox; //in colors of all players
 	SDL_Surface * background = nullptr;
 }
@@ -100,9 +100,9 @@ void CMessage::init()
 
 void CMessage::dispose()
 {
-	for (int i=0; i<PlayerColor::PLAYER_LIMIT_I; i++)
+	for (auto & piece : piecesOfBox)
 	{
-		for (auto & elem : piecesOfBox[i])
+		for (auto & elem : piece)
 		{
 			SDL_FreeSurface(elem);
 		}

+ 3 - 3
client/CPreGame.cpp

@@ -920,7 +920,7 @@ void CSelectionScreen::startScenario()
 		overWrite += boost::bind(&CCallback::save, LOCPLINT->cb.get(), saveGameName);
 		overWrite += boost::bind(&CGuiHandler::popIntTotally, &GH, this);
 
-		if(CResourceHandler::get()->existsResource(ResourceID(saveGameName, EResType::CLIENT_SAVEGAME)))
+		if(CResourceHandler::get("local")->existsResource(ResourceID(saveGameName, EResType::CLIENT_SAVEGAME)))
 		{
 			std::string hlp = CGI->generaltexth->allTexts[493]; //%s exists. Overwrite?
 			boost::algorithm::replace_first(hlp, "%s", sel->txt->text);
@@ -1354,7 +1354,7 @@ void SelectionTab::select( int position )
 
 	if(txt)
 	{
-		std::string filename = *CResourceHandler::get()->getResourceName(
+		std::string filename = *CResourceHandler::get("local")->getResourceName(
 								   ResourceID(curItems[py]->fileURI, EResType::CLIENT_SAVEGAME));
 		txt->setText(CFileInfo(filename).getBaseName());
 	}
@@ -1479,7 +1479,7 @@ void SelectionTab::printMaps(SDL_Surface *to)
 		}
 		else
 		{
-			name = CFileInfo(*CResourceHandler::get()->getResourceName(
+			name = CFileInfo(*CResourceHandler::get("local")->getResourceName(
 								 ResourceID(currentItem->fileURI, EResType::CLIENT_SAVEGAME))).getBaseName();
 		}
 

+ 4 - 4
client/Client.cpp

@@ -241,17 +241,17 @@ void CClient::loadGame( const std::string & fname )
 	CStopWatch tmh;
 	try
 	{
-		std::string clientSaveName = *CResourceHandler::get()->getResourceName(ResourceID(fname, EResType::CLIENT_SAVEGAME));
+		std::string clientSaveName = *CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::CLIENT_SAVEGAME));
 		std::string controlServerSaveName;
 
-		if (CResourceHandler::get()->existsResource(ResourceID(fname, EResType::SERVER_SAVEGAME)))
+		if (CResourceHandler::get("local")->existsResource(ResourceID(fname, EResType::SERVER_SAVEGAME)))
 		{
-			controlServerSaveName = *CResourceHandler::get()->getResourceName(ResourceID(fname, EResType::SERVER_SAVEGAME));
+			controlServerSaveName = *CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::SERVER_SAVEGAME));
 		}
 		else// create entry for server savegame. Triggered if save was made after launch and not yet present in res handler
 		{
 			controlServerSaveName = clientSaveName.substr(0, clientSaveName.find_last_of(".")) + ".vsgm1";
-			CResourceHandler::get()->createResource(controlServerSaveName, true);
+			CResourceHandler::get("local")->createResource(controlServerSaveName, true);
 		}
 
 		if(clientSaveName.empty())

+ 1 - 1
client/NetPacksClient.cpp

@@ -793,7 +793,7 @@ void YourTurn::applyCl( CClient *cl )
 void SaveGame::applyCl(CClient *cl)
 {
 	CFileInfo info(fname);
-	CResourceHandler::get()->createResource(info.getStem() + ".vcgm1");
+	CResourceHandler::get("local")->createResource(info.getStem() + ".vcgm1");
 
 	try
 	{

+ 6 - 6
lib/CConfigHandler.cpp

@@ -59,11 +59,11 @@ void SettingsStorage::init()
 {
 	std::string confName = "config/settings.json";
 
-	// Porbably new install. Create initial configuration
-	if (!CResourceHandler::get()->existsResource(ResourceID(confName)))
-		CResourceHandler::get()->createResource(confName);
-	else
-		JsonNode(ResourceID("config/settings.json")).swap(config);
+	JsonUtils::assembleFromFiles(confName).swap(config);
+
+	// Probably new install. Create config file to save settings to
+	if (!CResourceHandler::get("local")->existsResource(ResourceID(confName)))
+		CResourceHandler::get("local")->createResource(confName);
 
 	JsonUtils::maximize(config, "vcmi:settings");
 	JsonUtils::validate(config, "vcmi:settings", "settings");
@@ -294,4 +294,4 @@ void config::CConfigHandler::init()
 // Force instantiation of the SettingsStorage::NodeAccessor class template.
 // That way method definitions can sit in the cpp file
 template struct SettingsStorage::NodeAccessor<SettingsListener>;
-template struct SettingsStorage::NodeAccessor<Settings>;
+template struct SettingsStorage::NodeAccessor<Settings>;

+ 4 - 4
lib/CModHandler.cpp

@@ -547,12 +547,12 @@ std::vector <TModID> CModHandler::resolveDependencies(std::vector <TModID> input
 
 static JsonNode loadModSettings(std::string path)
 {
-	if (CResourceHandler::get()->existsResource(ResourceID(path)))
+	if (CResourceHandler::get("local")->existsResource(ResourceID(path)))
 	{
 		return JsonNode(ResourceID(path, EResType::TEXT));
 	}
 	// Probably new install. Create initial configuration
-	CResourceHandler::get()->createResource(path);
+	CResourceHandler::get("local")->createResource(path);
 	return JsonNode();
 }
 
@@ -687,7 +687,7 @@ static ui32 calculateModChecksum(const std::string modName, ISimpleResourceLoade
 	if (modName != "core")
 	{
 		ResourceID modConfFile("mods/" + modName + "/mod", EResType::TEXT);
-		ui32 configChecksum = CResourceHandler::getInitial()->load(modConfFile)->calculateCRC32();
+		ui32 configChecksum = CResourceHandler::get("initial")->load(modConfFile)->calculateCRC32();
 		modChecksum.process_bytes(reinterpret_cast<const void *>(&configChecksum), sizeof(configChecksum));
 	}
 	// third - add all detected text files from this mod into checksum
@@ -717,7 +717,7 @@ void CModHandler::loadModFilesystems()
 	for(std::string & modName : activeMods)
 	{
 		CModInfo & mod = allMods[modName];
-		CResourceHandler::addFilesystem(modName, genModFilesystem(modName, mod.config));
+		CResourceHandler::addFilesystem("data", modName, genModFilesystem(modName, mod.config));
 	}
 }
 

+ 55 - 37
lib/filesystem/Filesystem.cpp

@@ -14,8 +14,6 @@
 #include "../VCMIDirs.h"
 #include "../CStopWatch.h"
 
-CFilesystemList * CResourceHandler::resourceLoader = nullptr;
-CFilesystemList * CResourceHandler::initialLoader = nullptr;
 std::map<std::string, ISimpleResourceLoader*> CResourceHandler::knownLoaders = std::map<std::string, ISimpleResourceLoader*>();
 
 CFilesystemGenerator::CFilesystemGenerator(std::string prefix):
@@ -75,7 +73,7 @@ void CFilesystemGenerator::loadDirectory(const std::string &mountPoint, const Js
 
 	ResourceID resID(URI, EResType::DIRECTORY);
 
-	for(auto & loader : CResourceHandler::getInitial()->getResourcesWithName(resID))
+	for(auto & loader : CResourceHandler::get("initial")->getResourcesWithName(resID))
 	{
 		auto filename = loader->getResourceName(resID);
 		filesystem->addLoader(new CFilesystemLoader(mountPoint, *filename, depth), false);
@@ -85,7 +83,7 @@ void CFilesystemGenerator::loadDirectory(const std::string &mountPoint, const Js
 void CFilesystemGenerator::loadZipArchive(const std::string &mountPoint, const JsonNode & config)
 {
 	std::string URI = prefix + config["path"].String();
-	auto filename = CResourceHandler::getInitial()->getResourceName(ResourceID(URI, EResType::ARCHIVE_ZIP));
+	auto filename = CResourceHandler::get("initial")->getResourceName(ResourceID(URI, EResType::ARCHIVE_ZIP));
 	if (filename)
 		filesystem->addLoader(new CZipLoader(mountPoint, *filename), false);
 }
@@ -94,7 +92,7 @@ template<EResType::Type archiveType>
 void CFilesystemGenerator::loadArchive(const std::string &mountPoint, const JsonNode & config)
 {
 	std::string URI = prefix + config["path"].String();
-	auto filename = CResourceHandler::getInitial()->getResourceName(ResourceID(URI, archiveType));
+	auto filename = CResourceHandler::get("initial")->getResourceName(ResourceID(URI, archiveType));
 	if (filename)
 		filesystem->addLoader(new CArchiveLoader(mountPoint, *filename), false);
 }
@@ -102,10 +100,10 @@ void CFilesystemGenerator::loadArchive(const std::string &mountPoint, const Json
 void CFilesystemGenerator::loadJsonMap(const std::string &mountPoint, const JsonNode & config)
 {
 	std::string URI = prefix + config["path"].String();
-	auto filename = CResourceHandler::getInitial()->getResourceName(ResourceID(URI, EResType::TEXT));
+	auto filename = CResourceHandler::get("initial")->getResourceName(ResourceID(URI, EResType::TEXT));
 	if (filename)
 	{
-		auto configData = CResourceHandler::getInitial()->load(ResourceID(URI, EResType::TEXT))->readAll();
+		auto configData = CResourceHandler::get("initial")->load(ResourceID(URI, EResType::TEXT))->readAll();
 		const JsonNode config((char*)configData.first.get(), configData.second);
 		filesystem->addLoader(new CMappedFileLoader(mountPoint, config), false);
 	}
@@ -113,14 +111,17 @@ void CFilesystemGenerator::loadJsonMap(const std::string &mountPoint, const Json
 
 void CResourceHandler::clear()
 {
-	delete resourceLoader;
-	delete initialLoader;
+	delete knownLoaders["root"];
 }
 
-void CResourceHandler::initialize()
+ISimpleResourceLoader * CResourceHandler::createInitial()
 {
+	//temporary filesystem that will be used to initialize main one.
+	//used to solve several case-sensivity issues like Mp3 vs MP3
+	auto initialLoader = new CFilesystemList;
+
 	//recurse only into specific directories
-	auto recurseInDir = [](std::string URI, int depth)
+	auto recurseInDir = [&](std::string URI, int depth)
 	{
 		ResourceID ID(URI, EResType::DIRECTORY);
 
@@ -135,10 +136,6 @@ void CResourceHandler::initialize()
 		}
 	};
 
-	//temporary filesystem that will be used to initialize main one.
-	//used to solve several case-sensivity issues like Mp3 vs MP3
-	initialLoader = new CFilesystemList;
-
 	for (auto & path : VCMIDirs::get().dataPaths())
 	{
 		if (boost::filesystem::is_directory(path)) // some of system-provided paths may not exist
@@ -148,45 +145,66 @@ void CResourceHandler::initialize()
 
 	recurseInDir("CONFIG", 0);// look for configs
 	recurseInDir("DATA", 0); // look for archives
-	//TODO: improve mod loading process so depth 2 will no longer be needed
-	recurseInDir("MODS", 2); // look for mods. Depth 2 is required for now but won't cause speed issues if no mods present
+	recurseInDir("MODS", 64); // look for mods.
+
+	return initialLoader;
 }
 
-ISimpleResourceLoader * CResourceHandler::get()
+void CResourceHandler::initialize()
 {
-	return get("");
+	// Create tree-loke structure that looks like this:
+	// root
+	// |
+	// |- initial
+	// |
+	// |- data
+	// |  |-core
+	// |  |-mod1
+	// |  |-modN
+	// |
+	// |- local
+	//    |-saves
+	//    |-config
+
+	knownLoaders["root"] = new CFilesystemList();
+	knownLoaders["saves"] = new CFilesystemLoader("SAVES/", VCMIDirs::get().userSavePath());
+	knownLoaders["config"] = new CFilesystemLoader("CONFIG/", VCMIDirs::get().userConfigPath());
+
+	auto localFS = new CFilesystemList();
+	localFS->addLoader(knownLoaders["saves"], true);
+	localFS->addLoader(knownLoaders["config"], true);
+
+	addFilesystem("root", "initial", createInitial());
+	addFilesystem("root", "data", new CFilesystemList());
+	addFilesystem("root", "local", localFS);
 }
 
-ISimpleResourceLoader * CResourceHandler::get(std::string identifier)
+ISimpleResourceLoader * CResourceHandler::get()
 {
-	return knownLoaders.at(identifier);
+	return get("root");
 }
 
-ISimpleResourceLoader * CResourceHandler::getInitial()
+ISimpleResourceLoader * CResourceHandler::get(std::string identifier)
 {
-	assert(initialLoader);
-	return initialLoader;
+	return knownLoaders.at(identifier);
 }
 
 void CResourceHandler::load(const std::string &fsConfigURI)
 {
-	auto fsConfigData = initialLoader->load(ResourceID(fsConfigURI, EResType::TEXT))->readAll();
+	auto fsConfigData = get("initial")->load(ResourceID(fsConfigURI, EResType::TEXT))->readAll();
 
 	const JsonNode fsConfig((char*)fsConfigData.first.get(), fsConfigData.second);
 
-	resourceLoader = new CFilesystemList();
-	knownLoaders[""] = resourceLoader;
-	addFilesystem("core", createFileSystem("", fsConfig["filesystem"]));
-
-	// hardcoded system-specific path, may not be inside any of data directories
-	resourceLoader->addLoader(new CFilesystemLoader("SAVES/", VCMIDirs::get().userSavePath()), true);
-	resourceLoader->addLoader(new CFilesystemLoader("CONFIG/", VCMIDirs::get().userConfigPath()), true);
+	addFilesystem("data", "core", createFileSystem("", fsConfig["filesystem"]));
 }
 
-void CResourceHandler::addFilesystem(const std::string & identifier, ISimpleResourceLoader * loader)
+void CResourceHandler::addFilesystem(const std::string & parent, const std::string & identifier, ISimpleResourceLoader * loader)
 {
 	assert(knownLoaders.count(identifier) == 0);
-	resourceLoader->addLoader(loader, false);
+
+	auto list = dynamic_cast<CFilesystemList *>(knownLoaders.at(parent));
+	assert(list);
+	list->addLoader(loader, false);
 	knownLoaders[identifier] = loader;
 }
 
@@ -201,7 +219,7 @@ std::vector<std::string> CResourceHandler::getAvailableMods()
 {
 	static const std::string modDir = "MODS/";
 
-	auto list = initialLoader->getFilteredFiles([](const ResourceID & id) ->  bool
+	auto list = get("initial")->getFilteredFiles([](const ResourceID & id) ->  bool
 	{
 		return id.getType() == EResType::DIRECTORY
 			&& boost::range::count(id.getName(), '/') == 1
@@ -218,8 +236,8 @@ std::vector<std::string> CResourceHandler::getAvailableMods()
 
 		if (name == "WOG") // check if wog is actually present. Hack-ish but better than crash
 		{
-			if (!initialLoader->existsResource(ResourceID("DATA/ZVS", EResType::DIRECTORY)) &&
-				!initialLoader->existsResource(ResourceID("MODS/WOG/DATA/ZVS", EResType::DIRECTORY)))
+			if (!get("initial")->existsResource(ResourceID("DATA/ZVS", EResType::DIRECTORY)) &&
+				!get("initial")->existsResource(ResourceID("MODS/WOG/DATA/ZVS", EResType::DIRECTORY)))
 			{
 				continue;
 			}

+ 7 - 4
lib/filesystem/Filesystem.h

@@ -52,6 +52,12 @@ public:
  */
 class DLL_LINKAGE CResourceHandler
 {
+	/**
+	 * @brief createInitial - creates instance of initial loader
+	 * that contains data necessary to load main FS
+	 */
+	static ISimpleResourceLoader * createInitial();
+
 public:
 	/**
 	 * Gets an instance of resource loader.
@@ -62,7 +68,6 @@ public:
 	 */
 	static ISimpleResourceLoader * get();
 	static ISimpleResourceLoader * get(std::string identifier);
-	static ISimpleResourceLoader * getInitial();
 
 	/**
 	 * Creates instance of initial resource loader.
@@ -89,7 +94,7 @@ public:
 	 * @param identifier name of this loader by which it can be retrieved later
 	 * @param loader resource loader to add
 	 */
-	static void addFilesystem(const std::string & identifier, ISimpleResourceLoader * loader);
+	static void addFilesystem(const std::string & parent, const std::string & identifier, ISimpleResourceLoader * loader);
 
 	/**
 	 * @brief createModFileSystem - creates filesystem out of config file
@@ -107,6 +112,4 @@ public:
 private:
 	/** Instance of resource loader */
 	static std::map<std::string, ISimpleResourceLoader*> knownLoaders;
-	static CFilesystemList * resourceLoader;
-	static CFilesystemList * initialLoader;
 };

+ 4 - 4
server/CGameHandler.cpp

@@ -2226,8 +2226,8 @@ void CGameHandler::save(const std::string & filename )
 {
     logGlobal->errorStream() << "Saving to " << filename;
 	CFileInfo info(filename);
-	//CResourceHandler::get()->createResource(info.getStem() + ".vlgm1");
-	CResourceHandler::get()->createResource(info.getStem() + ".vsgm1");
+	//CResourceHandler::get("local")->createResource(info.getStem() + ".vlgm1");
+	CResourceHandler::get("local")->createResource(info.getStem() + ".vsgm1");
 
 	{
         logGlobal->infoStream() << "Ordering clients to serialize...";
@@ -2239,14 +2239,14 @@ void CGameHandler::save(const std::string & filename )
 	{
 // 		{
 // 			logGlobal->infoStream() << "Serializing game info...";
-// 			CSaveFile save(CResourceHandler::get()->getResourceName(ResourceID(info.getStem(), EResType::LIB_SAVEGAME)));
+// 			CSaveFile save(CResourceHandler::get("local")->getResourceName(ResourceID(info.getStem(), EResType::LIB_SAVEGAME)));
 // // 			char hlp[8] = "VCMISVG";
 // // 			save << hlp;
 // 			saveCommonState(save);
 // 		}
 
 		{
-			CSaveFile save(*CResourceHandler::get()->getResourceName(ResourceID(info.getStem(), EResType::SERVER_SAVEGAME)));
+			CSaveFile save(*CResourceHandler::get("local")->getResourceName(ResourceID(info.getStem(), EResType::SERVER_SAVEGAME)));
 			saveCommonState(save);
             logGlobal->infoStream() << "Saving server state";
 			save << *this;

+ 2 - 2
server/CVCMIServer.cpp

@@ -464,7 +464,7 @@ void CVCMIServer::loadGame()
 // 		CMapHeader dum;
 // 		StartInfo *si;
 // 
-// 		CLoadFile lf(CResourceHandler::get()->getResourceName(ResourceID(fname, EResType::LIB_SAVEGAME)));
+// 		CLoadFile lf(CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::LIB_SAVEGAME)));
 // 		lf >> sig >> dum >> si;
 // 		logNetwork->infoStream() <<"Reading save signature";
 // 
@@ -477,7 +477,7 @@ void CVCMIServer::loadGame()
 // 	}
 
 	{
-		CLoadFile lf(*CResourceHandler::get()->getResourceName(ResourceID(fname, EResType::SERVER_SAVEGAME)), minSupportedVersion);
+		CLoadFile lf(*CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::SERVER_SAVEGAME)), minSupportedVersion);
 		gh.loadCommonState(lf);
 		lf >> gh;
 	}

+ 1 - 1
vcmibuilder

@@ -273,7 +273,7 @@ then
 	OIFS="$IFS"
 	IFS=$'\n' 
 
-	for file in `find "$dest_dir" -type f -name "*.mp3"`
+	for file in `find "$dest_dir" -type f -iname "*.mp3"`
 	do
 		echo "Converting $file"
 		ogg=${file%.*}