CModInfoManager::CModInfoManager()
{
	m_bRunningMod = false;
	m_modCheckSum = 0;

	const ICmdLineArg *pModArg = gEnv->pSystem->GetICmdLine()->FindArg(eCLAT_Pre,"MOD");
	if (pModArg != NULL  && (*pModArg->GetValue() != 0) && (gEnv->pSystem->IsMODValid(pModArg->GetValue())))
	{
		m_bRunningMod = true;
	}

	Refresh();

	if (m_bRunningMod)
	{
		const ModInfo *pModInfo = GetActiveMod();
		if (pModInfo)
		{
			CryStackStringT<char, _MAX_PATH*2> modPath;
			modPath.Format("Mods\\%s", pModInfo->keyName.c_str());

			uint32 result = GetDirectoryHash(modPath.c_str());

			m_modCheckSum = result;
		}
	}
}
uint32 CModInfoManager::GetDirectoryHash( const char *pPath )
{
	if (!gEnv || !gEnv->pCryPak)
	{
		assert(0);
		return 0;
	}

	ICryPak* pCryPak = gEnv->pCryPak;

	// Recursively find all files and hash them
	uint32 result = 0;

	CryStackStringT<char, _MAX_PATH*2> searchPath;
	searchPath.Format("%s\\*", pPath);

	_finddata_t fd;
	intptr_t h = pCryPak->FindFirst(searchPath.c_str(), &fd, 0, true);
	if (h != -1)
	{
		CryStackStringT<char, _MAX_PATH*2> path;
		do 
		{
			if ((fd.attrib & _A_SUBDIR) == 0)
			{
				// Add to checksum
				uint32 fileHash = 0;

				CryStackStringT<char, _MAX_PATH*2> modPath;
				modPath.Format("%s\\%s", pPath, fd.name);

				if (GetFileHash(modPath.c_str(), fileHash))
				{
					result += fileHash;
				}

				continue;
			}

			if (strcmp(fd.name, ".") == 0 || strcmp(fd.name, "..") == 0)
				continue;

			path = pPath;
			path += "\\";
			path += fd.name;

			result += GetDirectoryHash(path.c_str());
		}
		while(0 == pCryPak->FindNext(h, &fd));

		pCryPak->FindClose (h);
	}

	return result;
}
Ejemplo n.º 3
0
void CAntiCheatManager::InitSession()
{
	OpenLogFile();

	const char * pSessionName = NULL;
	char sessionID[CRYSESSIONID_STRINGLEN];
	sessionID[0] = 0;
	
	if(CGameLobby * pGameLobby = g_pGame->GetGameLobby())
	{
		pSessionName = pGameLobby->GetSessionName();
		if (pSessionName && pSessionName[0]==0)
			pSessionName=NULL;
		pGameLobby->GetSessionIDAsString(sessionID, CRYSESSIONID_STRINGLEN);
	} 

	//This can't be logged via the cleaner XML method as we need to open the tag now, and close it later on, without leaving everything in memory the whole time
	CryStackStringT<char, 512> sessionStartTag;

	const char * pTelemetrySessionName = NULL;

	if(ITelemetryCollector * pTelemetryCollector = g_pGame->GetITelemetryCollector())
	{
		pTelemetrySessionName = pTelemetryCollector->GetSessionId().c_str();
	}

	sessionStartTag.Format("<Session name=\"%s\" telemetry_name=\"%s\" id=\"%s\">\n", pSessionName ? pSessionName : "UNKNOWN", pTelemetrySessionName ? pTelemetrySessionName : "UNKNOWN", sessionID[0] ? sessionID : "UNKNOWN");

	if (m_pLogFile)
	{
		gEnv->pCryPak->FWrite(sessionStartTag.c_str(), 1, sessionStartTag.length(), m_pLogFile);
	}

	if(CGameRules * pGameRules = g_pGame->GetGameRules())
	{
		XmlNodeRef sessionGameInfo = GetISystem()->CreateXmlNode("GameInfo");

		ILevel * pLevel = g_pGame->GetIGameFramework()->GetILevelSystem()->GetCurrentLevel();

		sessionGameInfo->setAttr("map",				pLevel->GetLevelInfo()->GetName());
		sessionGameInfo->setAttr("gamemode",	CGameRules::S_GetGameModeNamesArray()[pGameRules->GetGameMode()]);

		CheatLogInternalXml(sessionGameInfo);
	}
}
Ejemplo n.º 4
0
XmlNodeRef CAntiCheatManager::CreateIncidentXML(uint16 channelId, TCheatType type, const float *params, int numParams, const char * pDescription)
{
	XmlNodeRef incidentXml = GetISystem()->CreateXmlNode("Incident");

	CAntiCheatManager::Xml_SetDisplayName(incidentXml, channelId);
	CAntiCheatManager::Xml_SetGuid(incidentXml, channelId);
	CAntiCheatManager::Xml_SetCheatType(incidentXml, type);

	if(pDescription && pDescription[0])
		incidentXml->setAttr("description", pDescription);

	for(int i = 0; i < numParams; i++)
	{
		CryStackStringT<char, 16> paramNodeName;
		paramNodeName.FormatFast("%s-%d", PARAM_NODE, i+1);
		XmlNodeRef child = incidentXml->newChild(paramNodeName.c_str());
		child->setAttr(PARAM_VALUE, params[i]);
	}

	return incidentXml;
}
Ejemplo n.º 5
0
//---------------------------------------------------------------------
void StrToWstr(const char* str, wstring& dstr)
{
	CryStackStringT<wchar_t, 64> tmp;
	tmp.resize(strlen(str));
	tmp.clear();

	while (const wchar_t c=(wchar_t)(*str++))
	{
		tmp.append(1, c);
	}

	dstr.assign(tmp.data(), tmp.length());
}
Ejemplo n.º 6
0
//------------------------------------------------------------------------
// returns true if entity is killed, false if it is not
bool CGameRulesMPDamageHandling::SvOnHit( const HitInfo &hitInfo )
{
	const HitTypeInfo * pHitTypeInfo = m_pGameRules->GetHitTypeInfo(hitInfo.type);

#if !defined(_RELEASE)
	if(!pHitTypeInfo)
		CryFatalError("By ::SvOnHit() all hit info should have a hit type that is valid and registered in the GameRules. This isn't true of type %d!", hitInfo.type);
#endif

	SDamageHandling damageHandling(&hitInfo, 1.0f);

	float damage = hitInfo.damage;

	IActorSystem* pActorSystem = g_pGame->GetIGameFramework()->GetIActorSystem();
	CActor *pTargetActor = static_cast<CActor*>(pActorSystem->GetActor(hitInfo.targetId));
	CActor *pShooterActor = static_cast<CActor*>(pActorSystem->GetActor(hitInfo.shooterId));
	CPlayer* pShooterPlayer = (pShooterActor && pShooterActor->IsPlayer()) ? static_cast<CPlayer*>(pShooterActor) : NULL ;

	bool isPlayer = pTargetActor != NULL && pTargetActor->IsPlayer();

#ifndef _RELEASE
	//--- Fix to allow the damage handling to work for these entity classes in the same way as for Players
	static IEntityClass* sDamEntClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass("DamageTestEnt");
	isPlayer |= pTargetActor != NULL && pTargetActor->GetEntity()->GetClass() == sDamEntClass;
#endif

	CPlayer* pPlayer = isPlayer ? static_cast<CPlayer*>(pTargetActor) : NULL;
	const bool isMelee = ((pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::IsMeleeAttack) != 0);
	const bool checkHeadshots = ((pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::IgnoreHeadshots) == 0);

	bool bIsHeadShot = false;
	if(pPlayer && hitInfo.partId >= 0 && checkHeadshots)
	{
		bIsHeadShot = pPlayer->IsHeadShot(hitInfo);

		if (!bIsHeadShot && g_pGameCVars->g_mpHeadshotsOnly)
		{
			damage = 0.f;
		}
	}

	//If the player has died more than kTimeToAllowKillsAfterDeath seconds ago, we disallow any damage they apply, unless the hit type is flagged as allowing it.
	static const float kTimeToAllowKillsAfterDeath = 0.05f;
	if(pTargetActor && pShooterPlayer && !hitInfo.hitViaProxy
		&& ((pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::AllowPostDeathDamage) == 0) && pShooterActor->IsDead()
		&& (gEnv->pTimer->GetFrameStartTime().GetSeconds() - pShooterPlayer->GetDeathTime()) > kTimeToAllowKillsAfterDeath)
	{
		damage = 0.0f;
	}

	IGameRulesStateModule *stateModule = m_pGameRules->GetStateModule();
	IGameRulesRoundsModule* pRoundsModule = m_pGameRules->GetRoundsModule();

	if ( (stateModule != NULL && (stateModule->GetGameState() == IGameRulesStateModule::EGRS_PostGame)) || 
		   (pRoundsModule!= NULL && !pRoundsModule->IsInProgress() ))
	{
		// No damage allowed once the game has ended, except in cases where it would cause graphical glitches
		if (hitInfo.type != CGameRules::EHitType::PunishFall)
		{
			damage = 0.0f;
		}
	}

	IEntity *pTarget = gEnv->pEntitySystem->GetEntity(hitInfo.targetId);

#if defined(SERVER_CHECKS)

	if(damage != 0.0f)
	{
		int nNewCheckCounter = m_checkCounter + 1;
		
		if (CItem *pItem = static_cast<CItem *>(g_pGame->GetIGameFramework()->GetIItemSystem()->GetItem(hitInfo.weaponId)))
		{
			if(CWeapon * pWeapon = static_cast<CWeapon*>(pItem->GetIWeapon()))
			{
				int nFireModeFromShotId = GetFireModeFromShotId(hitInfo.shotId);

				static const int kCheckFreq = 7;

				if(pShooterActor &&	nNewCheckCounter == kCheckFreq)
				{
					float fDamageAtXMeters = 0.0f;

					float fDistance2D, fDistanceMax, fNetLagSeconds;
					CServerCheatMonitor::GetHitValidationInfo(*pShooterActor, hitInfo, fDistance2D, fDistanceMax, fNetLagSeconds);

					bool bDoDamageValidation = false;

					if(isMelee)
					{
						if(CMelee * pMelee = pWeapon->GetMelee())
						{
							//This check can't be used for everything because the default firemode returns '0.f' for range and only CMelee extends it
							//	the horizontal player speed is x 2.0f as the players could have potentially immediately turned and run away from each other
							float fMeleeRangeError = fDistance2D - (pMelee->GetRange() + (CServerCheatMonitor::kMaxHorizontalPlayerSpeed * fNetLagSeconds * 2.0f));
							if(fMeleeRangeError > 0.1f)
							{
								g_pGame->GetAntiCheatManager()->FlagActivity(eCT_MeleeRange, pShooterActor->GetChannelId(), fMeleeRangeError);
							}

							fDamageAtXMeters = pMelee->GetDamageAmountAtXMeters(fDistance2D);

							bDoDamageValidation = true;
						}
					}
					else
					{
						//////////////////////////////////////////////////////////////////////
						// Verify that the hit is from a valid shot

						DoShotValidation(hitInfo, pHitTypeInfo, pShooterActor);

						//////////////////////////////////////////////////////////////////////


						CFireMode * pFireMode = static_cast<CFireMode*>(pWeapon->GetFireMode(nFireModeFromShotId));

						if(pFireMode)
						{
							const SFireModeParams * pParams = pFireMode->GetShared();

							char projectileClassName[128];
							g_pGame->GetIGameFramework()->GetNetworkSafeClassName(projectileClassName, sizeof(projectileClassName), hitInfo.projectileClassId);
							IEntityClass * pProjectileClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(projectileClassName);

							if((pProjectileClass && (pProjectileClass == pParams->fireparams.ammo_type_class ||	pProjectileClass == pParams->plantparams.ammo_type_class)))
							{
								float fBulletSpeed = 100.f;
								const SAmmoParams * pAmmoParams = g_pGame->GetWeaponSystem()->GetAmmoParams(pFireMode->GetAmmoType());
								if(pAmmoParams)
								{
									fBulletSpeed = pAmmoParams->speed;
								}

								//Might have been closer when the shot was fired
								const float fMaxTimeSinceShot	= ((fDistanceMax / fBulletSpeed) * 2.0f) + fNetLagSeconds; //Should be less than this. Laaaaarge fudge factor
								float fDistance_Conservative	= fDistance2D - (fMaxTimeSinceShot * CServerCheatMonitor::kMaxHorizontalPlayerSpeed);

								fDamageAtXMeters = pFireMode->GetDamageAmountAtXMeters(fDistance_Conservative); 
							}
						}
						else if(pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::ValidationRequired)
						{
							CryStackStringT<char, 256> invalidFireModeMessage;
							invalidFireModeMessage.Format("Invalid fire mode, weapon: '%s', firemode: %d", pWeapon->GetEntity()->GetName(), nFireModeFromShotId);
							g_pGame->GetAntiCheatManager()->FlagActivity(eCT_ValidHitInfo, pShooterActor->GetChannelId(), invalidFireModeMessage.c_str());
						}
					}

					float fDamageFromWeapon = hitInfo.damage;			

					if(fDamageFromWeapon > fDamageAtXMeters && fDamageAtXMeters > 0.0f)
					{
						//Log the ratio of actual damage to expected damage, e.g. 1.2 x expected
						CryStackStringT<char, 256> excessiveDamageMessage;
						excessiveDamageMessage.Format("Weapon '%s', firemode %d", pWeapon->GetEntity()->GetName(), nFireModeFromShotId);
						g_pGame->GetAntiCheatManager()->FlagActivity(eCT_WeaponDamage, pShooterActor->GetChannelId(), fDamageFromWeapon / fDamageAtXMeters, excessiveDamageMessage.c_str());
					}


					if(pTargetActor)
					{
						CServerCheatMonitor::ValidateTargetActorPositionAgainstHit(*pTargetActor, hitInfo, fNetLagSeconds);
					}
					
					nNewCheckCounter = 0;
				}
				else
				{
					nNewCheckCounter = kCheckFreq - 1;
				}
			}
		}
		m_checkCounter = nNewCheckCounter;
	}

	// Update the shotcounter for tracking headshots and traversal times
	if(pShooterPlayer && (pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::ValidationRequired))
	{
		char netName[128];
		g_pGame->GetIGameFramework()->GetNetworkSafeClassName(netName, sizeof(netName), hitInfo.projectileClassId);
		IEntityClass * pProjectileClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(netName);
		if (pProjectileClass)
		{
			CShotCounter* pShotCounter = pShooterPlayer->GetShotCounter();
			pShotCounter->RecordHit(hitInfo, bIsHeadShot);
		}
	}
	
#endif // SERVER_CHECKS

	IEntityClass* pTargetClass = pTarget ? pTarget->GetClass() : NULL;

	// Check for friendly fire
	if( bool bCheckFriendlyFire = ((hitInfo.targetId!=hitInfo.shooterId) && (hitInfo.type!=CGameRules::EHitType::EventDamage)) )
	{
		if(IVehicle* pTargetVehicle = g_pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle(hitInfo.targetId))
		{
			if(IActor* pDriverTargetVehicle = pTargetVehicle->GetDriver())
			{
				// Vehicle driver shot own vehicle (same as shooting yourself), don't do friendly fire.
				bCheckFriendlyFire = pDriverTargetVehicle->GetEntityId()!=hitInfo.shooterId;
			}
		}
		if(bCheckFriendlyFire)
		{
			if (m_pGameRules->GetTeamCount() > 1)
			{
				int shooterTeamId = m_pGameRules->GetTeam(hitInfo.shooterId);
				int targetTeamId = m_pGameRules->GetTeam(hitInfo.targetId);

				if (shooterTeamId && (shooterTeamId == targetTeamId))
				{
					damage = GetFriendlyFireDamage(damage, hitInfo, pTargetActor);
				}
			}
		}
	}

	if (damage <= 0.f)
	{
		// If the hit isn't doing anything bail, this means any hit that gets past here has damage associated with it and thus wants to
		// display a hit indicator
		return false;
	}

	if (pPlayer)
	{
		if(hitInfo.partId >= 0 && !isMelee)
		{
			damageHandling.damageMultiplier *= pPlayer->GetBodyDamageMultiplier(hitInfo);
		}

		if (isMelee)
		{
			damageHandling.damageMultiplier *= g_pGameCVars->pl_melee.damage_multiplier_mp;
		}
	}

	damage *= damageHandling.damageMultiplier;

	HitInfo hitInfoWithDamage = hitInfo;
	hitInfoWithDamage.damage = damage;

	if(pPlayer)
	{
		SActorStats* pStats = pPlayer->GetActorStats();
		float actorHealth = pPlayer->GetHealth();

		if(pStats)
		{
#ifndef _RELEASE
			if (g_pGameCVars->g_LogDamage)
			{
				char weaponClassName[64], projectileClassName[64];

				CryLog ("[DAMAGE] %s '%s' took %.3f '%s' damage (%.3f x %.3f) weapon=%s projectile=%s",
						pPlayer->GetEntity()->GetClass()->GetName(), pPlayer->GetEntity()->GetName(),
						damage, m_pGameRules->GetHitType(hitInfo.type),
						hitInfo.damage, damageHandling.damageMultiplier,
						g_pGame->GetIGameFramework()->GetNetworkSafeClassName(weaponClassName, sizeof(weaponClassName), hitInfo.weaponClassId) ? weaponClassName : "none",
						g_pGame->GetIGameFramework()->GetNetworkSafeClassName(projectileClassName, sizeof(projectileClassName), hitInfo.projectileClassId) ? projectileClassName : "none");
			}
#endif

			if(pStats->bStealthKilling && actorHealth <= damage)
			{
				if(pPlayer->GetStealthKill().GetTargetId() != hitInfoWithDamage.shooterId)
				{
					pPlayer->StoreDelayedKillingHitInfo(hitInfoWithDamage);
				}
				
				hitInfoWithDamage.damage = 0;
			}
			else if (pStats->bStealthKilled && hitInfoWithDamage.type != CGameRules::EHitType::StealthKill)
			{
				hitInfoWithDamage.damage = 0;
			}
		}
	}
		
	bool bKilled = SvOnHitScaled(hitInfoWithDamage);

	return bKilled;
}
void CModInfoManager::Refresh()
{
#ifndef _WIN32
	assert(0 && "Calling Windows-specific code");
	return;
#endif

	if (!gEnv || !gEnv->pCryPak)
	{
		assert(0);
		return;
	}

	ICryPak* pCryPak = gEnv->pCryPak;

	m_mods.clear();

	// look for MODs
	{
		_finddata_t fd;
		intptr_t h = pCryPak->FindFirst ("Mods\\*", &fd, 0, true);
		if (h != -1)
		{
			CryStackStringT<char, _MAX_PATH*2> path;
			do 
			{
				if ((fd.attrib & _A_SUBDIR) == 0)
					continue;
				if (strcmp(fd.name, ".") == 0 || strcmp(fd.name, "..") == 0)
					continue;

				path = "Mods\\";
				path += fd.name;

				ModInfo mod;

				if (ModInfo_LoadFromFile(&mod, (path + "\\info.xml").c_str()) && mod.modType != eMIT_SPLEVEL)
				{
					mod.keyName = fd.name;
					if (mod.displayName.empty())
						mod.displayName = mod.keyName;
					path.replace('\\', '/');
					path.insert(0, '/');
					mod.mainImage = (path + "/modpreview.jpg").c_str();
					mod.logoImage = (path + "/modteamlogo.jpg").c_str();
					m_mods.push_back(mod);
				}
			}
			while(0 == pCryPak->FindNext(h, &fd));

			pCryPak->FindClose (h);
		}
	}

	// look for SP-levels
	{
		CryStackStringT<char, _MAX_PATH*2> path;
		path += PathUtil::GetGameFolder();
		path += "\\Levels\\*";

		_finddata_t fd;
		intptr_t h = pCryPak->FindFirst (path.c_str(), &fd, 0, true);
		if (h != -1)
		{
			do 
			{
				if ((fd.attrib & _A_SUBDIR) == 0)
					continue;
				if (strcmp(fd.name, ".") == 0 || strcmp(fd.name, "..") == 0)
					continue;

				path = PathUtil::GetGameFolder();
				path += "\\Levels\\";
				path += fd.name;

				ModInfo mod;

				if (ModInfo_LoadFromFile(&mod, (path + "\\info.xml").c_str()))
				{
					mod.modType = eMIT_SPLEVEL;
					mod.keyName = fd.name;
					path = "/Levels/";
					path += fd.name;
					mod.mainImage = (path + "/modpreview.jpg").c_str();
					mod.logoImage = (path + "/modteamlogo.jpg").c_str();
					if (mod.displayName.empty())
						mod.displayName = mod.keyName;
					m_mods.push_back(mod);
				}
			}
			while(0 == pCryPak->FindNext(h, &fd));

			pCryPak->FindClose (h);
		}
	}

	// look for MOD levels
	{
		m_modLevels.clear();

		CryStackStringT<char, _MAX_PATH*2> path;

		ILevelSystem* pLevelSystem = g_pGame->GetIGameFramework()->GetILevelSystem();
		size_t levelCount = pLevelSystem->GetLevelCount();
		for (size_t i = 0; i < levelCount; ++i)
		{
			ILevelInfo* pInfo = pLevelSystem->GetLevelInfo(i);
			if (!pInfo)
				continue;
			if (pInfo->GetIsModLevel() && (!pInfo->HasGameRules() || pInfo->SupportsGameType("SinglePlayer")))
			{
				ModInfo mod;
				const char* szLevelInfoDisplayName = pInfo->GetDisplayName();
				if (strcmp(szLevelInfoDisplayName, "") != 0)
				{
					mod.displayName = szLevelInfoDisplayName;
				}
				else // Fallback to directory name
				{
					mod.displayName = pInfo->GetName();
				}

				// load info.xml as well
				path = pInfo->GetPath();
				path.replace('/', '\\');
				if (ModInfo_LoadFromFile(&mod, (path + "\\info.xml").c_str()))
				{
					path.replace('\\', '/');
					path.insert(0, '/');
					mod.mainImage = (path + "/modpreview.jpg").c_str();
					mod.logoImage = (path + "/modteamlogo.jpg").c_str();
				}

				mod.keyName = pInfo->GetName();
				mod.modType = eMIT_SPLEVEL;

				m_modLevels.push_back(mod);
			}
		}
	}
}
Ejemplo n.º 8
0
bool CActionScope::QueueFragment(FragmentID fragID, const SFragTagState &fragTagState, uint32 optionIdx, float startTime, uint32 userToken, bool isRootScope, bool isHigherPriority, bool principleContext)
{
	if (m_scopeContext.pDatabase == NULL)
	{
		return false;
	}

	SBlendQuery query;
	FillBlendQuery(query, fragID, fragTagState, isHigherPriority, NULL);
	query.SetFlag(SBlendQuery::toInstalled, principleContext);

	SFragmentData  fragData;
	IAnimationSet* pAnimSet = m_scopeContext.pCharInst ? m_scopeContext.pCharInst->GetIAnimationSet() : NULL;
	m_sequenceFlags      = m_scopeContext.pDatabase->Query(fragData, query, optionIdx, pAnimSet, &m_lastFragSelection);
	m_lastQueueTagState  = query.tagStateTo;
	m_lastNormalisedTime = m_normalisedTime = 0.0f;
	m_isOneShot          = fragData.isOneShot && ((fragID == FRAGMENT_ID_INVALID) || ((m_context.controllerDef.GetFragmentDef(fragID).flags & SFragmentDef::PERSISTENT) == 0));
	m_blendOutDuration   = fragData.blendOutDuration;
	m_fragmentInstalled  = principleContext;

	const bool fragmentInstalled = HasFragment();

#if MANNEQUIN_DEBUGGING_ENABLED
	CryStackStringT<char,128> sTagList = "No Match";
	CryStackStringT<char,128> sFragTagList;

	if (!fragmentInstalled && (m_layer == 0) && (m_numLayers > 0))
	{
		const char* fragmentName = fragID != FRAGMENT_ID_INVALID ? m_context.controllerDef.m_fragmentIDs.GetTagName(fragID) : "None";
		m_context.controllerDef.m_tags.FlagsToTagList(fragTagState.globalTags, sTagList);
		const CTagDefinition* pFragTagDef = (fragID != FRAGMENT_ID_INVALID) ? m_context.controllerDef.GetFragmentTagDef(fragID) : NULL;
		if (pFragTagDef)
		{
			pFragTagDef->FlagsToTagList(fragTagState.fragmentTags, sFragTagList);
		}
		MannLog(GetActionController(), "Warning - Missing root level fragment %s(%s)", fragmentName, sTagList.c_str());
	}
	if (m_actionController.DebugFragments(principleContext) && fragmentInstalled)
	{
		if (HasFragment())
		{
			m_context.controllerDef.m_tags.FlagsToTagList(m_lastFragSelection.tagState.globalTags, sTagList);
			const CTagDefinition* pFragTagDef = m_context.controllerDef.GetFragmentTagDef(fragID);
			if (pFragTagDef)
			{
				pFragTagDef->FlagsToTagList(m_lastFragSelection.tagState.fragmentTags, sFragTagList);
			}
		}
		const char* fragmentName     = fragID != FRAGMENT_ID_INVALID ? m_context.controllerDef.m_fragmentIDs.GetTagName(fragID) : "None";
		const char* prevFragmentName = query.fragmentFrom != FRAGMENT_ID_INVALID ? m_context.controllerDef.m_fragmentIDs.GetTagName(query.fragmentFrom) : "None";

		MannLog(GetActionController(), "Frag %s (%s,%s) queued on %s for action %s", fragmentName, sTagList.c_str(), sFragTagList.c_str(), m_name.c_str(), m_pAction ? m_pAction->GetName() : "None");

		CryStackStringT<char,128> sTagStateFrom;
		CryStackStringT<char,128> sTagStateTo;

		SBlendQueryResult queryRes1, queryRes2;
		m_scopeContext.pDatabase->FindBestBlends(query, queryRes1, queryRes2);

		if (queryRes1.pFragmentBlend)
		{
			MannLog(GetActionController(), "Transition from (%s -> %s) %s", (queryRes1.fragmentFrom != FRAGMENT_ID_INVALID) ? prevFragmentName : "Any", (queryRes1.fragmentTo != FRAGMENT_ID_INVALID) ? fragmentName : "Any", queryRes1.pFragmentBlend->IsExitTransition() ? "Exit" : "");

			m_actionController.GetContext().controllerDef.m_tags.FlagsToTagList(queryRes1.tagStateFrom.globalTags, sTagStateFrom);
			m_actionController.GetContext().controllerDef.m_tags.FlagsToTagList(queryRes1.tagStateTo.globalTags, sTagStateTo);

			MannLog(GetActionController(), "Transition tags (%s -> %s)", sTagStateFrom.c_str(), sTagStateTo.c_str());
		}
		if (queryRes2.pFragmentBlend)
		{
			MannLog(GetActionController(), "And Transition from (%s -> %s) %s", (queryRes2.fragmentFrom != FRAGMENT_ID_INVALID) ? prevFragmentName : "Any", (queryRes2.fragmentTo != FRAGMENT_ID_INVALID) ? fragmentName : "Any", queryRes2.pFragmentBlend->IsExitTransition() ? "Exit" : "");

			m_actionController.GetContext().controllerDef.m_tags.FlagsToTagList(queryRes2.tagStateFrom.globalTags, sTagStateFrom);
			m_actionController.GetContext().controllerDef.m_tags.FlagsToTagList(queryRes2.tagStateTo.globalTags, sTagStateTo);

			MannLog(GetActionController(), "Transition tags (%s -> %s)", sTagStateFrom.c_str(), sTagStateTo.c_str());
		}
	}
#endif //MANNEQUIN_DEBUGGING_ENABLED

	m_fragmentDuration = m_transitionOutroDuration = m_transitionDuration = 0.0f;
	for (uint32 i = 0; i < SFragmentData::PART_TOTAL; i++)
	{
		m_partTypes[i] = fragData.transitionType[i];
		switch (fragData.transitionType[i])
		{
		case eCT_Normal:
			m_fragmentDuration += fragData.duration[i];
			break;
		case eCT_Transition:
			m_transitionDuration += fragData.duration[i];
			break;
		case eCT_TransitionOutro:
			m_transitionOutroDuration += fragData.duration[i];
			break;
		}
	}
	if (!isRootScope)
	{
		if (m_sequenceFlags & (eSF_Transition | eSF_TransitionOutro))
		{
			startTime = 0.0f;
		}
		else
		{
			startTime = max(startTime - (m_transitionOutroDuration + m_transitionDuration), 0.0f);
		}
	}
	m_lastFragmentID = fragID;
	m_fragmentTime   = -startTime;

	const uint32 numAnimLayers  = fragData.animLayers.size();
	const uint32 numScopeLayers = m_numLayers;
	const uint32 numLayers      = min(numAnimLayers, numScopeLayers);

	CRY_ASSERT_MESSAGE(numLayers <= m_numLayers, "Invalid layer count");

	m_userToken = userToken;

	uint32 nLayer = 0;
	for (nLayer = 0; nLayer < numLayers; nLayer++)
	{
		const bool  hasClips  = fragData.animLayers[nLayer].size() > 0;
		SSequencer &sequencer = m_layerSequencers[nLayer];

		sequencer.pos           = 0;
		sequencer.referenceTime = -1.0f;

		if (hasClips)
		{
			sequencer.sequence    = fragData.animLayers[nLayer];
			sequencer.blend       = sequencer.sequence[0].blend;
			sequencer.installTime = startTime + sequencer.blend.exitTime;
			sequencer.flags       = eSF_Queued;
		}
		else
		{
			sequencer.sequence.resize(0);

			sequencer.blend       = SAnimBlend();
			sequencer.installTime = startTime;
			sequencer.flags       = eSF_Queued | eSF_BlendingOut;
		}
	}

	for (; nLayer < numScopeLayers; nLayer++)
	{
		//--- Layers that are not touched by the new fragment blend out using default blends
		SSequencer &sequencer = m_layerSequencers[nLayer];
		sequencer.sequence.resize(0);
		sequencer.pos = 0;

		sequencer.blend       = SAnimBlend();
		sequencer.installTime = startTime;
		sequencer.flags       = eSF_Queued | eSF_BlendingOut;
	}

	const size_t numProcSequencers    = fragData.procLayers.size();
	const size_t totNumProcSequencers = max(numProcSequencers, m_procSequencers.size());
	m_procSequencers.resize(totNumProcSequencers);
	for (nLayer = 0; nLayer < numProcSequencers; nLayer++)
	{
		const bool      hasClips      = fragData.procLayers[nLayer].size() > 0;
		SProcSequencer &sequencerPush = m_procSequencers[nLayer];
		sequencerPush.pos = 0;

		if (hasClips)
		{
			sequencerPush.sequence = fragData.procLayers[nLayer];

			const float layerBlendTime = sequencerPush.sequence[0].blend.exitTime;
			sequencerPush.installTime = startTime;
			sequencerPush.blend       = sequencerPush.sequence[0].blend;
			sequencerPush.flags       = eSF_Queued;
			if (layerBlendTime > 0.0f)
			{
				sequencerPush.blend  = SAnimBlend();
				sequencerPush.flags |= eSF_BlendingOut;
			}
		}
		else
		{
			sequencerPush.sequence.resize(0);

			sequencerPush.blend       = SAnimBlend();
			sequencerPush.installTime = startTime;
			sequencerPush.flags       = eSF_Queued | eSF_BlendingOut;
		}
	}
	for (; nLayer < totNumProcSequencers; nLayer++)
	{
		SProcSequencer &sequencerPush = m_procSequencers[nLayer];

		sequencerPush.sequence.resize(0);
		sequencerPush.pos = 0;

		sequencerPush.blend       = SAnimBlend();
		sequencerPush.installTime = startTime;
		sequencerPush.flags       = eSF_Queued | eSF_BlendingOut;
	}

	return fragmentInstalled;
}