Beispiel #1
0
//called to enumerate the FX that this manager contains, and for each one it will query each
//key for the objects it uses, and for each object the provided callback will be called
//and provided with the effect, the object, and the provided user data
void CClientFXMgr::EnumerateObjects(CBaseFX::TEnumerateObjectsFn pfnObjectCB, void* pUserData)
{
	//don't allow for invalid functions!
	if(!pfnObjectCB)
		return;

	//iterate through all of our effects
	LTListIter<CClientFXInstance*> itFXInstance = m_FXInstanceList.Begin();
	while(itFXInstance != m_FXInstanceList.End())
	{
		CClientFXInstance* pInst = *itFXInstance;
		itFXInstance++;

		//now iterate through each key in that effect
		LTListIter<CBaseFX*> itActiveFX = pInst->m_ActiveFXList.Begin();
		while(itActiveFX != pInst->m_ActiveFXList.End())
		{
			CBaseFX* pFX = *itActiveFX;
			itActiveFX++;

			//and enumerate the objects used by that effect
			pFX->EnumerateObjects(pfnObjectCB, pUserData);
		}
	}
}
Beispiel #2
0
bool CLIENTFX_INSTANCE::IsFinished()
{
	if (IsDone()) 
		return true;

	CLinkListNode<FX_LINK>	*pActiveNode = m_collActiveFX.GetHead();
	CBaseFX	*pFX = LTNULL;
	while (pActiveNode)
	{
		pFX = pActiveNode->m_Data.m_pFX;

		// Check for expiration
		if( pFX ) 
		{				
			//determine if this effect has expired
			bool bExpired = ((pFX->GetElapsed() >= pFX->GetEndTime()) || pFX->IsShuttingDown()) && 
							 (pFX->IsFinishedShuttingDown() || !pActiveNode->m_Data.m_pRef->m_bSmoothShutdown);
			
			if (!bExpired) 
				return false;
		}

		pActiveNode = pActiveNode->m_pNext;
	}

	return true;
}
Beispiel #3
0
CBaseFX* CClientFXMgr::CreateFX(const char *sName, FX_BASEDATA *pBaseData, CBaseFXProps* pProps)
{
	//track our performance
	CTimedSystemBlock TimingBlock(g_tsClientFXUpdateCreate);

	CBaseFX *pNewFX = NULL;

	// Locate the named FX

	const FX_REF *pFxRef = CClientFXDB::GetSingleton().FindFX(sName);
	if( pFxRef ) 
	{
		pNewFX = pFxRef->m_pfnCreate();
	}

	// If we have a new fx, go ahead and add it onto the active list

	if( pNewFX ) 
	{
		//initialize the effect
		if( !pNewFX->Init(pBaseData, pProps) )
		{
			//if this failed to initialize, then destroy the effect
			pNewFX->Term();
			CClientFXDB::GetSingleton().DeleteEffect(pNewFX);

			pNewFX = NULL;
		}
	}

	// All done....
	return pNewFX;
}
Beispiel #4
0
void CLIENTFX_INSTANCE::SetPos( const LTVector &vWorldPos, const LTVector &vCamRelPos )
{
	// Loop through all of the Muzzle flash's active FX and set the positions...

	if( m_collActiveFX.GetSize() )
	{
		uint32		dwFlags;
		CBaseFX		*pFX;
		LTVector	vPos;
		CLinkListNode<FX_LINK> *pActiveFX = m_collActiveFX.GetHead();
		
		while( pActiveFX )
		{
			pFX = pActiveFX->m_Data.m_pFX;
			if( m_bPlayerView )
			{
				g_pLTCCommon->GetObjectFlags( pFX->GetFXObject(), OFT_Flags, dwFlags );
				dwFlags & FLAG_REALLYCLOSE ? vPos = vCamRelPos : vPos = vWorldPos;
			}
			else
			{
				vPos = vWorldPos;	
			}
			
			pFX->SetPos( vPos );
									
			pActiveFX = pActiveFX->m_pNext;
		}
	}
}
Beispiel #5
0
CBaseFX* CClientFXMgr::CreateFX(const char *sName, FX_BASEDATA *pBaseData, CBaseFXProps* pProps, HOBJECT hInstParent)
{
	CBaseFX *pNewFX = NULL;

	// Locate the named FX

	FX_REF *pFxRef = CClientFXDB::GetSingleton().FindFX(sName);

	if( pFxRef ) 
	{
		pNewFX = pFxRef->m_pfnCreate();
	}

	// If we have a new fx, go ahead and add it onto the active list

	if( pNewFX ) 
	{
		// Assign a unique ID for this FX

		pBaseData->m_dwID = GetUniqueID();
		
		if( !pNewFX->Init(m_pClientDE, pBaseData, pProps) )
		{
			// See if the FX->Init() filled out data to create a new instance...
			if( pBaseData->m_sNode[0] )
			{
				CLIENTFX_CREATESTRUCT	fxCS( pBaseData->m_sNode, pBaseData->m_dwFlags, pBaseData->m_vPos, pBaseData->m_rRot );
				fxCS.m_vTargetNorm		= pBaseData->m_vTargetNorm;
				fxCS.m_hParent			= hInstParent;
				
				CreateClientFX( fxCS, LTTRUE );
			}

			pNewFX->Term();
			CClientFXDB::GetSingleton().DeleteEffect(pNewFX);

			pNewFX = NULL;
		}
	}

	// All done....
	
	return pNewFX;
}
Beispiel #6
0
//------------------------------------------------------------------
//
//   FUNCTION : HandleShutdownEffect()
//
//   PURPOSE  : Given an instance and an effect that has just finished shutting down,
//				it will take the appropriate course of action. Note that this will
//				invalidate the node that is passed into it
//
//------------------------------------------------------------------
void CClientFXMgr::HandleShutdownEffect(CLIENTFX_INSTANCE* pInst, CLinkListNode<FX_LINK>* pKeyNode)
{
	//sanity check
	assert(pInst && pKeyNode);

	CBaseFX	*pFX = pKeyNode->m_Data.m_pFX;

	//we are finished shutting down, if we aren't looping, we need to destroy
	//the effect, otherwise just disable it
	if(pInst->m_bLoop && !pInst->m_bShutdown)
	{
		pFX->SetVisible(false);
		pFX->ClearState(FS_ACTIVE | FS_SHUTTINGDOWN | FS_INITIALFRAME);
	}
	else
	{
		pInst->DeleteFX(pKeyNode);
	}
}
Beispiel #7
0
void CLIENTFX_INSTANCE::DeleteFX(CLinkListNode<FX_LINK> *pDelNode)
{
	if( !pDelNode ) 
		return;

	CBaseFX* pDelFX = pDelNode->m_Data.m_pFX;

	if(pDelFX)
	{
		// Make sure no other active FX in this instance have this pDelFX has their parent...
		CLinkListNode<FX_LINK>	*pActiveNode = m_collActiveFX.GetHead();
		while( pActiveNode )
		{
			CBaseFX *pPossibleChildFX = pActiveNode->m_Data.m_pFX;

			if( pPossibleChildFX && (pPossibleChildFX->GetParent() == pDelFX->GetFXObject()))
			{
				// NULL out the parent otherwise it will reference an object that is no longer there
				pPossibleChildFX->SetParent( LTNULL );
			}
			
			pActiveNode = pActiveNode->m_pNext;
		}

		// Give the FX a chance to clean itself up
		pDelFX->Term();
		CClientFXDB::GetSingleton().DeleteEffect(pDelFX);
	}

	//now remove this node from our list
	m_collActiveFX.Remove(pDelNode);
}
Beispiel #8
0
bool CClientFXMgr::CreateFXKey(const CLIENTFX_CREATESTRUCT &fxInit, CClientFXInstance* pInst, const FX_KEY* pKey )
{
	if( !pKey ) 
		return false;
	//
	// We need to go ahead and create this effect
	//

	FX_BASEDATA	fxData;
	fxData.m_tTransform			= fxInit.m_tTransform;
	fxData.m_bUseTargetData		= fxInit.m_bUseTargetData;
	fxData.m_hTargetObject		= fxInit.m_hTargetObject;
	fxData.m_vTargetOffset		= fxInit.m_vTargetOffset;
	fxData.m_pFxMgr				= this;
	fxData.m_hParentObject		= fxInit.m_hParentObject;
	fxData.m_hParentRigidBody	= fxInit.m_hParentRigidBody;
	fxData.m_hNodeAttach		= fxInit.m_hNode;
	fxData.m_hSocketAttach		= fxInit.m_hSocket;
	fxData.m_dwFlags			= fxInit.m_dwFlags;

	// Create the FX
	CBaseFX *pNewFX = CreateFX(pKey->m_pFxRef->m_sName, &fxData, pKey->m_pProps);
	if( pNewFX )
	{
		pNewFX->SetVisible(false);
		pNewFX->ClearState(FS_INITIALFRAME | FS_ACTIVE | FS_SHUTTINGDOWN | FS_SUSPENDED);

		// Add it onto the list for link referencing
		pInst->m_ActiveFXList.AddTail(&pNewFX->m_FXListLink);
	}
	else
	{
		return false;
	}

	return true;
}
Beispiel #9
0
bool CClientFXMgr::UpdateAllActiveFX()
{
	//track our performance
	CTimedSystemBlock TimingBlock(g_tsClientFXUpdate);

	//Update our frame time, before any early outs so there aren't giant pops when the early
	//out fails
	float fFrameTime = m_Timer.GetTimerElapsedS();

	//add in all the effects from our next update list and clear that out
	LTListIter<CClientFXInstance*> itFXInstance = m_NextUpdateFXList.Begin();
	while(itFXInstance != m_NextUpdateFXList.End())
	{
		CClientFXInstance* pFXInstance = *itFXInstance;
		itFXInstance++;

		pFXInstance->m_FXListLink.Remove();
		m_FXInstanceList.AddTail(&pFXInstance->m_FXListLink);
	}

	HCONSOLEVAR hVar = m_pClientDE->GetConsoleVariable("UpdateClientFX");
	if (hVar)
	{
		float fVal = m_pClientDE->GetConsoleVariableFloat(hVar);

		if (!fVal) 
			return true;
	}

	//see if we should even update
	if( g_pGameClientShell->IsServerPaused( ))
	{
		//no time has elapsed, don't bother updating
		return true;
	}

	//
	// Update the group Instances
	//
	itFXInstance = m_FXInstanceList.Begin();
	while(itFXInstance != m_FXInstanceList.End())
	{
		CClientFXInstance* pInst = *itFXInstance;
		itFXInstance++;

		//see if this instance is suspended, if so, just call the suspended update
		if(pInst->UpdateSuspended())
		{
			//just run through all effects and give them a suspended updata
			LTListIter<CBaseFX*> itActiveFX = pInst->m_ActiveFXList.Begin();
			while(itActiveFX != pInst->m_ActiveFXList.End())
			{
				CBaseFX* pFX = *itActiveFX;
				itActiveFX++;
				pFX->SuspendedUpdate(fFrameTime);
			}

			//don't bother with any interval updating
			continue;
		}


		//determine the start and end of our update interval, relative to the instance
		//time frame
		float fStartInterval	= pInst->m_tmElapsed;
		float fEndInterval		= fStartInterval + fFrameTime;

		//we now need to iteratively break this interval down into a series of intervals that
		//do not extend past the end of the effect
		bool bLastSegment = false;
		while(!bLastSegment)
		{
			//pick whichever is closest, the end of the interval, or the duration of the
			//effect
			float fEndSegment = pInst->m_fDuration;

			if(fEndInterval < pInst->m_fDuration)
			{
				bLastSegment = true;
				fEndSegment = fEndInterval;
			}
			
			//alright, we now have an interval, update all the effects that lie within it
			pInst->UpdateInterval(fStartInterval, fEndSegment);

			//now move on to the next interval if necessary
			if(!bLastSegment)
			{
				fStartInterval	= 0.0f;
				fEndInterval	-= pInst->m_fDuration;
			}
		}

		//all done, save our time
		pInst->m_tmElapsed = fEndInterval;

		//see if we are done with this effect
		if(pInst->m_ActiveFXList.IsEmpty())
		{				
			// Destroy the instance
			DeleteClientFXInstance( pInst );
		}
	}

	// Success !!
	return true;
}	
Beispiel #10
0
//------------------------------------------------------------------
//
//   FUNCTION : UpdateInstanceInterval()
//
//   PURPOSE  : Given an instance and a time interval, this will appropriately update
//				all effects contained within that interval
//
//------------------------------------------------------------------
void CClientFXMgr::UpdateInstanceInterval(CLIENTFX_INSTANCE* pInst, float fStartInterval, float fEndInterval)
{
	//here are the possible scenarios:
	// Inactive
	// Inactive -> Active -> Shutting down
	// Inactive -> Active -> Shutting down -> Inactive
	// Inactive -> Active
	// Shutting Down
	// Shutting Down -> Inactive
	// Shutting Down -> Active -> Shutting Down
	// Shutting Down -> Active -> Shutting Down -> Inactive
	// Shutting Down -> Active
	// Active

	//A note about intervals: The interval used is inclusive of both start and ends. This does
	//mean that a boundary such as a key beginning or end can be hit twice, but because of the
	//way the state flow works, this will not cause any issues, since when it is inactive
	//it will look for active and vice a versa. Therefore since the beginning and end cannot
	//lie on the same position this should not introduce any issues, but ensures that the
	//full track length is handled when updating

	//alright, run through all active effects and determine what to do
	CLinkListNode<FX_LINK>				*pActiveNode;
	CLinkListNode<FX_LINK>				*pNextActiveNode;

	//determine if this is a looping instance
	bool bLoopInstance = pInst->m_bLoop;

	pActiveNode = pInst->m_collActiveFX.GetHead();
	while( pActiveNode )
	{
		//cache the next node in case we delete this key
		pNextActiveNode = pActiveNode->m_pNext;

		//alright, first off look at the state of the key and see what to do
		CBaseFX	*pFX		= pActiveNode->m_Data.m_pFX;
		const FX_KEY* pKey	= pActiveNode->m_Data.m_pRef;

		//this is our time slice beginning
		float fCurrStart = fStartInterval;

		//skip dead space on inactive effects
		if(!pFX->IsActive())
		{
			//sanity check, the shutting down flag should never be set without active
			assert(!pFX->IsShuttingDown());

			//This check is to verify that we aren't shutting down the instance and have inactive effects.
			//If we are shutting down, inactive effects are immediately pruned, and then active effects
			//should be removed as they are completed
			assert(!pInst->m_bShutdown);

			//figure out the start time of this effect
			float fKeyStart = pKey->m_tmStart;

			//this effect is not active. See if it should be (loop keys always should be)
			if(pKey->m_bContinualLoop || ((fKeyStart >= fCurrStart) && (fKeyStart <= fEndInterval)))
			{
				//our effect has just become active, we need to reset its elapsed time to 0,
				//and switch it over to an initial frame
				pFX->SetElapsed(0.0f);
				pFX->SetState(FS_ACTIVE | FS_INITIALFRAME);
				pFX->ClearState(FS_SHUTTINGDOWN);
				pFX->SetVisible(true);

				//handle applying a fake effect offset
				ApplyEffectStartingOffset(pFX, pKey);

				//move our timeslice forward to the beginning of the key
				fCurrStart = fKeyStart;
			}
		}

		if(pFX->IsActive())
		{
			//we are an active effect, which means we are either in the time block or are
			//shutting down. 

			//see if we are currently shutting down, and if we are going to transition into
			//becoming active
			if(pFX->IsShuttingDown())
			{
				float fKeyStart = pKey->m_tmStart;

				//however, we can only bring it into the active state from here if the instance
				//will allow us
				bool bCanActivate = pInst->m_bLoop && !pInst->m_bShutdown;

				//this effect is not active. See if it should be
				if(bCanActivate && (fKeyStart >= fCurrStart) && (fKeyStart <= fEndInterval))
				{
					//it will become active in this range, so move up to there and change state
					pFX->Update(fKeyStart - fCurrStart);

					pFX->SetElapsed(0.0f);
					pFX->SetState(FS_INITIALFRAME | FS_ACTIVE);
					pFX->ClearState(FS_SHUTTINGDOWN);

					//handle applying a fake effect offset
					ApplyEffectStartingOffset(pFX, pKey);

					//move our time position up to the key start
					fCurrStart = fKeyStart;
				}
			}

			//alright, we are now in a chunk of time where either the block is active
			//or shutting down. If it is active, we need to update until the end of the slice
			//or the end of the effect
			if(!pFX->IsShuttingDown())
			{
				//we aren't shutting down, so we can update like normal
				float fTimeBlockEnd = fEndInterval;
				bool bCompleteKey	= ((pKey->m_tmEnd <= fTimeBlockEnd) && (pKey->m_tmEnd >= fCurrStart));

				//see if we hit the end of the key
				if(bCompleteKey)
				{
					fTimeBlockEnd = pKey->m_tmEnd;
				}

				//update based upon the interval length
				pFX->Update(fTimeBlockEnd - fCurrStart);

				//the initial update state should be cleared now
				pFX->ClearState(FS_INITIALFRAME);

				//see if we completed the key
				if(bCompleteKey)
				{
					//we did, so now switch to a shutting down state if it isn't continually looping,
					//otherwise we need to reset the elapsed time to 0
					if(pKey->m_bContinualLoop && bLoopInstance)
					{
						//we have looped our key, so reset the elapsed amount. However, if we are a
						//continually looping effect that started with an offset, we don't want
						//to lose that offset and should threfore just wrap based upon the lifespan
						if(pKey->m_fMaxStartOffset >= 0.001f)
						{
							pFX->SetElapsed((float)fmod(pFX->GetElapsed(), pFX->GetLifespan()));
						}
						else
						{
							//no starting offset, so just to make sure that everything syncs
							//up correctly and no error gets introduced, reset it to 0
							pFX->SetElapsed(0.0f);
						}
					}
					else
					{
						//we're past our key, so start shutting down
						pFX->SetState(FS_SHUTTINGDOWN);
					}
				}

				//update our time start
				fCurrStart = fTimeBlockEnd;
			}

			//alright, now handle shutting down, in which case we just want to update however
			//much time we have left in this interval, and see if the effect is completed
			if(pFX->IsShuttingDown())
			{
				//allow it to update
				pFX->Update(fEndInterval - fCurrStart);

				//can this effect do a smooth shutdown?
				bool bSmoothShutdown = pKey->m_bSmoothShutdown && pInst->m_bSmoothShutdown;

				//see if this effect is done shutting down
				if(pFX->IsFinishedShuttingDown() || !bSmoothShutdown)
				{
					//notify of an effect that has finished shutting down
					HandleShutdownEffect(pInst, pActiveNode);

					//move onto the next node and keep processing
					pActiveNode = pNextActiveNode;
					continue;
				}
			}
		}
		
		//and onto the next node
		pActiveNode = pNextActiveNode;
	}
}
Beispiel #11
0
bool CClientFXMgr::CreateFXKey( CLIENTFX_INSTANCE* pInst, FX_KEY* pKey )
{
	if( !pInst || !pKey ) 
		return false;
	//
	// We need to go ahead and create this effect
	//

	assert(m_hCamera);

	FX_BASEDATA	fxData;
	fxData.m_vPos				= pInst->m_vPos;
	fxData.m_rRot				= pInst->m_rRot;
	fxData.m_dwID				= pInst->m_dwID;
	fxData.m_hTarget			= pInst->m_hTarget;
	fxData.m_dwObjectFlags		= pInst->m_dwObjectFlags;
	fxData.m_dwObjectFlags2		= pInst->m_dwObjectFlags2;
	fxData.m_bUseTargetData		= pInst->m_bUseTargetData;
	fxData.m_vTargetPos			= pInst->m_vTargetPos;
	fxData.m_vTargetNorm		= pInst->m_vTargetNorm;
	fxData.m_hCamera			= m_hCamera;

	// Save the parent
	fxData.m_hParent = pInst->m_hParent;

	// Is this FX supposed to be motion linked to another FX?
	if (pKey->m_bLinked)
	{
		CLinkListNode<FX_LINK>	*pNode = pInst->m_collActiveFX.GetHead();

		while (pNode)
		{
			if (pNode->m_Data.m_dwID == pKey->m_dwLinkedID)
			{
				// This is the one !!!
				if (pInst->ExistFX(pNode->m_Data.m_pFX))
				{
					CBaseFX	 *pMotionLinkFX	= pNode->m_Data.m_pFX;
					fxData.m_hParent = pMotionLinkFX->GetFXObject();
				}

				// done
				break;
			}
			
			pNode = pNode->m_pNext;
		}
	}

	// Create the FX
	CBaseFX *pNewFX = CreateFX(pKey->m_pFxRef->m_sName, &fxData, pKey->m_pProps, pInst->m_hParent);

	if( pNewFX )
	{
		pNewFX->SetVisible(false);
		pNewFX->ClearState(FS_INITIALFRAME | FS_ACTIVE | FS_SHUTTINGDOWN | FS_SUSPENDED);

		// Add it onto the list for link referencing

		FX_LINK	fxLink;
		fxLink.m_dwID = pKey->m_dwID;
		fxLink.m_pFX  = pNewFX;
		fxLink.m_pRef = pKey;

		pInst->m_collActiveFX.AddHead(fxLink);
	}
	else
	{
		return false;
	}

	return true;
}
Beispiel #12
0
void CClientFXMgr::ShutdownClientFX(CLIENTFX_INSTANCE *pFxGroup)
{	
	CLinkListNode<CLIENTFX_INSTANCE *> *pActiveNode = m_collActiveGroupFX.GetHead();

	//setup the callback in case any create effects as they are destroyed
	SetupCreateEffectCallback();

	while (pActiveNode)
	{	
		CLIENTFX_INSTANCE* pInst = pActiveNode->m_Data;

		if (pInst == pFxGroup)
		{		
			// Shut it down !!
			pInst->m_bShutdown = true;

			HOBJECT hReplaceParent = NULL;
			
			//see if this effect performs a smooth shutdown, if so, we need to create a dummy
			//object to place everything under a dummy object
			if (pInst->m_bSmoothShutdown)
			{
				LTVector	vPos;
				LTRotation	rRot;

				if (pFxGroup->m_hParent)
				{
					m_pClientDE->GetObjectPos(pFxGroup->m_hParent, &vPos);
					m_pClientDE->GetObjectRotation(pFxGroup->m_hParent, &rRot);
				}
				else
				{
					vPos = pFxGroup->m_vPos;
					rRot = pFxGroup->m_rRot;
				}

				// Create a temporary parent object....

				ObjectCreateStruct ocs;
				INIT_OBJECTCREATESTRUCT(ocs);

				ocs.m_ObjectType	= OT_NORMAL;
				ocs.m_Pos			= vPos;
				ocs.m_Rotation		= rRot;		 
				ocs.m_Flags			= 0;

				hReplaceParent = m_pClientDE->CreateObject(&ocs);
				pFxGroup->m_hAlternateParent = hReplaceParent;
				pFxGroup->m_hParent = hReplaceParent;				
			}


			if (!hReplaceParent)
			{
				//we couldn't create or didn't need a replacement object, so just remove all fx
				pInst->m_hAlternateParent	= NULL;
				pInst->m_hParent			= NULL;

				pInst->RemoveAllEffects();
			}
			else
			{
				// We have a parent to set, but in addition we need to notify all effects that
				//we are shutting down, and remove any effects that don't need a smooth shutdown (this
				//way it can be polled instantly after to determine if it is done)

				CLinkListNode<FX_LINK> *pActiveFxNode = pInst->m_collActiveFX.GetHead();
				CLinkListNode<FX_LINK> *pNextActiveFxNode = NULL;

				while( pActiveFxNode )
				{
					//cache the next in case this node is deleted
					pNextActiveFxNode = pActiveFxNode->m_pNext;

					CBaseFX *pFX = pActiveFxNode->m_Data.m_pFX;

					//we want to remove any inactive nodes
					if(!pFX->IsActive())
					{
						pInst->DeleteFX(pActiveFxNode);
					}
					else
					{
						const FX_KEY* pKey = pActiveFxNode->m_Data.m_pRef;

						//reassign the parent of this object
						pFX->SetParent(hReplaceParent);

						//we have an active effect, set it to shutting down
						pFX->SetState(FS_SHUTTINGDOWN);

						//now that it is shutting down, see if it is complete
						if(pFX->IsFinishedShuttingDown() || !pInst->m_bSmoothShutdown || !pKey->m_bSmoothShutdown)
						{
							//we can just remove the effect
							pInst->DeleteFX(pActiveFxNode);
						}
					}
					
					pActiveFxNode = pNextActiveFxNode;
				}
			}

			break;
		}

		pActiveNode = pActiveNode->m_pNext;
	}
}