You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
4.9 KiB
172 lines
4.9 KiB
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Contains the set of functions for manipulating entity hierarchies. |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
// UNDONE: Reconcile this with SetParent() |
|
|
|
#include "cbase.h" |
|
#include "hierarchy.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Does the linked list work of removing a child object from the hierarchy. |
|
// Input : pParent - |
|
// pChild - |
|
//----------------------------------------------------------------------------- |
|
void UnlinkChild( CBaseEntity *pParent, CBaseEntity *pChild ) |
|
{ |
|
CBaseEntity *pList; |
|
EHANDLE *pPrev; |
|
|
|
pList = pParent->m_hMoveChild; |
|
pPrev = &pParent->m_hMoveChild; |
|
while ( pList ) |
|
{ |
|
CBaseEntity *pNext = pList->m_hMovePeer; |
|
if ( pList == pChild ) |
|
{ |
|
// patch up the list |
|
pPrev->Set( pNext ); |
|
|
|
// Clear hierarchy bits for this guy |
|
pList->m_hMoveParent.Set( NULL ); |
|
pList->m_hMovePeer.Set( NULL ); |
|
pList->NetworkProp()->SetNetworkParent( CBaseHandle() ); |
|
pList->DispatchUpdateTransmitState(); |
|
pList->OnEntityEvent( ENTITY_EVENT_PARENT_CHANGED, NULL ); |
|
|
|
pParent->RecalcHasPlayerChildBit(); |
|
return; |
|
} |
|
else |
|
{ |
|
pPrev = &pList->m_hMovePeer; |
|
pList = pNext; |
|
} |
|
} |
|
|
|
// This only happens if the child wasn't found in the parent's child list |
|
Assert(0); |
|
} |
|
|
|
void LinkChild( CBaseEntity *pParent, CBaseEntity *pChild ) |
|
{ |
|
EHANDLE hParent; |
|
hParent.Set( pParent ); |
|
pChild->m_hMovePeer.Set( pParent->FirstMoveChild() ); |
|
pParent->m_hMoveChild.Set( pChild ); |
|
pChild->m_hMoveParent = hParent; |
|
pChild->NetworkProp()->SetNetworkParent( hParent ); |
|
pChild->DispatchUpdateTransmitState(); |
|
pChild->OnEntityEvent( ENTITY_EVENT_PARENT_CHANGED, NULL ); |
|
pParent->RecalcHasPlayerChildBit(); |
|
} |
|
|
|
void TransferChildren( CBaseEntity *pOldParent, CBaseEntity *pNewParent ) |
|
{ |
|
CBaseEntity *pChild = pOldParent->FirstMoveChild(); |
|
while ( pChild ) |
|
{ |
|
// NOTE: Have to do this before the unlink to ensure local coords are valid |
|
Vector vecAbsOrigin = pChild->GetAbsOrigin(); |
|
QAngle angAbsRotation = pChild->GetAbsAngles(); |
|
Vector vecAbsVelocity = pChild->GetAbsVelocity(); |
|
// QAngle vecAbsAngVelocity = pChild->GetAbsAngularVelocity(); |
|
|
|
UnlinkChild( pOldParent, pChild ); |
|
LinkChild( pNewParent, pChild ); |
|
|
|
// FIXME: This is a hack to guarantee update of the local origin, angles, etc. |
|
pChild->m_vecAbsOrigin.Init( FLT_MAX, FLT_MAX, FLT_MAX ); |
|
pChild->m_angAbsRotation.Init( FLT_MAX, FLT_MAX, FLT_MAX ); |
|
pChild->m_vecAbsVelocity.Init( FLT_MAX, FLT_MAX, FLT_MAX ); |
|
|
|
pChild->SetAbsOrigin(vecAbsOrigin); |
|
pChild->SetAbsAngles(angAbsRotation); |
|
pChild->SetAbsVelocity(vecAbsVelocity); |
|
// pChild->SetAbsAngularVelocity(vecAbsAngVelocity); |
|
|
|
pChild = pOldParent->FirstMoveChild(); |
|
} |
|
} |
|
|
|
void UnlinkFromParent( CBaseEntity *pRemove ) |
|
{ |
|
if ( pRemove->GetMoveParent() ) |
|
{ |
|
// NOTE: Have to do this before the unlink to ensure local coords are valid |
|
Vector vecAbsOrigin = pRemove->GetAbsOrigin(); |
|
QAngle angAbsRotation = pRemove->GetAbsAngles(); |
|
Vector vecAbsVelocity = pRemove->GetAbsVelocity(); |
|
// QAngle vecAbsAngVelocity = pRemove->GetAbsAngularVelocity(); |
|
|
|
UnlinkChild( pRemove->GetMoveParent(), pRemove ); |
|
|
|
pRemove->SetLocalOrigin(vecAbsOrigin); |
|
pRemove->SetLocalAngles(angAbsRotation); |
|
pRemove->SetLocalVelocity(vecAbsVelocity); |
|
// pRemove->SetLocalAngularVelocity(vecAbsAngVelocity); |
|
if ( pRemove->GetMoveType() != MOVETYPE_NONE && pRemove->GetMoveType() != MOVETYPE_VPHYSICS ) |
|
{ |
|
pRemove->UpdateWaterState(); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Clears the parent of all the children of the given object. |
|
//----------------------------------------------------------------------------- |
|
void UnlinkAllChildren( CBaseEntity *pParent ) |
|
{ |
|
CBaseEntity *pChild = pParent->FirstMoveChild(); |
|
while ( pChild ) |
|
{ |
|
CBaseEntity *pNext = pChild->NextMovePeer(); |
|
UnlinkFromParent( pChild ); |
|
pChild = pNext; |
|
} |
|
} |
|
|
|
bool EntityIsParentOf( CBaseEntity *pParent, CBaseEntity *pEntity ) |
|
{ |
|
while ( pEntity->GetMoveParent() ) |
|
{ |
|
pEntity = pEntity->GetMoveParent(); |
|
if ( pParent == pEntity ) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
static void GetAllChildren_r( CBaseEntity *pEntity, CUtlVector<CBaseEntity *> &list ) |
|
{ |
|
for ( ; pEntity != NULL; pEntity = pEntity->NextMovePeer() ) |
|
{ |
|
list.AddToTail( pEntity ); |
|
GetAllChildren_r( pEntity->FirstMoveChild(), list ); |
|
} |
|
} |
|
|
|
int GetAllChildren( CBaseEntity *pParent, CUtlVector<CBaseEntity *> &list ) |
|
{ |
|
if ( !pParent ) |
|
return 0; |
|
|
|
GetAllChildren_r( pParent->FirstMoveChild(), list ); |
|
return list.Count(); |
|
} |
|
|
|
int GetAllInHierarchy( CBaseEntity *pParent, CUtlVector<CBaseEntity *> &list ) |
|
{ |
|
if (!pParent) |
|
return 0; |
|
list.AddToTail( pParent ); |
|
return GetAllChildren( pParent, list ) + 1; |
|
}
|
|
|