bool CvCorporationEntry::CacheResults(Database::Results& kResults, CvDatabaseUtility& kUtility)
{
	if(!CvBaseInfo::CacheResults(kResults, kUtility))
		return false;

	m_iMaxFranchises = kResults.GetInt("MaxFranchises");
	m_iNumFreeTradeRoutes = kResults.GetInt("NumFreeTradeRoutes");
	m_iTradeRouteLandDistanceModifier = kResults.GetInt("TradeRouteLandDistanceModifier");
	m_iTradeRouteSeaDistanceModifier = kResults.GetInt("TradeRouteSeaDistanceModifier");
	m_iTradeRouteSpeedModifier = kResults.GetInt("TradeRouteSpeedModifier");
	m_iTradeRouteVisionBoost = kResults.GetInt("TradeRouteVisionBoost");
	m_bTradeRoutesInvulnerable = kResults.GetBool("TradeRoutesInvulnerable");
	m_iTradeRouteRecipientBonus = kResults.GetInt("TradeRouteRecipientBonus");
	m_iTradeRouteTargetBonus = kResults.GetInt("TradeRouteTargetBonus");

	//References
	const char* szTextVal = NULL;
	szTextVal = kResults.GetText("HeadquartersBuildingClass");
	m_eHeadquartersBuildingClass = (BuildingClassTypes) GC.getInfoTypeForString(szTextVal, true);

	szTextVal = kResults.GetText("OfficeBuildingClass");
	m_eOfficeBuildingClass = (BuildingClassTypes) GC.getInfoTypeForString(szTextVal, true);
	
	szTextVal = kResults.GetText("FranchiseBuildingClass");
	m_eFranchiseBuildingClass = (BuildingClassTypes) GC.getInfoTypeForString(szTextVal, true);

	szTextVal = kResults.GetText("OfficeBenefitHelper");
	m_strOfficeBenefitHelper = szTextVal;

	// This is not ideal, but Corporations are loaded last, and I want an easy way to tell if a building class is owned by a Corporation
	// Note: Intellisense may lie here! This will compile (declared as friend)
	CvBuildingClassInfo* pkBuildingInfo = GC.getBuildingClassInfo(m_eHeadquartersBuildingClass);
	if (pkBuildingInfo)
	{
		pkBuildingInfo->m_eCorporationType = (CorporationTypes) GetID();
		pkBuildingInfo->m_bIsHeadquarters = true;
	}
	pkBuildingInfo = GC.getBuildingClassInfo(m_eOfficeBuildingClass);
	if (pkBuildingInfo)
	{
		pkBuildingInfo->m_eCorporationType = (CorporationTypes) GetID();
		pkBuildingInfo->m_bIsOffice = true;
	}
	pkBuildingInfo = GC.getBuildingClassInfo(m_eFranchiseBuildingClass);
	if (pkBuildingInfo)
	{
		pkBuildingInfo->m_eCorporationType = (CorporationTypes) GetID();
		pkBuildingInfo->m_bIsFranchise = true;
	}

	const char* szCorporationType = GetType();

	kUtility.PopulateArrayByExistence(m_piResourceMonopolyAnd, "Resources", "Corporation_ResourceMonopolyAnds", "ResourceType", "CorporationType", szCorporationType);
	kUtility.PopulateArrayByExistence(m_piResourceMonopolyOrs, "Resources", "Corporation_ResourceMonopolyOrs", "ResourceType", "CorporationType", szCorporationType);
	kUtility.PopulateArrayByValue(m_piNumFreeResource, "Resources", "Corporation_NumFreeResource", "ResourceType", "CorporationType", szCorporationType, "NumResource");
	kUtility.PopulateArrayByValue(m_piUnitResourceProductionModifier, "Resources", "Corporation_UnitResourceProductionModifier", "ResourceType", "CorporationType", szCorporationType, "Modifier");
	kUtility.SetYields(m_piTradeRouteCityMod, "Corporation_TradeRouteCityYield", "CorporationType", szCorporationType);
	kUtility.SetYields(m_piTradeRouteMod, "Corporation_TradeRouteMod", "CorporationType", szCorporationType);

	//BuildingClassYieldChanges
	{
		kUtility.Initialize2DArray(m_ppiBuildingClassYieldChanges, "BuildingClasses", "Yields");

		std::string strKey("Corporation_BuildingClassYieldChanges");
		Database::Results* pResults = kUtility.GetResults(strKey);
		if (pResults == NULL)
		{
			pResults = kUtility.PrepareResults(strKey, "select BuildingClasses.ID as BuildingClassID, Yields.ID as YieldID, YieldChange from Corporation_BuildingClassYieldChanges inner join BuildingClasses on BuildingClasses.Type = BuildingClassType inner join Yields on Yields.Type = YieldType where CorporationType = ?");
		}

		pResults->Bind(1, szCorporationType);

		while (pResults->Step())
		{
			const int BuildingClassID = pResults->GetInt(0);
			const int iYieldID = pResults->GetInt(1);
			const int iYieldChange = pResults->GetInt(2);

			m_ppiBuildingClassYieldChanges[BuildingClassID][iYieldID] = iYieldChange;
		}
	}
	//ResourceYieldChanges
	{
		kUtility.Initialize2DArray(m_ppaiResourceYieldChange, "Resources", "Yields");

		std::string strKey("Corporation_ResourceYieldChanges");
		Database::Results* pResults = kUtility.GetResults(strKey);
		if (pResults == NULL)
		{
			pResults = kUtility.PrepareResults(strKey, "select Resources.ID as ResourceID, Yields.ID as YieldID, Yield from Corporation_ResourceYieldChanges inner join Resources on Resources.Type = ResourceType inner join Yields on Yields.Type = YieldType where CorporationType = ?");
		}

		pResults->Bind(1, szCorporationType);

		while (pResults->Step())
		{
			const int ResourceID = pResults->GetInt(0);
			const int YieldID = pResults->GetInt(1);
			const int yield = pResults->GetInt(2);

			m_ppaiResourceYieldChange[ResourceID][YieldID] = yield;
		}
	}

	//SpecialistYieldChanges
	{
		kUtility.Initialize2DArray(m_ppaiSpecialistYieldChange, "Specialists", "Yields");

		std::string strKey("Corporation_SpecialistYieldChanges");
		Database::Results* pResults = kUtility.GetResults(strKey);
		if (pResults == NULL)
		{
			pResults = kUtility.PrepareResults(strKey, "select Specialists.ID as SpecialistID, Yields.ID as YieldID, Yield from Corporation_SpecialistYieldChanges inner join Specialists on Specialists.Type = SpecialistType inner join Yields on Yields.Type = YieldType where CorporationType = ?");
		}

		pResults->Bind(1, szCorporationType);

		while (pResults->Step())
		{
			const int SpecialistID = pResults->GetInt(0);
			const int YieldID = pResults->GetInt(1);
			const int yield = pResults->GetInt(2);

			m_ppaiSpecialistYieldChange[SpecialistID][YieldID] = yield;
		}
	}

	return true;
}
예제 #2
0
void CvTypes::AcquireTypes(Database::Connection& db)
{

	//ArtifactType
	{
		typedef std::tr1::unordered_map<std::string, GreatWorkArtifactClass*> LookupTable;
		LookupTable kArtifactTypeLookupTable;
		kArtifactTypeLookupTable.insert(make_pair(std::string("ARTIFACT_ANCIENT_RUIN"), &s_eARTIFACT_ANCIENT_RUIN));
		kArtifactTypeLookupTable.insert(make_pair(std::string("ARTIFACT_BARBARIAN_CAMP"), &s_eARTIFACT_BARBARIAN_CAMP));
		kArtifactTypeLookupTable.insert(make_pair(std::string("ARTIFACT_BATTLE_RANGED"), &s_eARTIFACT_BATTLE_RANGED));
		kArtifactTypeLookupTable.insert(make_pair(std::string("ARTIFACT_BATTLE_MELEE"), &s_eARTIFACT_BATTLE_MELEE));
		kArtifactTypeLookupTable.insert(make_pair(std::string("ARTIFACT_RAZED_CITY"), &s_eARTIFACT_RAZED_CITY));
		kArtifactTypeLookupTable.insert(make_pair(std::string("ARTIFACT_WRITING"), &s_eARTIFACT_WRITING));

		Database::Results kResults;
		if(db.Execute(kResults, "SELECT Type, ID from GreatWorkArtifactClasses"))
		{
			while(kResults.Step())
			{
				std::string strArtifactType = kResults.GetText(0);
				LookupTable::iterator it = kArtifactTypeLookupTable.find(strArtifactType);
				if(it != kArtifactTypeLookupTable.end())
				{
					(*it->second) = static_cast<GreatWorkArtifactClass>(kResults.GetInt(1));
				}
			}
		}

		for(LookupTable::iterator it = kArtifactTypeLookupTable.begin(); it != kArtifactTypeLookupTable.end(); ++it)
		{
			if((*it->second) == NO_GREAT_WORK_ARTIFACT_CLASS)
			{
				char msg[256] = {0};
				sprintf_s(msg, "ArtifactType - %s is used in the DLL but does not exist in the database.", it->first.c_str());
				FILogFile* pLog = LOGFILEMGR.GetLog("Gamecore.log", FILogFile::kDontTimeStamp);
				pLog->WarningMsg(msg);
				CvAssertMsg(false, msg);
			}
		}
	}

	//GreatWorkSlots
	{
		typedef std::tr1::unordered_map<std::string, GreatWorkSlotType*> LookupTable;
		LookupTable kTypeLookupTable;
		kTypeLookupTable.insert(make_pair(std::string("GREAT_WORK_SLOT_ART_ARTIFACT"), &s_eGREAT_WORK_SLOT_ART_ARTIFACT));
		kTypeLookupTable.insert(make_pair(std::string("GREAT_WORK_SLOT_LITERATURE"), &s_eGREAT_WORK_SLOT_LITERATURE));
		kTypeLookupTable.insert(make_pair(std::string("GREAT_WORK_SLOT_MUSIC"), &s_eGREAT_WORK_SLOT_MUSIC));

		Database::Results kResults;
		if(db.Execute(kResults, "SELECT Type, ID from GreatWorkSlots"))
		{
			while(kResults.Step())
			{
				std::string strType = kResults.GetText(0);
				LookupTable::iterator it = kTypeLookupTable.find(strType);
				if(it != kTypeLookupTable.end())
				{
					(*it->second) = static_cast<GreatWorkSlotType>(kResults.GetInt(1));
				}
			}
		}

		for(LookupTable::iterator it = kTypeLookupTable.begin(); it != kTypeLookupTable.end(); ++it)
		{
			if((*it->second) == NO_GREAT_WORK_SLOT)
			{
				char msg[256] = {0};
				sprintf_s(msg, "GreatWorkSlotType - %s is used in the DLL but does not exist in the database.", it->first.c_str());
				FILogFile* pLog = LOGFILEMGR.GetLog("Gamecore.log", FILogFile::kDontTimeStamp);
				pLog->WarningMsg(msg);
				CvAssertMsg(false, msg);
			}
		}
	}

	//MissionTypes
	{
		typedef std::tr1::unordered_map<std::string, MissionTypes*> LookupTable;
		LookupTable kMissionTypesLookupTable;
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_MOVE_TO"), &s_eMISSION_MOVE_TO));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_ROUTE_TO"), &s_eMISSION_ROUTE_TO));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_MOVE_TO_UNIT"), &s_eMISSION_MOVE_TO_UNIT));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_SWAP_UNITS"), &s_eMISSION_SWAP_UNITS));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_SKIP"), &s_eMISSION_SKIP));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_SLEEP"), &s_eMISSION_SLEEP));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_ALERT"), &s_eMISSION_ALERT));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_FORTIFY"), &s_eMISSION_FORTIFY));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_GARRISON"), &s_eMISSION_GARRISON));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_SET_UP_FOR_RANGED_ATTACK"), &s_eMISSION_SET_UP_FOR_RANGED_ATTACK));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_EMBARK"), &s_eMISSION_EMBARK));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_DISEMBARK"), &s_eMISSION_DISEMBARK));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_AIRPATROL"), &s_eMISSION_AIRPATROL));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_HEAL"), &s_eMISSION_HEAL));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_AIRLIFT"), &s_eMISSION_AIRLIFT));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_NUKE"), &s_eMISSION_NUKE));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_PARADROP"), &s_eMISSION_PARADROP));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_AIR_SWEEP"), &s_eMISSION_AIR_SWEEP));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_REBASE"), &s_eMISSION_REBASE));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_RANGE_ATTACK"), &s_eMISSION_RANGE_ATTACK));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_PILLAGE"), &s_eMISSION_PILLAGE));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_FOUND"), &s_eMISSION_FOUND));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_JOIN"), &s_eMISSION_JOIN));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_CONSTRUCT"), &s_eMISSION_CONSTRUCT));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_DISCOVER"), &s_eMISSION_DISCOVER));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_HURRY"), &s_eMISSION_HURRY));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_TRADE"), &s_eMISSION_TRADE));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_BUY_CITY_STATE"), &s_eMISSION_BUY_CITY_STATE));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_REPAIR_FLEET"), &s_eMISSION_REPAIR_FLEET));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_SPACESHIP"), &s_eMISSION_SPACESHIP));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_CULTURE_BOMB"), &s_eMISSION_CULTURE_BOMB));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_FOUND_RELIGION"), &s_eMISSION_FOUND_RELIGION));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_GOLDEN_AGE"), &s_eMISSION_GOLDEN_AGE));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_BUILD"), &s_eMISSION_BUILD));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_LEAD"), &s_eMISSION_LEAD));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_DIE_ANIMATION"), &s_eMISSION_DIE_ANIMATION));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_BEGIN_COMBAT"), &s_eMISSION_BEGIN_COMBAT));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_END_COMBAT"), &s_eMISSION_END_COMBAT));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_AIRSTRIKE"), &s_eMISSION_AIRSTRIKE));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_SURRENDER"), &s_eMISSION_SURRENDER));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_CAPTURED"), &s_eMISSION_CAPTURED));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_IDLE"), &s_eMISSION_IDLE));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_DIE"), &s_eMISSION_DIE));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_DAMAGE"), &s_eMISSION_DAMAGE));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_MULTI_SELECT"), &s_eMISSION_MULTI_SELECT));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_MULTI_DESELECT"), &s_eMISSION_MULTI_DESELECT));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_WAIT_FOR"), &s_eMISSION_WAIT_FOR));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_SPREAD_RELIGION"), &s_eMISSION_SPREAD_RELIGION));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_ENHANCE_RELIGION"), &s_eMISSION_ENHANCE_RELIGION));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_REMOVE_HERESY"), &s_eMISSION_REMOVE_HERESY));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_ESTABLISH_TRADE_ROUTE"), &s_eMISSION_ESTABLISH_TRADE_ROUTE));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_PLUNDER_TRADE_ROUTE"), &s_eMISSION_PLUNDER_TRADE_ROUTE));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_CREATE_GREAT_WORK"), &s_eMISSION_GREAT_WORK));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_CHANGE_TRADE_UNIT_HOME_CITY"), &s_eMISSION_CHANGE_TRADE_UNIT_HOME_CITY));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_SELL_EXOTIC_GOODS"), &s_eMISSION_SELL_EXOTIC_GOODS));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_GIVE_POLICIES"), &s_eMISSION_GIVE_POLICIES));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_ONE_SHOT_TOURISM"), &s_eMISSION_ONE_SHOT_TOURISM));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_CHANGE_ADMIRAL_PORT"), &s_eMISSION_CHANGE_ADMIRAL_PORT));
#ifdef Imperial_Combat_BomberMission_FireBombing
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_FIREBOMB_IMPROVEMENT"), &s_eMISSION_FIREBOMB_IMPROVEMENT));
		kMissionTypesLookupTable.insert(make_pair(std::string("MISSION_FIREBOMB_BUILDING"), &s_eMISSION_FIREBOMB_BUILDING));
