source-engine/game/server/hierarchy.cpp

170 lines
4.8 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright 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);
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;
}