JsonNode JsonReader::ParseArray() { JsonNode object = JsonNode(JsonNode::Type::Array); bool end = false; /* Verify we're parsing an array */ if (*m_data == '[') m_data++; while (!end) { /* Use the index value as the key name */ object[object.ChildCount()] = this->ParseValue(); while (*m_data != ',' && *m_data != ']' && !EndOfFile()) m_data++; switch (*m_data) { case ',': m_data++; break; case ']': end = true; m_data++; break; default: PrintError("Syntax Error : ',' , ']' were expected. "); end = true; break; }; } return object; }
void CAnimation::initFromJson(const JsonNode & config) { std::string basepath; basepath = config["basepath"].String(); for(const JsonNode &group : config["sequences"].Vector()) { size_t groupID = group["group"].Float();//TODO: string-to-value conversion("moving" -> MOVING) source[groupID].clear(); for(const JsonNode &frame : group["frames"].Vector()) { source[groupID].push_back(JsonNode()); std::string filename = frame.String(); source[groupID].back()["file"].String() = basepath + filename; } } for(const JsonNode &node : config["images"].Vector()) { size_t group = node["group"].Float(); size_t frame = node["frame"].Float(); if (source[group].size() <= frame) source[group].resize(frame+1); source[group][frame] = node; std::string filename = node["file"].String(); source[group][frame]["file"].String() = basepath + filename; } }
void CArtHandler::afterLoadFinalization() { //All artifacts have their id, so we can properly update their bonuses' source ids. for(auto &art : artifacts) { for(auto &bonus : art->getExportedBonusList()) { assert(art == artifacts[art->id]); assert(bonus->source == Bonus::ARTIFACT); bonus->sid = art->id; } } for (CArtifact * art : artifacts) { VLC->objtypeh->loadSubObject(art->Name(), JsonNode(), Obj::ARTIFACT, art->id.num); if (!art->advMapDef.empty()) { JsonNode templ; templ["animation"].String() = art->advMapDef; // add new template. // Necessary for objects added via mods that don't have any templates in H3 VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, art->id)->addTemplate(templ); } // object does not have any templates - this is not usable object (e.g. pseudo-art like lock) if (VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, art->id)->getTemplates().empty()) VLC->objtypeh->removeSubObject(Obj::ARTIFACT, art->id); } }
JsonNode JsonReader::ParseObject() { JsonNode object = JsonNode(JsonNode::Type::Object); bool end = false; if (*m_data == '{') m_data++; /* Look for the next key name */ while (!end) { std::string key; /* Look for string quotes */ while (*m_data != '\"' && *m_data != '\'' && !EndOfFile()) m_data++; if (EndOfFile()) { PrintError("Syntax Error : '\"' , ''' were expected. "); break; } /* Parse the key as string */ key = ParseString(); SkipUntil(':'); if (EndOfFile()) { PrintError("Syntax Error : ':' was expected. "); break; } m_data++; object[key] = this->ParseValue(); while (*m_data != ',' && *m_data != '}' && !EndOfFile()) m_data++; switch (*m_data) { case ',': m_data++; break; case '}': end = true; m_data++; break; default: PrintError("Syntax Error : ',' , '}' were expected. "); end = true; break; }; } return object; }
void CModHandler::loadGameContent() { CStopWatch timer, totalTime; CContentHandler content; logGlobal->infoStream() << "\tInitializing content handler: " << timer.getDiff() << " ms"; // first - load virtual "core" mod that contains all data // TODO? move all data into real mods? RoE, AB, SoD, WoG content.preloadModData("core", JsonNode(ResourceID("config/gameConfig.json"))); logGlobal->infoStream() << "\tParsing original game data: " << timer.getDiff() << " ms"; for(const TModID & modName : activeMods) { logGlobal->infoStream() << "\t\t" << allMods[modName].name; std::string modFileName = "mods/" + modName + "/mod.json"; const JsonNode config = JsonNode(ResourceID(modFileName)); JsonUtils::validate(config, "vcmi:mod", modName); content.preloadModData(modName, config); } logGlobal->infoStream() << "\tParsing mod data: " << timer.getDiff() << " ms"; content.loadMod("core"); logGlobal->infoStream() << "\tLoading original game data: " << timer.getDiff() << " ms"; for(const TModID & modName : activeMods) { content.loadMod(modName); logGlobal->infoStream() << "\t\t" << allMods[modName].name; } logGlobal->infoStream() << "\tLoading mod data: " << timer.getDiff() << "ms"; VLC->creh->loadCrExpBon(); VLC->creh->buildBonusTreeForTiers(); //do that after all new creatures are loaded identifiers.finalize(); logGlobal->infoStream() << "\tResolving identifiers: " << timer.getDiff() << " ms"; content.afterLoadFinalization(); logGlobal->infoStream() << "\tHandlers post-load finalization: " << timer.getDiff() << " ms"; logGlobal->infoStream() << "\tAll game content loaded in " << totalTime.getDiff() << " ms"; }
void CModHandler::loadMods() { const JsonNode modConfig = loadModSettings("config/modSettings.json"); loadMods("", "", modConfig["activeMods"], true); coreMod = CModInfo("core", modConfig["core"], JsonNode(ResourceID("config/gameConfig.json"))); coreMod.name = "Original game files"; }
JsonNode JsonReader::Parse(const char *filename) { std::ifstream file(filename, std::ios::in | std::ios::binary); if (!file.is_open()) { std::cout << "Fatal Error: File \"" << filename << "\" doesn't exist." << std::endl; return JsonNode(); } else { return this->Parse(file); } }
std::vector<JsonNode> CArtHandler::loadLegacyData(size_t dataSize) { artifacts.resize(dataSize); std::vector<JsonNode> h3Data; h3Data.reserve(dataSize); #define ART_POS(x) #x , const std::vector<std::string> artSlots = { ART_POS_LIST }; #undef ART_POS static std::map<char, std::string> classes = {{'S',"SPECIAL"}, {'T',"TREASURE"},{'N',"MINOR"},{'J',"MAJOR"},{'R',"RELIC"},}; CLegacyConfigParser parser("DATA/ARTRAITS.TXT"); CLegacyConfigParser events("DATA/ARTEVENT.TXT"); parser.endLine(); // header parser.endLine(); for (size_t i = 0; i < dataSize; i++) { JsonNode artData; artData["text"]["name"].String() = parser.readString(); artData["text"]["event"].String() = events.readString(); artData["value"].Float() = parser.readNumber(); for(auto & artSlot : artSlots) { if(parser.readString() == "x") { artData["slot"].Vector().push_back(JsonNode()); artData["slot"].Vector().back().String() = artSlot; } } artData["class"].String() = classes[parser.readString()[0]]; artData["text"]["description"].String() = parser.readString(); parser.endLine(); events.endLine(); h3Data.push_back(artData); } return h3Data; }
void CModHandler::loadMods(std::string path, std::string parent, const JsonNode & modSettings, bool enableMods) { for (std::string modName : getModList(path)) { boost::to_lower(modName); std::string modFullName = parent.empty() ? modName : parent + '.' + modName; if (CResourceHandler::get("initial")->existsResource(ResourceID(CModInfo::getModFile(modFullName)))) { CModInfo mod(modFullName, modSettings[modName], JsonNode(ResourceID(CModInfo::getModFile(modFullName)))); if (!parent.empty()) // this is submod, add parent to dependecies mod.dependencies.insert(parent); allMods[modFullName] = mod; if (mod.enabled && enableMods) activeMods.push_back(modFullName); loadMods(CModInfo::getModDir(modFullName) + '/', modFullName, modSettings[modName]["mods"], enableMods && mod.enabled); } } }
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; }
void SimpleJsonParser::parse( std::vector<CString>& tokens ) { enum ParseState { SCAN=1, ARRAY, PAIR, PAIR_COLON, RVALUE, RVALUE_SEPARATOR }; ParseState state = SCAN; LPCSTR tag_name = NULL; CString array_index; std::stack<JsonNode *> nodeStack; m_values.clear(); m_type = JSONROOT; nodeStack.push( this ); for ( CString& token : tokens ) { // printf( "%s ", (LPCSTR)token ); switch ( state ) { case SCAN: if ( token == "[" ) { // Start of array m_type = JSONARRAY; state = RVALUE; break; } else if ( token == "{" ) { // Start of object m_type = JSONOBJECT; state = PAIR; break; } throw std::exception( "Parser expected opening object or array" ); case PAIR: // Check for empty object if ( token == "}" && nodeStack.top()->m_type == JSONOBJECT && nodeStack.top()->m_values.size() == 0 ) { nodeStack.pop(); state = RVALUE_SEPARATOR; break; } tag_name = strip_quotes( token ); state = PAIR_COLON; break; case PAIR_COLON: if ( token != ":" ) throw std::exception( "Parser expecting colon seperator" ); state = RVALUE; break; case RVALUE: { if ( token == "]" ) { // Empty array if ( nodeStack.top()->m_type != JSONARRAY ) throw std::exception( "Unexpected array closing bracket" ); nodeStack.pop(); state = RVALUE_SEPARATOR; break; } JsonNode* node = nodeStack.top(); if ( node->m_type == JSONARRAY ) { array_index.Format( "%d", node->m_values.size() ); tag_name = (LPCSTR)array_index; } if ( node->m_values.find( tag_name ) != node->m_values.end() ) { CString error; error.Format( "Duplicate JSON tag name '%s'", tag_name ); throw std::exception( (LPCSTR)error ); } if ( token == "[" ) { node->m_values[ tag_name ] = JsonNode( JSONARRAY ); state = RVALUE; nodeStack.push( &node->m_values[ tag_name ] ); break; } if ( token == "{" ) { node->m_values[ tag_name ] = JsonNode( JSONOBJECT ); state = PAIR; nodeStack.push( &node->m_values[ tag_name ] ); break; } // Add a constant to current node container if ( node->m_type != JSONOBJECT && node->m_type != JSONARRAY) throw std::exception( "Parser expecting container JSON node" ); node->m_values[ tag_name ] = JsonNode( strip_quotes( token ) ); state = RVALUE_SEPARATOR; break; } case RVALUE_SEPARATOR: { JsonNode* node = nodeStack.top(); if ( token == "," ) { state = node->m_type == JSONARRAY ? RVALUE : PAIR; break; } if ( token == "}" && node->m_type == JSONOBJECT ) { nodeStack.pop(); break; } if ( token == "]" && node->m_type == JSONARRAY ) { // Assert all non-null nodes in the array are the same type JsonNodeType expected_type = JSONNULL; for ( auto child : node->m_values ) { if ( child.second.m_type == JSONNULL ) ; else if ( expected_type == JSONNULL ) expected_type = child.second.m_type; else if ( child.second.m_type != expected_type ) { CString error; error.Format( "Mixed object types in '%s'", child.first ); throw std::exception( (LPCSTR)error ); } } nodeStack.pop(); break; } throw std::exception( "Parser expecting object or array seperator" ); } } } if ( nodeStack.size() > 0 ) throw std::exception( "Unclosed JSON objects detected" ); }