#endif
		Database::Results kResults;
		if(db.Execute(kResults, "SELECT Type, ID from Missions"))
		{
			while(kResults.Step())
			{
				std::string strMissionType = kResults.GetText(0);
				LookupTable::iterator it = kMissionTypesLookupTable.find(strMissionType);
				if(it != kMissionTypesLookupTable.end())
				{
					(*it->second) = static_cast<MissionTypes>(kResults.GetInt(1));
				}
			}
		}

		int iNumTypes = db.Count("Missions", false);
		if(iNumTypes >= 0)
		{
			s_uiNUM_MISSION_TYPES = static_cast<unsigned int>(iNumTypes);
		}

		for(LookupTable::iterator it = kMissionTypesLookupTable.begin(); it != kMissionTypesLookupTable.end(); ++it)
		{
			if((*it->second) == NO_MISSION)
			{
				char msg[256] = {0};
				sprintf_s(msg, "MissionType - %s is used in the DLL but does not exist in the database.", it->first.c_str());
				FILogFile* pLog = LOGFILEMGR.GetLog("Gamecore.log", FILogFile::kDontTimeStamp);
				pLog->WarningMsg(msg);
				CvAssertMsg(false, msg);
			}
		}
	}
}
//------------------------------------------------------------------------------
bool CvDllDatabaseUtility::ValidateGameDatabase()
{
	//This function contains a suite of useful game database unit tests that will
	//ensure the database conforms to certain unique rules of Civ5.
	if(!gDLL->ShouldValidateGameDatabase())
	{
		LogMsg("*** SKIPPING Game Database Validation. ****");
		LogMsg("You can enable it by setting 'ValidateGameDatabase = 1' in config.ini");
		return true;
	}

	cvStopWatch kPerfTest("Validating Game Database", "xml-perf.log");
	bool bError = false;

	LogMsg("**** Validating Game Database *****");

	//Test that all Tables w/ 'ID' column start at 0 and not 1.
	{
		cvStopWatch watch("Ensure All Tables with 'ID' column start at 0");
		Database::Results kTables("name");
		if(DB.SelectAt(kTables, "sqlite_master", "type", "table"))
		{
			while(kTables.Step())
			{
				const char* szTableName = kTables.GetText(0);
				if(DB.Count(szTableName) > 0)
				{
					//Test if table has 'ID' column
					bool bHasIDColumn = false;
					{
						//Execute "select ID from <table_name> limit 1;
						//If there's a SQL error, it's most likely due to a lack of an 'id' column.
						char szSQL[512];
						sprintf_s(szSQL, "pragma table_info(%s)", szTableName);
						Database::Results kResults;
						DB.Execute(kResults, szSQL);
						while(kResults.Step())
						{
							const char* szName = kResults.GetText("name");
							if(strcmp(szTableName, szName) == 0)
							{
								bHasIDColumn = true;
								break;
							}

						}
					}

					if(bHasIDColumn)
					{
						Database::SingleResult kTest;
						if(!DB.SelectAt(kTest, szTableName, "ID", 0))
						{
							//Table has 'ID' column and contains data but does not use ID 0.
							char szError[512];
							sprintf_s(szError, "Table '%s' contains 'ID' column that starts at 1 instead of 0.", szTableName);
							LogMsg(szError);
							bError = true;
						}
					}

				}
			}
		}
	}

	//Validate FK constraints
	{
		cvStopWatch watch("Validate FK Constraints");
		DB.ValidateFKConstraints();
	}

	LogMsg("Performing Localization Checks");
	{
		cvStopWatch watch("Localization Checks");
		LogMsg("Checking Tag Format...");
		LogMsg("Note: Tags must only use [A-Z_] characters, start with 'TXT_KEY_', and be under 128 characters long.");

		Database::Results kLanguages;
		if(DB.SelectAll(kLanguages, "Languages"))
		{
			while(kLanguages.Step())
			{
				const char* szTagColumnName = kLanguages.GetText("TagColumnName");
				const char* szTableName = kLanguages.GetText("TableName");

				Database::Results kResults;
				char szSQL[512];
				sprintf_s(szSQL, "SELECT DISTINCT %s from %s", szTagColumnName, szTableName);
				if(DB.Execute(kResults, szSQL))
				{
					bool bFirst = true;
					while(kResults.Step())
					{
						const char* szTag = kResults.GetText(0);
						const size_t len = strlen(szTag);
						if(len > 128)
						{
							if(bFirst)
							{
								LogMsg("In table %s...", szTableName);
								bFirst = false;
							}

							bError =  true;
							LogMsg("Tag (%s) has size greater than 127 characters.", szTag);
						}
						else
						{
							if(strncmp("TXT_KEY_", szTag, 8) != 0)
							{
								if(bFirst)
								{
									LogMsg("In table %s...", szTableName);
									bFirst = false;
								}

								bError = true;
								LogMsg("Tag (%s) does not start with 'TXT_KEY_'", szTag);
							}

							for(size_t i = 0; i < len; ++i)
							{
								char ch = szTag[i];
								if(ch != '_' && !((ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')))
								{
									if(bFirst)
									{
										LogMsg("In table %s...", szTableName);
										bFirst = false;
									}

									bError = true;
									LogMsg("Tag (%s) contains invalid character (%.1s)", szTag, &ch);
								}
							}
						}
					}
				}
			}
		}
	}

	LogMsg("Validating UnitGameplay2DScripts");
	{
		cvStopWatch watch("Validating UnitGameplay2DScripts");
		Database::Results kResults;
		if(DB.Execute(kResults, "Select Type from Units where not exists (select 1 from UnitGameplay2DScripts where UnitType = Units.Type limit 1)"))
		{
			while(kResults.Step())
			{
				const char* szUnitType = kResults.GetText(0);
				LogMsg("Missing Entry for %s", szUnitType);
				bError = true;
			}
		}
	}

	if(bError)
	{
		LogMsg("**** VALIDATION FAILED *****");
	}
	else
	{
		LogMsg("**** Validation Success *****");
	}

	kPerfTest.EndPerfTest();
	LogMsg("Validation Took %f seconds", kPerfTest.GetDeltaInSeconds());

	return !bError;
}
//------------------------------------------------------------------------------
bool CvDllDatabaseUtility::PrefetchGameData()
{
	cvStopWatch kTest("PrefetchGameData", "xml-perf.log");

	//Because Colors and PlayerColors are used everywhere during load
	//(by the translator) we load interface infos first.
	//Interface
	PrefetchCollection(GC.GetColorInfo(), "Colors");
	PrefetchCollection(GC.GetPlayerColorInfo(), "PlayerColors");
	PrefetchCollection(GC.getInterfaceModeInfo(), "InterfaceModes");

	//AI
	PrefetchCollection(GC.getAICityStrategyInfo(), "AICityStrategies");
	PrefetchCollection(GC.getEconomicAIStrategyInfo(), "AIEconomicStrategies");
	PrefetchCollection(GC.getAIGrandStrategyInfo(), "AIGrandStrategies");
	PrefetchCollection(GC.getMilitaryAIStrategyInfo(), "AIMilitaryStrategies");
	PrefetchCollection(GC.getCitySpecializationInfo(), "CitySpecializations");
	PrefetchCollection(GC.getTacticalMoveInfo(), "TacticalMoves");

	//BasicInfos
	//AnimationOperators?
	//Attitudes?
	PrefetchCollection(GC.getUnitAIInfo(), "UnitAIInfos");
	PrefetchCollection(GC.getUnitCombatClassInfo(), "UnitCombatInfos");

	//Buildings
	PrefetchCollection(GC.getBuildingClassInfo(), "BuildingClasses");
	PrefetchCollection(GC.getBuildingInfo(), "Buildings");

	//GameInfo
	PrefetchCollection(GC.getEmphasisInfo(), "EmphasizeInfos");
	PrefetchCollection(GC.getEraInfo(), "Eras");
	PrefetchCollection(GC.getGameOptionInfo(), "GameOptions");
	PrefetchCollection(GC.getGameSpeedInfo(), "GameSpeeds");
	PrefetchCollection(GC.getHandicapInfo(), "HandicapInfos");
	PrefetchCollection(GC.getHurryInfo(), "HurryInfos");
	PrefetchCollection(GC.getMPOptionInfo(), "MultiplayerOptions");
	PrefetchCollection(GC.getPlayerOptionInfo(), "PlayerOptions");
	PrefetchCollection(GC.getPolicyInfo(), "Policies");
	PrefetchCollection(GC.getPolicyBranchInfo(), "PolicyBranchTypes");
	PrefetchCollection(GC.getProcessInfo(), "Processes");
	PrefetchCollection(GC.getProjectInfo(), "Projects");
	PrefetchCollection(GC.getSmallAwardInfo(), "SmallAwards");
	PrefetchCollection(GC.getSpecialistInfo(), "Specialists");
	PrefetchCollection(GC.getVictoryInfo(), "Victories");
	PrefetchCollection(GC.getVoteInfo(), "Votes");
	PrefetchCollection(GC.getVoteSourceInfo(), "VoteSources");
#if defined(MOD_BALANCE_CORE)
	PrefetchCollection(GC.getEventInfo(), "Events");
	PrefetchCollection(GC.getEventChoiceInfo(), "EventChoices");
	PrefetchCollection(GC.getCityEventInfo(), "CityEvents");
	PrefetchCollection(GC.getCityEventChoiceInfo(), "CityEventChoices");
#endif
	PrefetchCollection(GC.getUnitDomainInfo(), "Domains");

#if defined(MOD_EVENTS_DIPLO_MODIFIERS)
	PrefetchCollection(GC.getDiploModifierInfo(), "DiploModifiers");
#endif

	//Leaders
	PrefetchCollection(GC.getLeaderHeadInfo(), "Leaders");

	//Misc
	PrefetchCollection(GC.getRouteInfo(), "Routes");

	CvNotificationXMLEntries* pkNotificationEntries =  GC.GetNotificationEntries();
	if(pkNotificationEntries != NULL)
	{
		PrefetchCollection(pkNotificationEntries->GetNotificationEntries(), "Notifications");
	}

	//Technologies
	PrefetchCollection(GC.getTechInfo(), "Technologies");

	//Terrain
	PrefetchCollection(GC.getFeatureInfo(), "Features");
	PrefetchCollection(GC.getImprovementInfo(), "Improvements");
	PrefetchCollection(GC.getResourceClassInfo(), "ResourceClasses");
	PrefetchCollection(GC.getResourceInfo(), "Resources");
#if defined(MOD_API_PLOT_YIELDS)
	if (MOD_API_PLOT_YIELDS) {
		PrefetchCollection(GC.getPlotInfo(), "Plots");
	}
#endif
#if defined(MOD_API_UNIFIED_YIELDS)
	if (MOD_API_UNIFIED_YIELDS) {
		PrefetchCollection(GC.getGreatPersonInfo(), "GreatPersons");
	}
#endif
	PrefetchCollection(GC.getTerrainInfo(), "Terrains");
	PrefetchCollection(GC.getYieldInfo(), "Yields");

	//Units
	PrefetchCollection(GC.getAutomateInfo(), "Automates");
	PrefetchCollection(GC.getBuildInfo(), "Builds");
	PrefetchCollection(GC.getCommandInfo(), "Commands");
	PrefetchCollection(GC.getControlInfo(), "Controls");
	PrefetchCollection(GC.getEntityEventInfo(), "EntityEvents");
	PrefetchCollection(GC.getMissionInfo(), "Missions");
	PrefetchCollection(GC.getMultiUnitFormationInfo(), "MultiUnitFormations");
	PrefetchCollection(GC.getSpecialUnitInfo(), "SpecialUnits");
	PrefetchCollection(GC.getUnitClassInfo(), "UnitClasses");
	PrefetchCollection(GC.getPromotionInfo(), "UnitPromotions");
	PrefetchCollection(GC.getUnitInfo(), "Units");

	//Civilizations - must be after buildings and units
	PrefetchCollection(GC.getCivilizationInfo(), "Civilizations");
	PrefetchCollection(GC.getMinorCivInfo(), "MinorCivilizations");
	PrefetchCollection(GC.getTraitInfo(), "Traits");
	PrefetchCollection(GC.getReligionInfo(), "Religions");
	PrefetchCollection(GC.getBeliefInfo(), "Beliefs");
	PrefetchCollection(GC.getLeagueSpecialSessionInfo(), "LeagueSpecialSessions");
	PrefetchCollection(GC.getLeagueNameInfo(), "LeagueNames");
	PrefetchCollection(GC.getLeagueProjectInfo(), "LeagueProjects");
	PrefetchCollection(GC.getLeagueProjectRewardInfo(), "LeagueProjectRewards");
	PrefetchCollection(GC.getResolutionInfo(), "Resolutions");

#if defined(MOD_API_ACHIEVEMENTS) || defined(ACHIEVEMENT_HACKS)
	PrefetchCollection(GC.getAchievementInfo(), "Achievements");
#endif

#if defined(MOD_BALANCE_CORE)
	// Must be after buildings because this calls from Buildings
	PrefetchCollection(GC.getCorporationInfo(), "Corporations");
	PrefetchCollection(GC.getContractInfo(), "Contracts");
#endif

	//Copy flavors into string array
	{
		CvDatabaseUtility kUtility;
		CvString*& paFlavors = GC.getFlavorTypes();
		const int iNumFlavors = kUtility.MaxRows("Flavors");
		//GC.getNumFlavorTypes() = iNumFlavors;
		GC.setNumFlavorTypes(iNumFlavors);
		paFlavors = FNEW(CvString[iNumFlavors], c_eCiv5GameplayDLL, 0);

		Database::Results kResults;
		if(DB.SelectWhere(kResults, "Flavors", "ID > -1"))
		{
			while(kResults.Step())
			{
				const int iFlavor = kResults.GetInt("ID");
				CvAssert(iFlavor >= 0 && iFlavor < iNumFlavors);
				if(iFlavor >= 0 && iFlavor < iNumFlavors)
				{
					paFlavors[iFlavor] = kResults.GetText("Type");

				}
			}
		}
		else
		{
			CvAssertMsg(false, DB.ErrorMessage());
		}
	}

	ValidatePrefetchProcess();

	return true;
}
//------------------------------------------------------------------------------
bool CvDllDatabaseUtility::PerformDatabasePostProcessing()
{
	//Insert any database methods that you would like performed after the database
	//has been fully loaded.  This method will execute every single time the game
	//is run.
	//Updates performed here are done AFTER the database has been built or read
	//from cache.
	Database::Connection* db = GC.GetGameDatabase();

	//Update Defines table from references in PostDefines table
	db->BeginTransaction();
	Database::Results kPostDefines;

	//Build insertion statement
	Database::Results kInsert;
	db->Execute(kInsert, "INSERT OR REPLACE INTO Defines(Name, Value) VALUES(?, ?)");

	db->SelectAll(kPostDefines, "PostDefines");
	while(kPostDefines.Step())
	{
		const char* szName = kPostDefines.GetText("Name");
		const char* szKeyName = kPostDefines.GetText("Key");
		const char* szTableName = kPostDefines.GetText("Table");
		char szSQL[512];

		sprintf_s(szSQL, "select ROWID from %s where Type = '%s' LIMIT 1", szTableName, szKeyName);

		Database::Results kLookup;

		//Compile the command.
		if(db->Execute(kLookup, szSQL))
		{
			//Run the command.
			if(kLookup.Step())
			{
				//Perform insertion
				kInsert.Bind(1, szName);
				kInsert.Bind(2, kLookup.GetInt(0));
				kInsert.Step();
				kInsert.Reset();
			}
		}
	}

	// ** Modify ResourceUsage of Resources table **
	// Set ResourceUsage to 1 if it's referenced in Unit_ResourceQuantityRequirements
	// NOTE: This query could be simplified using the IN operator but when analyzed this
	//			statement generates faster operations.
	const char* szStrategicResource
	    = "UPDATE Resources SET ResourceUsage = 1 WHERE EXISTS (SELECT * FROM Unit_ResourceQuantityRequirements WHERE ResourceType = Type)";
	db->Execute(szStrategicResource);

	// Set ResourceUsage to 2 if the Resource has a happiness value greater than 0
	const char* szLuxoryResource
	    = "UPDATE Resources SET ResourceUsage = 2 where Happiness > 0";
	db->Execute(szLuxoryResource);

	//These are hard-coded GameDefines enum values, let's share them with the database so that they
	//get the same amount of love as the DB.
	Database::Results kInsertDefine;
	if(db->Execute(kInsertDefine, "INSERT OR REPLACE INTO Defines(Name, Value) VALUES(?, ?);"))
	{
		InsertGameDefine(kInsertDefine, "MAX_CIV_PLAYERS", MAX_CIV_PLAYERS);
		InsertGameDefine(kInsertDefine, "MAX_CIV_TEAMS", MAX_CIV_TEAMS);
		InsertGameDefine(kInsertDefine, "MAX_MAJOR_CIVS", MAX_MAJOR_CIVS);
		InsertGameDefine(kInsertDefine, "MAX_MINOR_CIVS", MAX_MINOR_CIVS);
		InsertGameDefine(kInsertDefine, "MAX_PLAYERS", MAX_PLAYERS);
		InsertGameDefine(kInsertDefine, "MAX_TEAMS", MAX_TEAMS);
		InsertGameDefine(kInsertDefine, "BARBARIAN_PLAYER", BARBARIAN_PLAYER);
		InsertGameDefine(kInsertDefine, "BARBARIAN_TEAM", BARBARIAN_TEAM);

		InsertGameDefine(kInsertDefine, "NUM_CITY_PLOTS", AVG_CITY_PLOTS);
		InsertGameDefine(kInsertDefine, "MIN_CITY_RADIUS", MIN_CITY_RADIUS);
		InsertGameDefine(kInsertDefine, "MAX_CITY_RADIUS", MAX_CITY_RADIUS);
		InsertGameDefine(kInsertDefine, "CITY_HOME_PLOT", CITY_HOME_PLOT);
		InsertGameDefine(kInsertDefine, "MAX_CITY_RADIUS", MAX_CITY_RADIUS);
		InsertGameDefine(kInsertDefine, "MAX_CITY_DIAMETER", (2*MAX_CITY_RADIUS+1));
	}

	db->EndTransaction();

	return true;
}
//------------------------------------------------------------------------------
bool CvDllDatabaseUtility::CacheGameDatabaseData()
{
	//Do not cache everything if we don't need to.
	if(m_bGameDatabaseNeedsCaching == false)
		return true;

	//The following code depends on a valid initialized database.
	bool bSuccess = true;

	//TODO: Figure out how to handle cases where Validation has failed.
	/*bSuccess &= */
	ValidateGameDatabase();
	//bSuccess &= PerformDatabasePostProcessing();

	//HACK Legacy 'FindInfoByType' support.
	//In order to support the legacy code still using the old infos system,
	//all of the id/type pairs must be added to gc.m_infosMap
	//I apologize for this horrendous code, please remove it in the near future.
	GC.infoTypeFromStringReset();
	Database::Results kTables("name");
	if(DB.SelectAt(kTables, "sqlite_master", "type", "table"))
	{
		while(kTables.Step())
		{
			Database::Results kTypes;
			if(DB.SelectAll(kTypes, kTables.GetText(0)))
			{
				bool bFirstStep = true;
				while(kTypes.Step())
				{
					if(bFirstStep)
					{
						if(!kTypes.HasColumn("ID") || !kTypes.HasColumn("Type"))
						{
							break;
						}

						bFirstStep = false;
					}

					const int rowid = kTypes.GetInt("ID");
					const char* szType = kTypes.GetText("Type");
					if(szType)
						GC.setInfoTypeFromString(szType, rowid);
				}
			}
		}
	}

	bSuccess &= LoadGlobalDefines();
	bSuccess &= PrefetchGameData();
	bSuccess &= UpdatePlayableCivilizationCounts();

	CvTypes::AcquireTypes(DB);

	bSuccess &= SetGlobalActionInfo();

	//Clear out database cache and tune for runtime use.
	DB.ClearCountCache();

	//Log Database Memory statistics
	LogMsg(DB.CalculateMemoryStats());

	CvAssertMsg(bSuccess, "Failed to load Gameplay Database Data! Not Good!");

	if(bSuccess)
		m_bGameDatabaseNeedsCaching = false;
		
#if defined(CUSTOM_MODS_H)
	// Load up the CustomModOptions configuration
	gCustomMods.preloadCache();
#endif

	return bSuccess;
}