void SaveGame::applyCl(CClient *cl) { CFileInfo info(fname); CResourceHandler::get("local")->createResource(info.getStem() + ".vcgm1"); try { CSaveFile save(*CResourceHandler::get()->getResourceName(ResourceID(info.getStem(), EResType::CLIENT_SAVEGAME))); cl->saveCommonState(save); save << *cl; } catch(std::exception &e) { logNetwork->errorStream() << "Failed to save game:" << e.what(); } }
std::unordered_map<ResourceID, std::string> CFilesystemLoader::listFiles(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); assert(boost::filesystem::is_directory(baseDirectory)); std::unordered_map<ResourceID, std::string> fileList; std::vector<std::string> 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); for(; it != enddir; ++it) { EResType::Type type; if (boost::filesystem::is_directory(it->status())) { path.resize(it.level()+1); path.back() = it->path().leaf().string(); it.no_push(depth <= it.level()); // don't iterate into directory if depth limit reached type = EResType::DIRECTORY; } else type = EResTypeHelper::getTypeFromExtension(boost::filesystem::extension(*it)); 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(); fileList[ResourceID(filename, type)] = filename; } } return fileList; }
bool CResourceLoader::createResource(std::string URI) { std::string filename = URI; boost::to_upper(URI); BOOST_REVERSE_FOREACH (const LoaderEntry & entry, loaders) { if (entry.writeable && boost::algorithm::starts_with(URI, entry.prefix)) { // remove loader prefix from filename filename = filename.substr(entry.prefix.size()); if (!entry.loader->createEntry(filename)) return false; //or continue loop? resources[ResourceID(URI)].push_back(ResourceLocator(entry.loader.get(), filename)); } } return false; }
ui8 * getCachedFile(ResourceID && rid) { BOOST_FOREACH(auto & file, cache) { if (file.name == rid) return file.getCopy(); } // Still here? Cache miss if (cache.size() > cacheSize) cache.pop_front(); cache.push_back(FileData()); auto data = CResourceHandler::get()->loadData(rid); cache.back().name = ResourceID(rid); cache.back().size = data.second; cache.back().data = data.first.release(); return cache.back().getCopy(); }
CDefObjInfoHandler::CDefObjInfoHandler() { VLC->dobjinfo = this; auto textFile = CResourceHandler::get()->load(ResourceID("DATA/OBJECTS.TXT"))->readAll(); std::istringstream inp(std::string((char*)textFile.first.get(), textFile.second)); int objNumber; inp>>objNumber; std::string mapStr; for(int hh=0; hh<objNumber; ++hh) { auto nobj = new CGDefInfo(); std::string dump; inp>>nobj->name; std::transform(nobj->name.begin(), nobj->name.end(), nobj->name.begin(), (int(*)(int))toupper); for(int o=0; o<6; ++o) { nobj->blockMap[o] = 0xff; nobj->visitMap[o] = 0x00; nobj->coverageMap[o] = 0x00; nobj->shadowCoverage[o] = 0x00; } inp>>mapStr; std::reverse(mapStr.begin(), mapStr.end()); for(int v=0; v<mapStr.size(); ++v) { if(mapStr[v]=='0') { nobj->blockMap[v/8] &= 255 - (128 >> (v%8)); } } inp>>mapStr; std::reverse(mapStr.begin(), mapStr.end()); for(int v=0; v<mapStr.size(); ++v) { if(mapStr[v]=='1') { nobj->visitMap[v/8] |= (128 >> (v%8)); } }
bool CFilesystemList::createResource(std::string filename, bool update) { logGlobal->traceStream()<< "Creating " << filename; for (auto & loader : boost::adaptors::reverse(loaders)) { if (writeableLoaders.count(loader.get()) != 0 // writeable, && loader->createResource(filename, update)) // successfully created { // Check if resource was created successfully. Possible reasons for this to fail // a) loader failed to create resource (e.g. read-only FS) // b) in update mode, call with filename that does not exists assert(load(ResourceID(filename))); logGlobal->traceStream()<< "Resource created successfully"; return true; } } logGlobal->traceStream()<< "Failed to create resource"; return false; }
void MusicEntry::load(std::string musicURI) { if (music) { logGlobal->traceStream()<<"Del-ing music file "<<currentName; Mix_FreeMusic(music); music = nullptr; } currentName = musicURI; logGlobal->traceStream()<<"Loading music file "<<musicURI; data = CResourceHandler::get()->load(ResourceID(musicURI, EResType::MUSIC))->readAll(); musicFile = SDL_RWFromConstMem(data.first.get(), data.second); #ifdef VCMI_SDL1 music = Mix_LoadMUS_RW(musicFile); if(!music) { SDL_FreeRW(musicFile); musicFile = nullptr; logGlobal->warnStream() << "Warning: Cannot open " << currentName << ": " << Mix_GetError(); return; } #else music = Mix_LoadMUS_RW(musicFile, SDL_FALSE); if(!music) { SDL_FreeRW(musicFile); musicFile = nullptr; logGlobal->warnStream() << "Warning: Cannot open " << currentName << ": " << Mix_GetError(); return; } #endif // 0 }
Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound) { if (sound.empty()) return nullptr; // Load and insert try { auto data = CResourceHandler::get()->load(ResourceID(std::string("SOUNDS/") + sound, EResType::SOUND))->readAll(); SDL_RWops *ops = SDL_RWFromMem(data.first.release(), data.second); Mix_Chunk *chunk; chunk = Mix_LoadWAV_RW(ops, 1); // will free ops return chunk; } catch(std::exception &e) { logGlobal->warnStream() << "Cannot get sound " << sound << " chunk: " << e.what(); return nullptr; } }
void CModHandler::loadConfigFromFile (std::string name) { std::string paths; for(auto& p : CResourceHandler::get()->getResourceNames(ResourceID("config/" + name))) { paths += p.string() + ", "; } paths = paths.substr(0, paths.size() - 2); logGlobal->debugStream() << "Loading hardcoded features settings from [" << paths << "], result:"; settings.data = JsonUtils::assembleFromFiles("config/" + name); const JsonNode & hardcodedFeatures = settings.data["hardcodedFeatures"]; settings.MAX_HEROES_AVAILABLE_PER_PLAYER = hardcodedFeatures["MAX_HEROES_AVAILABLE_PER_PLAYER"].Float(); logGlobal->debugStream() << "\tMAX_HEROES_AVAILABLE_PER_PLAYER\t" << settings.MAX_HEROES_AVAILABLE_PER_PLAYER; settings.MAX_HEROES_ON_MAP_PER_PLAYER = hardcodedFeatures["MAX_HEROES_ON_MAP_PER_PLAYER"].Float(); logGlobal->debugStream() << "\tMAX_HEROES_ON_MAP_PER_PLAYER\t" << settings.MAX_HEROES_ON_MAP_PER_PLAYER; settings.CREEP_SIZE = hardcodedFeatures["CREEP_SIZE"].Float(); logGlobal->debugStream() << "\tCREEP_SIZE\t" << settings.CREEP_SIZE; settings.WEEKLY_GROWTH = hardcodedFeatures["WEEKLY_GROWTH_PERCENT"].Float(); logGlobal->debugStream() << "\tWEEKLY_GROWTH\t" << settings.WEEKLY_GROWTH; settings.NEUTRAL_STACK_EXP = hardcodedFeatures["NEUTRAL_STACK_EXP_DAILY"].Float(); logGlobal->debugStream() << "\tNEUTRAL_STACK_EXP\t" << settings.NEUTRAL_STACK_EXP; settings.MAX_BUILDING_PER_TURN = hardcodedFeatures["MAX_BUILDING_PER_TURN"].Float(); logGlobal->debugStream() << "\tMAX_BUILDING_PER_TURN\t" << settings.MAX_BUILDING_PER_TURN; settings.DWELLINGS_ACCUMULATE_CREATURES = hardcodedFeatures["DWELLINGS_ACCUMULATE_CREATURES"].Bool(); logGlobal->debugStream() << "\tDWELLINGS_ACCUMULATE_CREATURES\t" << settings.DWELLINGS_ACCUMULATE_CREATURES; settings.ALL_CREATURES_GET_DOUBLE_MONTHS = hardcodedFeatures["ALL_CREATURES_GET_DOUBLE_MONTHS"].Bool(); logGlobal->debugStream() << "\tALL_CREATURES_GET_DOUBLE_MONTHS\t" << settings.ALL_CREATURES_GET_DOUBLE_MONTHS; settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS = hardcodedFeatures["WINNING_HERO_WITH_NO_TROOPS_RETREATS"].Bool(); logGlobal->debugStream() << "\tWINNING_HERO_WITH_NO_TROOPS_RETREATS\t" << settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS; const JsonNode & gameModules = settings.data["modules"]; modules.STACK_EXP = gameModules["STACK_EXPERIENCE"].Bool(); logGlobal->debugStream() << "\tSTACK_EXP\t" << modules.STACK_EXP; modules.STACK_ARTIFACT = gameModules["STACK_ARTIFACTS"].Bool(); logGlobal->debugStream() << "\tSTACK_ARTIFACT\t" << modules.STACK_ARTIFACT; modules.COMMANDERS = gameModules["COMMANDERS"].Bool(); logGlobal->debugStream() << "\tCOMMANDERS\t" << modules.COMMANDERS; modules.MITHRIL = gameModules["MITHRIL"].Bool(); logGlobal->debugStream() << "\tMITHRIL\t" << modules.MITHRIL; }
void CHeroHandler::loadObstacles() { auto loadObstacles = [](const JsonNode &node, bool absolute, std::map<int, CObstacleInfo> &out) { for(const JsonNode &obs : node.Vector()) { int ID = obs["id"].Float(); CObstacleInfo & obi = out[ID]; obi.ID = ID; obi.defName = obs["defname"].String(); obi.width = obs["width"].Float(); obi.height = obs["height"].Float(); obi.allowedTerrains = obs["allowedTerrain"].convertTo<std::vector<ETerrainType> >(); obi.allowedSpecialBfields = obs["specialBattlefields"].convertTo<std::vector<BFieldType> >(); obi.blockedTiles = obs["blockedTiles"].convertTo<std::vector<si16> >(); obi.isAbsoluteObstacle = absolute; } }; const JsonNode config(ResourceID("config/obstacles.json")); loadObstacles(config["obstacles"], false, obstacles); loadObstacles(config["absoluteObstacles"], true, absoluteObstacles); //loadObstacles(config["moats"], true, moats); }
CMusicHandler::CMusicHandler(): listener(settings.listen["general"]["music"]) { listener(std::bind(&CMusicHandler::onVolumeChange, this, _1)); // Map music IDs // Vectors for helper const std::string setEnemy[] = {"AITheme0", "AITheme1", "AITheme2"}; const std::string setBattle[] = {"Combat01", "Combat02", "Combat03", "Combat04"}; auto fillSet = [=](std::string setName, const std::string list[], size_t amount) { for (size_t i=0; i < amount; i++) addEntryToSet(setName, i, "music/" + list[i]); }; fillSet("enemy-turn", setEnemy, ARRAY_COUNT(setEnemy)); fillSet("battle", setBattle, ARRAY_COUNT(setBattle)); JsonNode terrains(ResourceID("config/terrains.json")); for (auto entry : terrains.Struct()) { int terrIndex = vstd::find_pos(GameConstants::TERRAIN_NAMES, entry.first); addEntryToSet("terrain", terrIndex, "Music/" + entry.second["music"].String()); } }
// Allocate an SDL chunk and cache it. Mix_Chunk *CSoundHandler::GetSoundChunk(soundBase::soundID soundID) { // Find its name auto fname = sounds[soundID]; if (fname.empty()) return nullptr; // Load and insert try { auto data = CResourceHandler::get()->load(ResourceID(std::string("SOUNDS/") + fname, EResType::SOUND))->readAll(); SDL_RWops *ops = SDL_RWFromMem(data.first.release(), data.second); Mix_Chunk *chunk; chunk = Mix_LoadWAV_RW(ops, 1); // will free ops soundChunks.insert(std::pair<soundBase::soundID, Mix_Chunk *>(soundID, chunk)); return chunk; } catch(std::exception &e) { logGlobal->warnStream() << "Cannot get sound " << soundID << " chunk: " << e.what(); return nullptr; } }
int main(int argc, char** argv) #endif { #ifdef __APPLE__ // Correct working dir executable folder (not bundle folder) so we can use executable relative pathes std::string executablePath = argv[0]; std::string workDir = executablePath.substr(0, executablePath.rfind('/')); chdir(workDir.c_str()); // Check for updates OSX_checkForUpdates(); // Check that game data is prepared. Otherwise run vcmibuilder helper application FILE* check = fopen((VCMIDirs::get().localPath() + "/game_data_prepared").c_str(), "r"); if (check == nullptr) { system("open ./vcmibuilder.app"); return 0; } fclose(check); #endif std::cout << "Starting... " << std::endl; po::options_description opts("Allowed options"); opts.add_options() ("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") ("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") ("oneGoodAI", "puts one default AI and the rest will be EmptyAI") ("autoSkip", "automatically skip turns in GUI") ("disable-video", "disable video player") ("nointro,i", "skips intro movies"); if(argc > 1) { try { po::store(po::parse_command_line(argc, argv, opts), vm); } catch(std::exception &e) { std::cerr << "Failure during parsing command-line options:\n" << e.what() << std::endl; } } po::notify(vm); if(vm.count("help")) { prog_help(opts); return 0; } if(vm.count("version")) { prog_version(); return 0; } if(vm.count("noGUI")) { gNoGUI = true; vm.insert(std::pair<std::string, po::variable_value>("onlyAI", po::variable_value())); } //Set environment vars to make window centered. Sometimes work, sometimes not. :/ putenv((char*)"SDL_VIDEO_WINDOW_POS"); putenv((char*)"SDL_VIDEO_CENTERED=1"); // Have effect on X11 system only (Linux). // For whatever reason in fullscreen mode SDL takes "raw" mouse input from DGA X11 extension // (DGA = Direct graphics access). Because this is raw input (before any speed\acceleration proceesing) // it may result in very small \ very fast mouse when game in fullscreen mode putenv((char*)"SDL_VIDEO_X11_DGAMOUSE=0"); // Init old logging system and new (temporary) logging system CStopWatch total, pomtime; std::cout.flags(std::ios::unitbuf); console = new CConsoleHandler; *console->cb = boost::bind(&processCommand, _1); console->start(); atexit(dispose); CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Client_log.txt", console); logConfig.configureDefault(); logGlobal->infoStream() <<"Creating console "<<pomtime.getDiff(); // Init filesystem and settings preinitDLL(::console); settings.init(); // Initialize logging based on settings logConfig.configure(); // Some basic data validation to produce better error messages in cases of incorrect install auto testFile = [](std::string filename, std::string message) -> bool { if (CResourceHandler::get()->existsResource(ResourceID(filename))) return true; logGlobal->errorStream() << "Error: " << message << " was not found!"; return false; }; if (!testFile("DATA/HELP.TXT", "Heroes III data") && !testFile("MODS/VCMI/MOD.JSON", "VCMI mod") && !testFile("DATA/StackQueueBgBig.PCX", "VCMI data")) exit(1); // These are unrecoverable errors // these two are optional + some installs have them on CD and not in data directory testFile("VIDEO/GOOD1A.SMK", "campaign movies"); testFile("SOUNDS/G1A.WAV", "campaign music"); //technically not a music but voiced intro sounds conf.init(); logGlobal->infoStream() <<"Loading settings: "<<pomtime.getDiff(); logGlobal->infoStream() << NAME; srand ( time(nullptr) ); const JsonNode& video = settings["video"]; const JsonNode& res = video["screenRes"]; //something is really wrong... if (res["width"].Float() < 100 || res["height"].Float() < 100) { logGlobal->errorStream() << "Fatal error: failed to load settings!"; logGlobal->errorStream() << "Possible reasons:"; logGlobal->errorStream() << "\tCorrupted local configuration file at " << VCMIDirs::get().userConfigPath() << "/settings.json"; logGlobal->errorStream() << "\tMissing or corrupted global configuration file at " << VCMIDirs::get().userConfigPath() << "/schemas/settings.json"; logGlobal->errorStream() << "VCMI will now exit..."; exit(EXIT_FAILURE); } if(!gNoGUI) { if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_AUDIO)) { logGlobal->errorStream()<<"Something was wrong: "<< SDL_GetError(); exit(-1); } atexit(SDL_Quit); setScreenRes(res["width"].Float(), res["height"].Float(), video["bitsPerPixel"].Float(), video["fullscreen"].Bool()); logGlobal->infoStream() <<"\tInitializing screen: "<<pomtime.getDiff(); } CCS = new CClientState; CGI = new CGameInfo; //contains all global informations about game (texts, lodHandlers, map handler etc.) // Initialize video #if DISABLE_VIDEO CCS->videoh = new CEmptyVideoPlayer; #else if (!gNoGUI && !vm.count("disable-video")) CCS->videoh = new CVideoPlayer; else CCS->videoh = new CEmptyVideoPlayer; #endif logGlobal->infoStream()<<"\tInitializing video: "<<pomtime.getDiff(); //we can properly play intro only in the main thread, so we have to move loading to the separate thread boost::thread loading(init); if(!gNoGUI ) { if(!vm.count("battle") && !vm.count("nointro")) playIntro(); SDL_FillRect(screen,nullptr,0); } CSDL_Ext::update(screen); loading.join(); logGlobal->infoStream()<<"Initialization of VCMI (together): "<<total.getDiff(); if(!vm.count("battle")) { Settings session = settings.write["session"]; session["autoSkip"].Bool() = vm.count("autoSkip"); session["oneGoodAI"].Bool() = vm.count("oneGoodAI"); std::string fileToStartFrom; //none by default if(vm.count("start")) fileToStartFrom = vm["start"].as<std::string>(); if(fileToStartFrom.size() && boost::filesystem::exists(fileToStartFrom)) startGameFromFile(fileToStartFrom); //ommit pregame and start the game using settings from fiel else { if(fileToStartFrom.size()) { logGlobal->warnStream() << "Warning: cannot find given file to start from (" << fileToStartFrom << "). Falling back to main menu."; } GH.curInt = CGPreGame::create(); //will set CGP pointer to itself } } else { auto si = new StartInfo(); si->mode = StartInfo::DUEL; si->mapname = vm["battle"].as<std::string>(); si->playerInfos[PlayerColor(0)].color = PlayerColor(0); si->playerInfos[PlayerColor(1)].color = PlayerColor(1); startGame(si); } if(!gNoGUI) { mainGUIThread = new boost::thread(&CGuiHandler::run, &GH); listenForEvents(); } else { while(true) boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); } return 0; }
std::pair<std::unique_ptr<ui8[]>, ui64> CTrueTypeFont::loadData(const JsonNode & config) { std::string filename = "Data/" + config["file"].String(); return CResourceHandler::get()->load(ResourceID(filename, EResType::TTF_FONT))->readAll(); }
CBitmapFont::CBitmapFont(const std::string & filename): data(CResourceHandler::get()->load(ResourceID("data/" + filename, EResType::BMP_FONT))->readAll()), chars(loadChars()), height(data.first.get()[5]) {}
SDL_Surface * BitmapHandler::loadBitmapFromDir(std::string path, std::string fname, bool setKey) { if(!fname.size()) { logGlobal->warnStream() << "Call to loadBitmap with void fname!"; return nullptr; } if (!CResourceHandler::get()->existsResource(ResourceID(path + fname, EResType::IMAGE))) { return nullptr; } SDL_Surface * ret=nullptr; auto readFile = CResourceHandler::get()->load(ResourceID(path + fname, EResType::IMAGE))->readAll(); if (isPCX(readFile.first.get())) { //H3-style PCX ret = loadH3PCX(readFile.first.get(), readFile.second); if (ret) { if(ret->format->BytesPerPixel == 1 && setKey) { const SDL_Color &c = ret->format->palette->colors[0]; SDL_SetColorKey(ret,SDL_SRCCOLORKEY,SDL_MapRGB(ret->format, c.r, c.g, c.b)); } } else logGlobal->errorStream()<<"Failed to open "<<fname<<" as H3 PCX!"; } else { //loading via SDL_Image ret = IMG_Load_RW( //create SDL_RW with our data (will be deleted by SDL) SDL_RWFromConstMem((void*)readFile.first.get(), readFile.second), 1); // mark it for auto-deleting if (ret) { if (ret->format->palette) { //set correct value for alpha\unused channel for (int i=0; i< ret->format->palette->ncolors; i++) ret->format->palette->colors[i].unused = 255; } } else { logGlobal->errorStream()<<"Failed to open "<<fname<<" via SDL_Image"; logGlobal->errorStream()<<"Reason: " << IMG_GetError(); } } // When modifyin anything here please check two use cases: // 1) Vampire mansion in Necropolis (not 1st color is transparent) // 2) Battle background when fighting on grass/dirt, topmost sky part (NO transparent color) // 3) New objects that may use 24-bit images for icons (e.g. witchking arts) auto colorID = SDL_MapRGB(ret->format, 0, 255, 255); if (ret->format->palette) { auto & color = ret->format->palette->colors[colorID]; // set color key only if exactly such color was found if (color.r == 0 && color.g == 255 && color.b == 255) SDL_SetColorKey(ret, SDL_SRCCOLORKEY, colorID); } else // always set { SDL_SetColorKey(ret, SDL_SRCCOLORKEY, colorID); } return ret; }
void CClient::loadGame( const std::string & fname ) { logNetwork->infoStream() <<"Loading procedure started!"; CServerHandler sh; sh.startServer(); CStopWatch tmh; try { std::string clientSaveName = CResourceHandler::get()->getResourceName(ResourceID(fname, EResType::CLIENT_SAVEGAME)); std::string controlServerSaveName; if (CResourceHandler::get()->existsResource(ResourceID(fname, EResType::SERVER_SAVEGAME))) { controlServerSaveName = CResourceHandler::get()->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); } if(clientSaveName.empty()) throw std::runtime_error("Cannot open client part of " + fname); if(controlServerSaveName.empty()) throw std::runtime_error("Cannot open server part of " + fname); unique_ptr<CLoadFile> loader; { CLoadIntegrityValidator checkingLoader(clientSaveName, controlServerSaveName); loadCommonState(checkingLoader); loader = checkingLoader.decay(); } logNetwork->infoStream() << "Loaded common part of save " << tmh.getDiff(); const_cast<CGameInfo*>(CGI)->mh = new CMapHandler(); const_cast<CGameInfo*>(CGI)->mh->map = gs->map; pathInfo = make_unique<CPathsInfo>(getMapSize()); CGI->mh->init(); logNetwork->infoStream() <<"Initing maphandler: "<<tmh.getDiff(); *loader >> *this; logNetwork->infoStream() << "Loaded client part of save " << tmh.getDiff(); } catch(std::exception &e) { logGlobal->errorStream() << "Cannot load game " << fname << ". Error: " << e.what(); throw; //obviously we cannot continue here } serv = sh.connectToServer(); serv->addStdVecItems(gs); tmh.update(); ui8 pom8; *serv << ui8(3) << ui8(1); //load game; one client *serv << fname; *serv >> pom8; if(pom8) throw std::runtime_error("Server cannot open the savegame!"); else logNetwork->infoStream() << "Server opened savegame properly."; *serv << ui32(gs->scenarioOps->playerInfos.size()+1); //number of players + neutral for(auto it = gs->scenarioOps->playerInfos.begin(); it != gs->scenarioOps->playerInfos.end(); ++it) { *serv << ui8(it->first.getNum()); //players } *serv << ui8(PlayerColor::NEUTRAL.getNum()); logNetwork->infoStream() <<"Sent info to server: "<<tmh.getDiff(); serv->enableStackSendingByID(); serv->disableSmartPointerSerialization(); }
std::unique_ptr<CInputStream> CMappedFileLoader::load(const std::string & resourceName) const { return CResourceHandler::get()->load(ResourceID(resourceName)); }
std::string CMappedFileLoader::getFullName(const std::string & resourceName) const { return CResourceHandler::get()->getResourceName(ResourceID(resourceName)); }
void CBonusTypeHandler::load() { const JsonNode gameConf(ResourceID("config/gameConfig.json")); const JsonNode config(JsonUtils::assembleFromFiles(gameConf["bonuses"].convertTo<std::vector<std::string> >())); load(config); }
void CModHandler::initialize(std::vector<std::string> availableMods) { std::string confName = "config/modSettings.json"; JsonNode modConfig; // Porbably new install. Create initial configuration if (!CResourceHandler::get()->existsResource(ResourceID(confName))) CResourceHandler::get()->createResource(confName); else modConfig = JsonNode(ResourceID(confName)); const JsonNode & modList = modConfig["activeMods"]; JsonNode resultingList; std::vector <TModID> detectedMods; for(std::string name : availableMods) { boost::to_lower(name); std::string modFileName = "mods/" + name + "/mod.json"; if (CResourceHandler::get()->existsResource(ResourceID(modFileName))) { const JsonNode config = JsonNode(ResourceID(modFileName)); if (config.isNull()) continue; if (!modList[name].isNull() && modList[name].Bool() == false ) { resultingList[name].Bool() = false; continue; // disabled mod } resultingList[name].Bool() = true; CModInfo & mod = allMods[name]; mod.identifier = name; mod.name = config["name"].String(); mod.description = config["description"].String(); mod.dependencies = config["depends"].convertTo<std::set<std::string> >(); mod.conflicts = config["conflicts"].convertTo<std::set<std::string> >(); detectedMods.push_back(name); } else logGlobal->warnStream() << "\t\t Directory " << name << " does not contains VCMI mod"; } if (!checkDependencies(detectedMods)) { logGlobal->errorStream() << "Critical error: failed to load mods! Exiting..."; exit(1); } activeMods = resolveDependencies(detectedMods); modConfig["activeMods"] = resultingList; CResourceHandler::get()->createResource("CONFIG/modSettings.json"); std::ofstream file(CResourceHandler::get()->getResourceName(ResourceID("config/modSettings.json")), std::ofstream::trunc); file << modConfig; }
std::unique_ptr<CInputStream> CMapService::getStreamFromFS(const std::string & name) { return CResourceHandler::get()->load(ResourceID(name, EResType::MAP)); }
void CClient::loadGame(const std::string & fname, const bool server, const std::vector<int>& humanplayerindices, const int loadNumPlayers, int player_, const std::string & ipaddr, const std::string & port) { PlayerColor player(player_); //intentional shadowing logNetwork->infoStream() <<"Loading procedure started!"; CServerHandler sh; if(server) sh.startServer(); else serv = sh.justConnectToServer(ipaddr,port=="" ? "3030" : port); CStopWatch tmh; unique_ptr<CLoadFile> loader; try { std::string clientSaveName = *CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::CLIENT_SAVEGAME)); std::string controlServerSaveName; if (CResourceHandler::get("local")->existsResource(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("local")->createResource(controlServerSaveName, true); } if(clientSaveName.empty()) throw std::runtime_error("Cannot open client part of " + fname); if(controlServerSaveName.empty()) throw std::runtime_error("Cannot open server part of " + fname); { CLoadIntegrityValidator checkingLoader(clientSaveName, controlServerSaveName, minSupportedVersion); loadCommonState(checkingLoader); loader = checkingLoader.decay(); } logNetwork->infoStream() << "Loaded common part of save " << tmh.getDiff(); const_cast<CGameInfo*>(CGI)->mh = new CMapHandler(); const_cast<CGameInfo*>(CGI)->mh->map = gs->map; pathInfo = make_unique<CPathsInfo>(getMapSize()); CGI->mh->init(); logNetwork->infoStream() <<"Initing maphandler: "<<tmh.getDiff(); } catch(std::exception &e) { logGlobal->errorStream() << "Cannot load game " << fname << ". Error: " << e.what(); throw; //obviously we cannot continue here } /* if(!server) player = PlayerColor(player_); */ std::set<PlayerColor> clientPlayers; if(server) serv = sh.connectToServer(); //*loader >> *this; if(server) { tmh.update(); ui8 pom8; *serv << ui8(3) << ui8(loadNumPlayers); //load game; one client if single-player *serv << fname; *serv >> pom8; if(pom8) throw std::runtime_error("Server cannot open the savegame!"); else logNetwork->infoStream() << "Server opened savegame properly."; } if(server) { for(auto & elem : gs->scenarioOps->playerInfos) if(!std::count(humanplayerindices.begin(),humanplayerindices.end(),elem.first.getNum()) || elem.first==player) { clientPlayers.insert(elem.first); } clientPlayers.insert(PlayerColor::NEUTRAL); } else { clientPlayers.insert(player); } std::cout << "CLIENTPLAYERS:\n"; for(auto x : clientPlayers) std::cout << x << std::endl; std::cout << "ENDCLIENTPLAYERS\n"; serialize(loader->serializer,0,clientPlayers); *serv << ui32(clientPlayers.size()); for(auto & elem : clientPlayers) *serv << ui8(elem.getNum()); serv->addStdVecItems(gs); /*why is this here?*/ //*loader >> *this; logNetwork->infoStream() << "Loaded client part of save " << tmh.getDiff(); logNetwork->infoStream() <<"Sent info to server: "<<tmh.getDiff(); //*serv << clientPlayers; serv->enableStackSendingByID(); serv->disableSmartPointerSerialization(); // logGlobal->traceStream() << "Objects:"; // for(int i = 0; i < gs->map->objects.size(); i++) // { // auto o = gs->map->objects[i]; // if(o) // logGlobal->traceStream() << boost::format("\tindex=%5d, id=%5d; address=%5d, pos=%s, name=%s") % i % o->id % (int)o.get() % o->pos % o->getHoverText(); // else // logGlobal->traceStream() << boost::format("\tindex=%5d --- nullptr") % i; // } }
void CJsonRmgTemplateLoader::loadTemplates() { const JsonNode rootNode(ResourceID("config/rmg.json")); for(const auto & templatePair : rootNode.Struct()) { auto tpl = new CRmgTemplate(); try { tpl->setName(templatePair.first); const auto & templateNode = templatePair.second; // Parse main template data tpl->setMinSize(parseMapTemplateSize(templateNode["minSize"].String())); tpl->setMaxSize(parseMapTemplateSize(templateNode["maxSize"].String())); tpl->setPlayers(parsePlayers(templateNode["players"].String())); tpl->setCpuPlayers(parsePlayers(templateNode["cpu"].String())); // Parse zones std::map<TRmgTemplateZoneId, CRmgTemplateZone *> zones; for (const auto & zonePair : templateNode["zones"].Struct()) { auto zone = new CRmgTemplateZone(); auto zoneId = boost::lexical_cast<TRmgTemplateZoneId>(zonePair.first); zone->setId(zoneId); const auto & zoneNode = zonePair.second; zone->setType(parseZoneType(zoneNode["type"].String())); zone->setSize(zoneNode["size"].Float()); if (!zoneNode["owner"].isNull()) zone->setOwner(zoneNode["owner"].Float()); zone->setPlayerTowns(parseTemplateZoneTowns(zoneNode["playerTowns"])); zone->setNeutralTowns(parseTemplateZoneTowns(zoneNode["neutralTowns"])); if (!zoneNode["matchTerrainToTown"].isNull()) //default : true zone->setMatchTerrainToTown(zoneNode["matchTerrainToTown"].Bool()); zone->setTerrainTypes(parseTerrainTypes(zoneNode["terrainTypes"].Vector(), zone->getDefaultTerrainTypes())); if (!zoneNode["townsAreSameType"].isNull()) //default : false zone->setTownsAreSameType((zoneNode["townsAreSameType"].Bool())); for (int i = 0; i < 2; ++i) { std::set<TFaction> allowedTownTypes; if (i) { if (zoneNode["allowedTowns"].isNull()) allowedTownTypes = zone->getDefaultTownTypes(); } else { if (zoneNode["allowedMonsters"].isNull()) allowedTownTypes = VLC->townh->getAllowedFactions(false); } if (allowedTownTypes.empty()) { for (const JsonNode & allowedTown : zoneNode[i ? "allowedTowns" : "allowedMonsters"].Vector()) { //complain if the town type is not present in our game if (auto id = VLC->modh->identifiers.getIdentifier("faction", allowedTown, false)) allowedTownTypes.insert(id.get()); } } if (!zoneNode[i ? "bannedTowns" : "bannedMonsters"].isNull()) { for (const JsonNode & bannedTown : zoneNode[i ? "bannedTowns" : "bannedMonsters"].Vector()) { //erase unindentified towns silently if (auto id = VLC->modh->identifiers.getIdentifier("faction", bannedTown, true)) vstd::erase_if_present(allowedTownTypes, id.get()); } } if (i) zone->setTownTypes(allowedTownTypes); else zone->setMonsterTypes(allowedTownTypes); } const std::string monsterStrength = zoneNode["monsters"].String(); if (monsterStrength == "weak") zone->setMonsterStrength(EMonsterStrength::ZONE_WEAK); else if (monsterStrength == "normal") zone->setMonsterStrength(EMonsterStrength::ZONE_NORMAL); else if (monsterStrength == "strong") zone->setMonsterStrength(EMonsterStrength::ZONE_STRONG); else throw (rmgException("incorrect monster power")); if (!zoneNode["mines"].isNull()) { auto mines = zoneNode["mines"].Struct(); //FIXME: maybe there is a smarter way to parse it already? zone->setMinesAmount(Res::WOOD, mines["wood"].Float()); zone->setMinesAmount(Res::ORE, mines["ore"].Float()); zone->setMinesAmount(Res::GEMS, mines["gems"].Float()); zone->setMinesAmount(Res::CRYSTAL, mines["crystal"].Float()); zone->setMinesAmount(Res::SULFUR, mines["sulfur"].Float()); zone->setMinesAmount(Res::MERCURY, mines["mercury"].Float()); zone->setMinesAmount(Res::GOLD, mines["gold"].Float()); //TODO: Mithril } //treasures if (!zoneNode["treasure"].isNull()) { //TODO: parse vector of different treasure settings if (zoneNode["treasure"].getType() == JsonNode::DATA_STRUCT) { auto treasureInfo = zoneNode["treasure"].Struct(); { CTreasureInfo ti; ti.min = treasureInfo["min"].Float(); ti.max = treasureInfo["max"].Float(); ti.density = treasureInfo["density"].Float(); //TODO: use me zone->addTreasureInfo(ti); } } else if (zoneNode["treasure"].getType() == JsonNode::DATA_VECTOR) { for (auto treasureInfo : zoneNode["treasure"].Vector()) { CTreasureInfo ti; ti.min = treasureInfo["min"].Float(); ti.max = treasureInfo["max"].Float(); ti.density = treasureInfo["density"].Float(); zone->addTreasureInfo(ti); } } } zones[zone->getId()] = zone; } //copy settings from already parsed zones for (const auto & zonePair : templateNode["zones"].Struct()) { auto zoneId = boost::lexical_cast<TRmgTemplateZoneId>(zonePair.first); auto zone = zones[zoneId]; const auto & zoneNode = zonePair.second; if (!zoneNode["terrainTypeLikeZone"].isNull()) { int id = zoneNode["terrainTypeLikeZone"].Float(); zone->setTerrainTypes(zones[id]->getTerrainTypes()); zone->setMatchTerrainToTown(zones[id]->getMatchTerrainToTown()); } if (!zoneNode["townTypeLikeZone"].isNull()) zone->setTownTypes (zones[zoneNode["townTypeLikeZone"].Float()]->getTownTypes()); if (!zoneNode["treasureLikeZone"].isNull()) { for (auto treasureInfo : zones[zoneNode["treasureLikeZone"].Float()]->getTreasureInfo()) { zone->addTreasureInfo(treasureInfo); } } if (!zoneNode["minesLikeZone"].isNull()) { for (auto mineInfo : zones[zoneNode["minesLikeZone"].Float()]->getMinesInfo()) { zone->setMinesAmount (mineInfo.first, mineInfo.second); } } } tpl->setZones(zones); // Parse connections std::list<CRmgTemplateZoneConnection> connections; for(const auto & connPair : templateNode["connections"].Vector()) { CRmgTemplateZoneConnection conn; conn.setZoneA(zones.find(boost::lexical_cast<TRmgTemplateZoneId>(connPair["a"].String()))->second); conn.setZoneB(zones.find(boost::lexical_cast<TRmgTemplateZoneId>(connPair["b"].String()))->second); conn.setGuardStrength(connPair["guard"].Float()); connections.push_back(conn); } tpl->setConnections(connections); { auto zones = tpl->getZones(); for (auto con : tpl->getConnections()) { auto idA = con.getZoneA()->getId(); auto idB = con.getZoneB()->getId(); zones[idA]->addConnection(idB); zones[idB]->addConnection(idA); } } tpl->validate(); templates[tpl->getName()] = tpl; } catch(const std::exception & e) { logGlobal->errorStream() << boost::format("Template %s has errors. Message: %s.") % tpl->getName() % std::string(e.what()); } } }