Esempio n. 1
0
/*
	Scanning the files ... this is the business!!
*/
void scanFiles(const CSString &filespec)
{
	std::vector<std::string> filenames;

	buildFileVector(filenames, filespec);

	// if there s no file, nothing to do
	if (filenames.empty())
		return;

	// display the table header line
	fprintf(Outf,"FILE");
	for (unsigned i=0;i<fields.size();i++)
		fprintf(Outf,"%s%s",SEPARATOR, fields[i]._name.c_str());
	fprintf(Outf,"\n");

	UFormLoader *formLoader = NULL;
	NLMISC::TTime last = NLMISC::CTime::getLocalTime ();
	NLMISC::TTime start = NLMISC::CTime::getLocalTime ();

	NLMISC::CSmartPtr<UForm> form;


	for (uint j = 0; j < filenames.size(); j++)
	{
		if	(NLMISC::CTime::getLocalTime () > last + 5000)
		{
			last = NLMISC::CTime::getLocalTime ();
			if	(j>0)
			{
				nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/filenames.size(),j,filenames.size(), (filenames.size()-j)*(last-start)/j/1000);
			}

		}

		//std::string p = NLMISC::CPath::lookup (filenames[j], false, false);
		std::string p = filenames[j];
		if (p.empty()) continue;

		// create the georges loader if necessary
		if (formLoader == NULL)
		{
			WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
			formLoader = UFormLoader::createLoader ();
		}

		// Load the form with given sheet id
//		form = formLoader->loadForm (sheetIds[j].toString().c_str ());
		form = formLoader->loadForm (filenames[j].c_str ());
		if	(form)
		{
			// the form was found so read the true values from George
//			std::string s;
			fprintf(Outf,"%s",CFile::getFilenameWithoutExtension(filenames[j]).c_str());
			for	(unsigned i=0;i<fields.size();i++)
			{
				UFormElm::TWhereIsValue where;
				UFormElm	*fieldForm=NULL;
				std::string	valueString;
				
				form->getRootNode ().getNodeByName(&fieldForm, fields[i]._name.c_str());

				if	(fieldForm)
				{
					if	(fieldForm->isArray())	//	if its an array
					{
						uint	arraySize=0,arrayIndex=0;
						fieldForm->getArraySize(arraySize);
						while (arrayIndex<arraySize)
						{
							if	(fieldForm->getArrayValue(valueString,arrayIndex,fields[i]._evaluated, &where))
								;//addQuotesRoundString	(valueString);
							else
								setErrorString	(valueString, fields[i]._evaluated, where);

							arrayIndex++;
							if (arrayIndex<arraySize)	//	another value in the array..
								valueString+=ARRAY_SEPARATOR;
						}

					}
					else
					{
						if	(form->getRootNode ().getValueByName(valueString,fields[i]._name.c_str(),fields[i]._evaluated,&where))	//fieldForm->getValue(valueString,fields[i]._evaluated))
							;//addQuotesRoundString	(valueString);
						else
							setErrorString	(valueString, fields[i]._evaluated, where);
					}
				}
//				else	//	node not found.
//				{
//					setErrorString	(valueString, fields[i]._evaluated, where);
//				}

				replaceTrueAndFalseTagToCsv(valueString);

				fprintf(Outf,"%s%s", SEPARATOR, valueString.c_str());
				
//				UFormElm::TWhereIsValue where;
//
//				bool result=form->getRootNode ().getValueByName(s,fields[i]._name.c_str(),fields[i]._evaluated,&where);
//				if (!result)
//				{
//					if (fields[i]._evaluated)
//					{
//						s="ERR";
//					}
//					else
//					{
//						switch(where)
//						{
//						case UFormElm::ValueForm: s="ValueForm"; break;
//						case UFormElm::ValueParentForm: s="ValueParentForm"; break;
//						case UFormElm::ValueDefaultDfn: s="ValueDefaultDfn"; break;
//						case UFormElm::ValueDefaultType: s="ValueDefaultType"; break;
//						default: s="ERR";
//						}
//						
//					}
//					
//				}
//				else
//				{
//					// add quotes round strings
//					std::string hold=s;
//					s.erase();
//					s='\"';
//					for (unsigned i=0;i<hold.size();i++)
//					{
//						if (hold[i]=='\"')
//							s+="\"\"";
//						else
//							s+=hold[i];
//					}
//					s+='\"';
//				}
//				fprintf(Outf,"%s%s", SEPARATOR, s);
			}
			fprintf(Outf,"\n");
		}

	}

	// free the georges loader if necessary
	if (formLoader != NULL)
	{
		UFormLoader::releaseLoader (formLoader);
		WarningLog->removeFilter ("CFormLoader: Can't open the form file");
	}

	// housekeeping
//	sheetIds.clear ();
	filenames.clear ();

	fields.clear();
}
Esempio n. 2
0
/*
 * CSV -> Georges
 */
void	convertCsvFile( const string &file, bool generate, const string& sheetType )
{
	const uint			BUFFER_SIZE = 16*1024;
	char			lineBuffer[BUFFER_SIZE];
	FILE			*s;

	vector<string>	fields;
	vector<string>	args;

	if ((s = fopen(file.c_str(), "r")) == NULL)
	{
		fprintf(stderr, "Can't find file %s to convert\n", file.c_str());
		return;
	}

	loadSheetPath();

	UFormLoader *formLoader = UFormLoader::createLoader ();
	NLMISC::CSmartPtr<CForm> form;
	NLMISC::CSmartPtr<UFormDfn> formDfn;


	fgets(lineBuffer, BUFFER_SIZE, s);
	explode(std::string(lineBuffer), std::string(SEPARATOR), fields);

	vector<bool> activeFields( fields.size(), true );

	// Load DFN (generation only)
	set<CDfnField>	dfnFields;
	if ( generate )
	{
		formDfn = formLoader->loadFormDfn( (sheetType + ".dfn").c_str() );
		if ( ! formDfn )
			nlerror( "Can't find DFN for %s", sheetType.c_str() );
		fillFromDFN( formLoader, dfnFields, formDfn, "", sheetType );

		// Display missing fields and check fields against DFN
		uint i;
		for ( i=1; i!=fields.size(); ++i )
		{
			eraseCarriageReturnsAndMakeBlankNonAsciiChars( fields[i] );
			if ( fields[i].empty() )
			{
				nlinfo( "Skipping field #%u (empty)", i );
				activeFields[i] = false;
			}
			else if ( nlstricmp( fields[i], "parent" ) == 0 )
			{
				strlwr( fields[i] ); // non-const version
			}
			else
			{
				set<CDfnField>::iterator ist = dfnFields.find( CDfnField(fields[i]) );
				if ( ist == dfnFields.end() )
				{
					nlinfo( "Skipping field #%u (%s, not found in %s DFN)", i, fields[i].c_str(), sheetType.c_str() );
					activeFields[i] = false;
				}
			}
		}
		for ( i=1; i!=fields.size(); ++i )
		{
			if ( activeFields[i] )
				nlinfo( "Selected field: %s", fields[i].c_str() );
		}
	}

	string addExtension = "." + sheetType;
	uint dirmapLetterIndex = ~0;
	bool dirmapLetterBackward = false;
	vector<string> dirmapDirs;
	string dirmapSheetCode;
	bool WriteEmptyProperties = false, WriteSheetsToDisk = true;
	bool ForceInsertParents = false;

	if ( generate )
	{
		// Get the directory mapping
		try
		{
			CConfigFile dirmapcfg;
			dirmapcfg.load( sheetType + "_dirmap.cfg" );

			if ( OutputPath.empty() )
			{
				CConfigFile::CVar *path = dirmapcfg.getVarPtr( "OutputPath" );
				if ( path )
					OutputPath = path->asString();
				if ( ! OutputPath.empty() )
				{
					if ( OutputPath[OutputPath.size()-1] != '/' )
						OutputPath += '/';
					else if ( ! CFile::isDirectory( OutputPath ) )
						nlwarning( "Output path does not exist" );
				}
			}

			CConfigFile::CVar *letterIndex1 = dirmapcfg.getVarPtr( "LetterIndex" );
			if ( letterIndex1 && letterIndex1->asInt() > 0 )
			{
				dirmapLetterIndex = letterIndex1->asInt() - 1;

				CConfigFile::CVar *letterWay = dirmapcfg.getVarPtr( "LetterWay" );
				dirmapLetterBackward = (letterWay && (letterWay->asInt() == 1));
				
				CConfigFile::CVar dirs = dirmapcfg.getVar( "Directories" );
				for ( uint idm=0; idm!=dirs.size(); ++idm )
				{
					dirmapDirs.push_back( dirs.asString( idm ) );
					nlinfo( "Directory: %s", dirmapDirs.back().c_str() );
					if ( ! CFile::isExists( OutputPath + dirmapDirs.back() ) )
					{
						CFile::createDirectory( OutputPath + dirmapDirs.back() );
					}
					else
					{
						if ( ! CFile::isDirectory( OutputPath + dirmapDirs.back() ) )
						{
							nlwarning( "Already existing but not a directory!" );
						}
					}
				}

				nlinfo( "Mapping letter #%u (%s) of sheet name to directory", dirmapLetterIndex + 1, dirmapLetterBackward?"backward":"forward" );
			}
			
			CConfigFile::CVar *sheetCode = dirmapcfg.getVarPtr( "AddSheetCode" );
			if ( sheetCode )
				dirmapSheetCode = sheetCode->asString();
			nlinfo( "Sheet code: %s", dirmapSheetCode.c_str() );

			if ( ! dirmapLetterBackward )
				dirmapLetterIndex += dirmapSheetCode.size();

			CConfigFile::CVar *wep = dirmapcfg.getVarPtr( "WriteEmptyProperties" );
			if ( wep )
				WriteEmptyProperties = (wep->asInt() == 1);
			nlinfo( "Write empty properties mode: %s", WriteEmptyProperties ? "ON" : "OFF" );

			CConfigFile::CVar *wstd = dirmapcfg.getVarPtr( "WriteSheetsToDisk" );
			if ( wstd )
				WriteSheetsToDisk = (wstd->asInt() == 1);
			nlinfo( "Write sheets to disk mode: %s", WriteSheetsToDisk ? "ON" : "OFF" );

			CConfigFile::CVar *fiparents = dirmapcfg.getVarPtr( "ForceInsertParents" );
			if ( fiparents )
				ForceInsertParents = (fiparents->asInt() == 1);
			nlinfo( "Force insert parents mode: %s", ForceInsertParents ? "ON" : "OFF" );
		}
		catch ( EConfigFile& e )
		{
			nlwarning( "Problem in directory mapping: %s", e.what() );
		}
		

		nlinfo( "Using output path: %s", OutputPath.c_str() );
		nlinfo( "Press a key to generate *.%s", sheetType.c_str() );
		getchar();
		nlinfo( "Generating...." );

	}
	else
		nlinfo("Updating modifications (only modified fields are updated)");

	set<string> newSheets;
	uint nbNewSheets = 0, nbModifiedSheets = 0, nbUnchangedSheets = 0, nbWritten = 0;
	while (!feof(s))
	{
		lineBuffer[0] = '\0';
		fgets(lineBuffer, BUFFER_SIZE, s);
		explode(std::string(lineBuffer), std::string(SEPARATOR), args);

		if (args.size() < 1)
			continue;

		eraseCarriageReturnsAndMakeBlankNonAsciiChars( args[0] );
		replaceTrueAndFalseTagFromCsv(args);

		// Skip empty lines
		if ( args[0].empty() || (args[0] == string(".")+sheetType) )
			continue;

		//nldebug( "%s: %u", args[0].c_str(), args.size() );
		string	filebase = dirmapSheetCode+args[0]; /*+"."+sheetType;*/
		if (filebase.find("."+sheetType) == string::npos)
		{
			filebase += "." + sheetType;
		}
		strlwr	(filebase);
		string	filename, dirbase;
		bool	isNewSheet=true;

		// Locate existing sheet
//		map<string, string>::iterator it = inputSheetPathContent.find( CFile::getFilenameWithoutExtension( filebase ) );
		map<string, string>::iterator it = inputSheetPathContent.find( CFile::getFilename( filebase ) );
		
		if	(it == inputSheetPathContent.end())
		{
			// Not found
			if ( ! generate )
			{
				if ( ! filebase.empty() )
				{
					nlwarning( "Sheet %s not found", filebase.c_str( )); 
					continue;
				}
			}			
			else
			{
				// Load template sheet
				filename = strlwr( static_cast<const string&>(filebase) );
				form = (CForm*)formLoader->loadForm( (string("_empty.") + sheetType).c_str() );
				if (form == NULL)
				{
					nlerror( "Can't load sheet _empty.%s", sheetType.c_str() );
				}

				// Deduce directory from sheet name
				if ( dirmapLetterIndex != ~0 )
				{
					if ( dirmapLetterIndex < filebase.size() )
					{
						uint letterIndex;
						char c;
						if ( dirmapLetterBackward )
							letterIndex = filebase.size() - 1 - (CFile::getExtension( filebase ).size()+1) - dirmapLetterIndex;
						else
							letterIndex = dirmapLetterIndex;
						c = tolower( filebase[letterIndex] );
						vector<string>::const_iterator idm;
						for ( idm=dirmapDirs.begin(); idm!=dirmapDirs.end(); ++idm )
						{
							if ( (! (*idm).empty()) && (tolower((*idm)[0]) == c) )
							{
								dirbase = (*idm) + "/";
								break;
							}
						}
						if ( idm==dirmapDirs.end() )
						{
							nlinfo( "Directory mapping not found for %s (index %u)", filebase.c_str(), letterIndex );
							dirbase = ""; // put into root
						}
					}
					else
					{
						nlerror( "Can't map directory with letter #%u, greater than size of %s + code", dirmapLetterIndex, filebase.c_str() );
					}
				}

				nlinfo( "New sheet: %s", filebase.c_str() );
				++nbNewSheets;
				if ( ! newSheets.insert( filebase ).second )
					nlwarning( "Found duplicate sheet: %s", filebase.c_str() );
				isNewSheet = true;
			}
		}
		else // an existing sheet was found
		{

			// Load sheet (skip if failed)
			dirbase = "";
			filename = (*it).second; // whole path
			form = (CForm*)formLoader->loadForm( filename.c_str() );
			if (form == NULL)
			{
				nlwarning( "Can't load sheet %s", filename.c_str() );
				continue;
			}

			isNewSheet = false;
		}

		const	UFormElm	&rootForm=form->getRootNode();
		bool displayed = false;
		bool isModified = false;
		uint i;
		for (	i=1;	i<args.size		()
					&&	i<fields.size	();	++i )
		{
			const string	&var = fields[i];
			string			&val = args[i];

			eraseCarriageReturnsAndMakeBlankNonAsciiChars( val );

			// Skip column with inactive field (empty or not in DFN)
			if ( (! activeFields[i]) )
				continue;

			// Skip setting of empty cell except if required
			if ( (! WriteEmptyProperties) && val.empty() )
				continue;

			// Special case for parent sheet
			if	(var == "parent") // already case-lowered
			{
				vector<string> parentVals;
				explode( val, std::string(ARRAY_SEPARATOR), parentVals );
				if ( (parentVals.size() == 1) && (parentVals[0].empty()) )
					parentVals.clear();

				if ( (isNewSheet || ForceInsertParents) && (! parentVals.empty()) )
				{
					// This is slow. Opti: insertParent() should have an option to do it without loading the form
					//	parent have same type that this object (postulat).
					uint	nbinsertedparents=0;

					for ( uint p=0; p!=parentVals.size(); ++p )
					{						
						string	localExtension=(parentVals[p].find(addExtension)==string::npos)?addExtension:"";
						string	parentName=parentVals[p]+localExtension;

						CSmartPtr<CForm> parentForm = (CForm*)formLoader->loadForm(CFile::getFilename(parentName.c_str()).c_str());
						if ( ! parentForm )
						{
							nlwarning( "Can't load parent form %s", parentName.c_str() );
						}
						else
						{
							form->insertParent( p, parentName.c_str(), parentForm );
							isModified=true;
							displayed = true;
							nbinsertedparents++;
						}

					}
					nlinfo( "Inserted %u parent(s)", nbinsertedparents );
				}
				// NOTE: Changing the parent is not currently implemented!
				continue;
			}

			const	UFormElm	*fieldForm=NULL;
						
			if	(rootForm.getNodeByName(&fieldForm, var.c_str()))
			{
				UFormDfn	*dfnForm=const_cast<UFormElm&>(rootForm).getStructDfn();
				nlassert(dfnForm);
								
				vector<string> memberVals;
				explode( val, std::string(ARRAY_SEPARATOR), memberVals );
				uint32	memberIndex=0;
				
				while (memberIndex<memberVals.size())
				{
					const	uint	currentMemberIndex=memberIndex;
					std::string		memberVal=memberVals[memberIndex];
					memberIndex++;
					
					if	(!memberVal.empty())
					{
						if (memberVal[0] == '"')
							memberVal.erase(0, 1);
						if (memberVal.size()>0 && memberVal[memberVal.size()-1] == '"')
							memberVal.resize(memberVal.size()-1);
						
						if (memberVal == "ValueForm" ||
							memberVal == "ValueParentForm" ||
							memberVal == "ValueDefaultDfn" ||
							memberVal == "ValueDefaultType" ||
							memberVal == "ERR")
							continue;
					}


					//				nlassert(fieldDfn);
					//				virtual bool getEntryFilenameExt (uint entry, std::string &name) const = 0;
					//				virtual bool getEntryFilename (uint entry, std::string &name) const = 0;
					if (dfnForm)
					{
						string	fileName;
						string	fileNameExt;
						bool	toto=false;
						static	string	filenameTyp("filename.typ");
						string	extension;
			
						uint	fieldIndex;
						if (dfnForm->getEntryIndexByName (fieldIndex, var))	//	field exists.
						{
							dfnForm->getEntryFilename(fieldIndex,fileName);
							if (fileName==filenameTyp)
							{
								dfnForm->getEntryFilenameExt(fieldIndex,fileNameExt);
								if (	!fileNameExt.empty()
									&&	fileNameExt!="*.*")
								{
									string::size_type	index=fileNameExt.find(".");
									if (index==string::npos)	//	not found.
									{
										extension=fileNameExt;
									}
									else
									{
										extension=fileNameExt.substr(index+1);
									}
									
									if	(memberVal.find(extension)==string::npos)	// extension not found.
									{
										memberVal=NLMISC::toString("%s.%s",memberVal.c_str(),extension.c_str());
									}
									
								}
								
							}
							
						}
						
					}
					

					if	(dfnForm->isAnArrayEntryByName(var))
					{
						if	(	!isNewSheet
							&&	fieldForm!=NULL)
						{
							uint arraySize;
							const UFormElm *arrayNode = NULL;
							if (fieldForm->isArray() 
								&& fieldForm->getArraySize(arraySize) && arraySize == memberVals.size())
							{
								string	test;
								if	(	fieldForm->getArrayValue(test, currentMemberIndex)
									&&	test==memberVal	)
								{
									continue;
								}
							}
						}
						//nldebug( "%s: %s '%s'", args[0].c_str(), var.c_str(), memberVal.c_str() );
						// need to put the value at the correct index.
						const	std::string	fieldName=NLMISC::toString("%s[%d]", var.c_str(), currentMemberIndex).c_str();
						const_cast<UFormElm&>(rootForm).setValueByName(memberVal.c_str(), fieldName.c_str());
						isModified=true;
						displayed = true;
					}
					else
					{
						if	(!isNewSheet)
						{
							string	test;
							if	(	rootForm.getValueByName(test,var.c_str())
								&&	test==memberVal	)
							{
								continue;
							}
							
						}					
						//nldebug( "%s: %s '%s'", args[0].c_str(), var.c_str(), memberVal.c_str() );
						const_cast<UFormElm&>(rootForm).setValueByName(memberVal.c_str(), var.c_str());
						isModified=true;
						displayed = true;
					}
					
					if	(!isNewSheet)
					{
						isModified = true;
						if (!displayed)
							nlinfo("in %s:", filename.c_str());
						displayed = true;
						nlinfo("%s = %s", var.c_str(), memberVal.c_str());
					}

				}

			}
			else	//	field Node not found :\ (bad)
			{
			}
			
		}

		if ( ! isNewSheet )
		{
			if ( isModified )
				++nbModifiedSheets;
			else
				++nbUnchangedSheets;
		}

		// Write sheet
		if ( isNewSheet || displayed )
		{
			if ( WriteSheetsToDisk )
			{
				++nbWritten;
				string	path = isNewSheet ? OutputPath : "";
				string	ext = (filename.find( addExtension ) == string::npos) ? addExtension : "";
				string	absoluteFileName=path + dirbase + filename + ext;
				
//				nlinfo("opening: %s",  absoluteFileName.c_str() );
				COFile	output(absoluteFileName);
				if	(!output.isOpen())
				{
					nlinfo("creating path: %s",  (path + dirbase).c_str() );
					NLMISC::CFile::createDirectory(path + dirbase);
				}

//				nlinfo("opening2: %s",  absoluteFileName.c_str() );
				output.open	(absoluteFileName);
				
				if (!output.isOpen())
				{					
					nlinfo("ERROR! cannot create file path: %s",  absoluteFileName.c_str() );
				}
				else
				{
					form->write(output, true);
					output.close();
					
					if	(!CPath::exists(filename + ext))
						CPath::addSearchFile(absoluteFileName);					
				}					

			}
			clearSheet( form, &form->getRootNode() );
		}

	}
	nlinfo( "%u sheets processed (%u new, %u modified, %u unchanged - %u written)", nbNewSheets+nbModifiedSheets+nbUnchangedSheets, nbNewSheets, nbModifiedSheets, nbUnchangedSheets, nbWritten );
	UFormLoader::releaseLoader (formLoader);
}
Esempio n. 3
0
//-----------------------------------------------
// readGeorges for CStaticSkillsTree
//
//-----------------------------------------------
void CStaticSkillsTree::readGeorges( const NLMISC::CSmartPtr<NLGEORGES::UForm> &form, const NLMISC::CSheetId &sheetId )
{
	if( form )
	{
		UFormElm& root = form->getRootNode();
		
		UFormElm *arraySkillElt = NULL;
		if( root.getNodeByName( &arraySkillElt, "SkillData" ) )
		{
			if( arraySkillElt )
			{
				uint NbSkills;
				nlverify( arraySkillElt->getArraySize( NbSkills ) );

				nlassertex( NbSkills == SKILLS::NUM_SKILLS, ("(%u != %u) Please synchronise game_share/skill.* with leveldesign/game_element/xp_table/skills.skill_tree (use skill_extractor.exe)", NbSkills, SKILLS::NUM_SKILLS));

				SkillsTree.resize( NbSkills );
				
				for( uint i = 0; i < NbSkills; ++i )
				{
					UFormElm* SkillElt = NULL;
					if( ! ( arraySkillElt->getArrayNode( &SkillElt, i ) && SkillElt ) )
					{
						nlwarning("<CStaticSkillsTree::readGeorges> can't get array node of SkillElt in sheet %s", sheetId.toString().c_str() );
					}
					else
					{
						// Skill
						string SkillName;
						SkillElt->getValueByName( SkillName, "Skill" );
						SKILLS::ESkills skill = SKILLS::toSkill( SkillName );
						nlassert( skill != SKILLS::unknown );
						if (skill == SKILLS::unknown)
						{
							continue;
						}
						SkillsTree[ skill ].Skill = skill;

						if( ! SkillElt->getValueByName( SkillsTree[ skill ].SkillCode, "SkillCode" ) )
						{
							nlwarning("<CStaticSkillsTree::readGeorges> can't get node SkillCode in sheet %s", sheetId.toString().c_str() );
						}

						// Skill Code
						if( ! SkillElt->getValueByName( SkillsTree[ skill ].SkillCode, "SkillCode" ) )
						{
							nlwarning("<CStaticSkillsTree::readGeorges> can't get node SkillCode in sheet %s", sheetId.toString().c_str() );
						}

						// Max skill value
						if( ! SkillElt->getValueByName( SkillsTree[ skill ].MaxSkillValue, "MaxSkillValue" ) )
						{
							nlwarning("<CStaticSkillsTree::readGeorges> can't get node MaxSkillValue in sheet %s", sheetId.toString().c_str() );
						}

						// Type of stage
						if( ! SkillElt->getValueByName( SkillsTree[ skill ].StageType, "Type of Stage" ) )
						{
							nlwarning("<CStaticSkillsTree::readGeorges> can't get node 'Type of Stage' in sheet %s", sheetId.toString().c_str() );
						}

						// ParentSkill
						if( ! SkillElt->getValueByName( SkillName, "ParentSkill" ) )
						{
							nlwarning("<CStaticSkillsTree::readGeorges> can't get node ParentSkills in sheet %s", sheetId.toString().c_str() );
						}
						else
						{	
							SkillsTree[ skill ].ParentSkill = SKILLS::toSkill( SkillName );
						}

						// ChildSkills
						UFormElm *arrayChildSkillElt = NULL;
						if( SkillElt->getNodeByName( &arrayChildSkillElt, "ChildSkills" ) )
						{
							if( arrayChildSkillElt )
							{
								uint NbChildSkills;
								nlverify( arrayChildSkillElt->getArraySize( NbChildSkills ) );
								
								SkillsTree[ skill ].ChildSkills.resize( NbChildSkills );
								
								for( uint i = 0; i < NbChildSkills; ++i )
								{
									string childSkillName;
									arrayChildSkillElt->getArrayValue( childSkillName, i );
									SKILLS::ESkills childSkill = SKILLS::toSkill( childSkillName );
									nlassert( childSkill != SKILLS::unknown );
									if (skill == SKILLS::unknown)
									  {
										continue;
									  }
									SkillsTree[ skill ].ChildSkills[ i ] = childSkill;
								}
							}
						}
					}
				}
			}
		}
	}
}