Added support for ragdoll prop gibs + related ragdoll LRU forced fade from Alien Swarm SDK

This commit is contained in:
Blixibon 2021-11-27 15:47:13 -06:00
parent 4bc56b214b
commit cea38f03ec
5 changed files with 263 additions and 7 deletions

View File

@ -259,6 +259,9 @@ LINK_ENTITY_TO_CLASS( client_ragdoll, C_ClientRagdoll );
BEGIN_DATADESC( C_ClientRagdoll ) BEGIN_DATADESC( C_ClientRagdoll )
DEFINE_FIELD( m_bFadeOut, FIELD_BOOLEAN ), DEFINE_FIELD( m_bFadeOut, FIELD_BOOLEAN ),
DEFINE_FIELD( m_bImportant, FIELD_BOOLEAN ), DEFINE_FIELD( m_bImportant, FIELD_BOOLEAN ),
#ifdef MAPBASE
DEFINE_FIELD( m_flForcedRetireTime, FIELD_FLOAT ),
#endif
DEFINE_FIELD( m_iCurrentFriction, FIELD_INTEGER ), DEFINE_FIELD( m_iCurrentFriction, FIELD_INTEGER ),
DEFINE_FIELD( m_iMinFriction, FIELD_INTEGER ), DEFINE_FIELD( m_iMinFriction, FIELD_INTEGER ),
DEFINE_FIELD( m_iMaxFriction, FIELD_INTEGER ), DEFINE_FIELD( m_iMaxFriction, FIELD_INTEGER ),
@ -377,6 +380,9 @@ C_ClientRagdoll::C_ClientRagdoll( bool bRestoring )
m_bFadeOut = false; m_bFadeOut = false;
m_bFadingOut = false; m_bFadingOut = false;
m_bImportant = false; m_bImportant = false;
#ifdef MAPBASE
m_flForcedRetireTime = 0.0f;
#endif
m_bNoModelParticles = false; m_bNoModelParticles = false;
SetClassname("client_ragdoll"); SetClassname("client_ragdoll");
@ -457,7 +463,11 @@ void C_ClientRagdoll::OnRestore( void )
if ( m_bFadeOut == true ) if ( m_bFadeOut == true )
{ {
#ifdef MAPBASE
s_RagdollLRU.MoveToTopOfLRU( this, m_bImportant, m_flForcedRetireTime );
#else
s_RagdollLRU.MoveToTopOfLRU( this, m_bImportant ); s_RagdollLRU.MoveToTopOfLRU( this, m_bImportant );
#endif
} }
NoteRagdollCreationTick( this ); NoteRagdollCreationTick( this );

View File

@ -737,6 +737,10 @@ public:
bool m_bFadeOut; bool m_bFadeOut;
bool m_bImportant; bool m_bImportant;
#ifdef MAPBASE
// Required to save/restore Alien Swarm SDK ragdoll LRU forced fade
float m_flForcedRetireTime;
#endif
float m_flEffectTime; float m_flEffectTime;
private: private:

View File

@ -704,9 +704,157 @@ void C_PhysPropClientside::ParseAllEntities(const char *pMapData)
} }
} }
#ifdef MAPBASE
CBaseAnimating *BreakModelCreate_Ragdoll( CBaseEntity *pOwnerEnt, breakmodel_t *pModel, const Vector &position, const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity )
{
C_BaseAnimating *pOwner = dynamic_cast<C_BaseAnimating *>( pOwnerEnt );
if ( !pOwner )
return NULL;
C_ClientRagdoll *pRagdoll = new C_ClientRagdoll( false );
if ( pRagdoll == NULL )
return NULL;
const char *pModelName = pModel->modelName;
if ( pRagdoll->InitializeAsClientEntity( pModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false )
{
pRagdoll->Release();
return NULL;
}
pRagdoll->SetAbsOrigin( position );
pRagdoll->SetAbsAngles( angles );
matrix3x4_t boneDelta0[MAXSTUDIOBONES];
matrix3x4_t boneDelta1[MAXSTUDIOBONES];
matrix3x4_t currentBones[MAXSTUDIOBONES];
const float boneDt = 0.1f;
pRagdoll->SetParent( pOwner );
pRagdoll->ForceSetupBonesAtTime( boneDelta0, gpGlobals->curtime - boneDt );
pRagdoll->ForceSetupBonesAtTime( boneDelta1, gpGlobals->curtime );
pRagdoll->ForceSetupBonesAtTime( currentBones, gpGlobals->curtime );
pRagdoll->SetParent( NULL );
// We need to take these from the entity
//pRagdoll->SetAbsOrigin( position );
//pRagdoll->SetAbsAngles( angles );
pRagdoll->IgniteRagdoll( pOwner );
pRagdoll->TransferDissolveFrom( pOwner );
pRagdoll->InitModelEffects();
if ( pOwner->IsEffectActive( EF_NOSHADOW ) )
{
pRagdoll->AddEffects( EF_NOSHADOW );
}
pRagdoll->m_nRenderFX = kRenderFxRagdoll;
pRagdoll->SetRenderMode( pOwner->GetRenderMode() );
pRagdoll->SetRenderColor( pOwner->GetRenderColor().r, pOwner->GetRenderColor().g, pOwner->GetRenderColor().b, pOwner->GetRenderColor().a );
//pRagdoll->SetGlobalFadeScale( pOwner->GetGlobalFadeScale() );
pRagdoll->SetSkin( pOwner->GetSkin() );
//pRagdoll->m_vecForce = pOwner->m_vecForce;
//pRagdoll->m_nForceBone = 0; //pOwner->m_nForceBone;
pRagdoll->SetNextClientThink( CLIENT_THINK_ALWAYS );
pRagdoll->SetModelName( AllocPooledString( pModelName ) );
pRagdoll->ResetSequence( 0 );
pRagdoll->SetModelScale( pOwner->GetModelScale() );
pRagdoll->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
//pRagdoll->m_builtRagdoll = true;
CStudioHdr *hdr = pRagdoll->GetModelPtr();
if ( !hdr )
{
pRagdoll->Release();
Warning( "Couldn't create ragdoll gib for %s (no model pointer)\n", pModel->modelName );
return NULL;
}
pRagdoll->m_pRagdoll = CreateRagdoll(
pRagdoll,
hdr,
vec3_origin,
0,
boneDelta0,
boneDelta1,
currentBones,
boneDt );
if ( !pRagdoll->m_pRagdoll )
{
pRagdoll->Release();
Warning( "Couldn't create ragdoll gib for %s\n", pModel->modelName );
return NULL;
}
IPhysicsObject *pPhysicsObject = pRagdoll->VPhysicsGetObject();
if ( pPhysicsObject )
{
// randomize velocity by 5%
float rndf = RandomFloat( -0.025, 0.025 );
Vector rndVel = velocity + rndf*velocity;
pPhysicsObject->AddVelocity( &rndVel, &angVelocity );
}
pRagdoll->ApplyLocalAngularVelocityImpulse( angVelocity );
if ( pRagdoll->m_pRagdoll )
{
pRagdoll->m_bImportant = false;
pRagdoll->m_flForcedRetireTime = pModel->fadeTime > 0.0f ? gpGlobals->curtime + pModel->fadeTime : 0.0f;
s_RagdollLRU.MoveToTopOfLRU( pRagdoll, pRagdoll->m_bImportant, pRagdoll->m_flForcedRetireTime );
pRagdoll->m_bFadeOut = true;
}
// Cause the entity to recompute its shadow type and make a
// version which only updates when physics state changes
// NOTE: We have to do this after m_pRagdoll is assigned above
// because that's what ShadowCastType uses to figure out which type of shadow to use.
pRagdoll->DestroyShadow();
pRagdoll->CreateShadow();
pRagdoll->SetAbsOrigin( position );
pRagdoll->SetAbsAngles( angles );
pRagdoll->SetPlaybackRate( 0 );
pRagdoll->SetCycle( 0 );
// put into ACT_DIERAGDOLL if it exists, otherwise use sequence 0
int nSequence = pRagdoll->SelectWeightedSequence( ACT_DIERAGDOLL );
if ( nSequence < 0 )
{
pRagdoll->ResetSequence( 0 );
}
else
{
pRagdoll->ResetSequence( nSequence );
}
pRagdoll->UpdatePartitionListEntry();
pRagdoll->MarkRenderHandleDirty();
NoteRagdollCreationTick( pRagdoll );
//pRagdoll->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt );
return pRagdoll;
}
#endif
CBaseEntity *BreakModelCreateSingle( CBaseEntity *pOwner, breakmodel_t *pModel, const Vector &position, CBaseEntity *BreakModelCreateSingle( CBaseEntity *pOwner, breakmodel_t *pModel, const Vector &position,
const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity, int nSkin, const breakablepropparams_t &params ) const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity, int nSkin, const breakablepropparams_t &params )
{ {
#ifdef MAPBASE
if ( pModel->isRagdoll )
{
CBaseEntity *pEntity = BreakModelCreate_Ragdoll( pOwner, pModel, position, angles, velocity, angVelocity );
return pEntity;
}
#endif
C_PhysPropClientside *pEntity = C_PhysPropClientside::CreateNew(); C_PhysPropClientside *pEntity = C_PhysPropClientside::CreateNew();
if ( !pEntity ) if ( !pEntity )
@ -778,10 +926,12 @@ CBaseEntity *BreakModelCreateSingle( CBaseEntity *pOwner, breakmodel_t *pModel,
pEntity->SetFadeMinMax( pModel->fadeMinDist, pModel->fadeMaxDist ); pEntity->SetFadeMinMax( pModel->fadeMinDist, pModel->fadeMaxDist );
} }
#ifndef MAPBASE
if ( pModel->isRagdoll ) if ( pModel->isRagdoll )
{ {
DevMsg( "BreakModelCreateSingle: clientside doesn't support ragdoll breakmodels.\n" ); DevMsg( "BreakModelCreateSingle: clientside doesn't support ragdoll breakmodels.\n" );
} }
#endif
IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject(); IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject();

View File

@ -830,6 +830,33 @@ void CRagdollLRURetirement::Update( float frametime ) // EPISODIC VERSION
m_iRagdollCount = 0; m_iRagdollCount = 0;
m_iSimulatedRagdollCount = 0; m_iSimulatedRagdollCount = 0;
#ifdef MAPBASE // From Alien Swarm SDK
// remove ragdolls with a forced retire time
for ( i = m_LRU.Head(); i < m_LRU.InvalidIndex(); i = next )
{
next = m_LRU.Next(i);
CBaseAnimating *pRagdoll = m_LRU[i].Get();
//Just ignore it until we're done burning/dissolving.
if ( pRagdoll && pRagdoll->GetEffectEntity() )
continue;
// ignore if it's not time to force retire this ragdoll
if ( m_LRU[i].GetForcedRetireTime() == 0.0f || gpGlobals->curtime < m_LRU[i].GetForcedRetireTime() )
continue;
//Msg(" Removing ragdoll %s due to forced retire time of %f (now = %f)\n", pRagdoll->GetModelName(), m_LRU[i].GetForcedRetireTime(), gpGlobals->curtime );
#ifdef CLIENT_DLL
pRagdoll->SUB_Remove();
#else
pRagdoll->SUB_StartFadeOut( 0 );
#endif
m_LRU.Remove(i);
}
#endif
// First, find ragdolls that are good candidates for deletion because they are not // First, find ragdolls that are good candidates for deletion because they are not
// visible at all, or are in a culled visibility box // visible at all, or are in a culled visibility box
for ( i = m_LRU.Head(); i < m_LRU.InvalidIndex(); i = next ) for ( i = m_LRU.Head(); i < m_LRU.InvalidIndex(); i = next )
@ -847,12 +874,12 @@ void CRagdollLRURetirement::Update( float frametime ) // EPISODIC VERSION
if ( m_LRU.Count() > iMaxRagdollCount ) if ( m_LRU.Count() > iMaxRagdollCount )
{ {
//Found one, we're done. //Found one, we're done.
if ( ShouldRemoveThisRagdoll( m_LRU[i] ) == true ) if ( ShouldRemoveThisRagdoll( pRagdoll ) == true )
{ {
#ifdef CLIENT_DLL #ifdef CLIENT_DLL
m_LRU[ i ]->SUB_Remove(); pRagdoll->SUB_Remove();
#else #else
m_LRU[ i ]->SUB_StartFadeOut( 0 ); pRagdoll->SUB_StartFadeOut( 0 );
#endif #endif
m_LRU.Remove(i); m_LRU.Remove(i);
@ -933,10 +960,11 @@ void CRagdollLRURetirement::Update( float frametime ) // EPISODIC VERSION
} }
} }
CBaseAnimating *pRemoveRagdoll = m_LRU[ furthestOne ].Get();
#ifdef CLIENT_DLL #ifdef CLIENT_DLL
m_LRU[ furthestOne ]->SUB_Remove(); pRemoveRagdoll->SUB_Remove();
#else #else
m_LRU[ furthestOne ]->SUB_StartFadeOut( 0 ); pRemoveRagdoll->SUB_StartFadeOut( 0 );
#endif #endif
} }
@ -957,9 +985,9 @@ void CRagdollLRURetirement::Update( float frametime ) // EPISODIC VERSION
continue; continue;
#ifdef CLIENT_DLL #ifdef CLIENT_DLL
m_LRU[ i ]->SUB_Remove(); pRagdoll->SUB_Remove();
#else #else
m_LRU[ i ]->SUB_StartFadeOut( 0 ); pRagdoll->SUB_StartFadeOut( 0 );
#endif #endif
m_LRU.Remove(i); m_LRU.Remove(i);
} }
@ -989,6 +1017,33 @@ void CRagdollLRURetirement::Update( float frametime ) // Non-episodic version
m_iRagdollCount = 0; m_iRagdollCount = 0;
m_iSimulatedRagdollCount = 0; m_iSimulatedRagdollCount = 0;
#ifdef MAPBASE // From Alien Swarm SDK
// remove ragdolls with a forced retire time
for ( i = m_LRU.Head(); i < m_LRU.InvalidIndex(); i = next )
{
next = m_LRU.Next(i);
CBaseAnimating *pRagdoll = m_LRU[i].Get();
//Just ignore it until we're done burning/dissolving.
if ( pRagdoll && pRagdoll->GetEffectEntity() )
continue;
// ignore if it's not time to force retire this ragdoll
if ( m_LRU[i].GetForcedRetireTime() == 0.0f || gpGlobals->curtime < m_LRU[i].GetForcedRetireTime() )
continue;
//Msg(" Removing ragdoll %s due to forced retire time of %f (now = %f)\n", pRagdoll->GetModelName(), m_LRU[i].GetForcedRetireTime(), gpGlobals->curtime );
#ifdef CLIENT_DLL
pRagdoll->SUB_Remove();
#else
pRagdoll->SUB_StartFadeOut( 0 );
#endif
m_LRU.Remove(i);
}
#endif
for ( i = m_LRU.Head(); i < m_LRU.InvalidIndex(); i = next ) for ( i = m_LRU.Head(); i < m_LRU.InvalidIndex(); i = next )
{ {
next = m_LRU.Next(i); next = m_LRU.Next(i);
@ -1074,11 +1129,19 @@ ConVar g_ragdoll_important_maxcount( "g_ragdoll_important_maxcount", "2", FCVAR_
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Move it to the top of the LRU // Move it to the top of the LRU
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#ifdef MAPBASE // From Alien Swarm SDK
void CRagdollLRURetirement::MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant, float flForcedRetireTime )
#else
void CRagdollLRURetirement::MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant ) void CRagdollLRURetirement::MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant )
#endif
{ {
if ( bImportant ) if ( bImportant )
{ {
#ifdef MAPBASE // From Alien Swarm SDK
m_LRUImportantRagdolls.AddToTail( CRagdollEntry( pRagdoll, flForcedRetireTime ) );
#else
m_LRUImportantRagdolls.AddToTail( pRagdoll ); m_LRUImportantRagdolls.AddToTail( pRagdoll );
#endif
if ( m_LRUImportantRagdolls.Count() > g_ragdoll_important_maxcount.GetInt() ) if ( m_LRUImportantRagdolls.Count() > g_ragdoll_important_maxcount.GetInt() )
{ {
@ -1108,7 +1171,11 @@ void CRagdollLRURetirement::MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImpo
} }
} }
#ifdef MAPBASE // From Alien Swarm SDK
m_LRU.AddToTail( CRagdollEntry( pRagdoll, flForcedRetireTime ) );
#else
m_LRU.AddToTail( pRagdoll ); m_LRU.AddToTail( pRagdoll );
#endif
} }

View File

@ -83,6 +83,22 @@ struct ragdollparams_t
bool fixedConstraints; bool fixedConstraints;
}; };
#ifdef MAPBASE // From Alien Swarm SDK
class CRagdollEntry
{
public:
CRagdollEntry( CBaseAnimating *pRagdoll, float flForcedRetireTime ) : m_hRagdoll( pRagdoll ), m_flForcedRetireTime( flForcedRetireTime )
{
}
CBaseAnimating* Get() { return m_hRagdoll.Get(); }
float GetForcedRetireTime() { return m_flForcedRetireTime; }
private:
CHandle<CBaseAnimating> m_hRagdoll;
float m_flForcedRetireTime;
};
#endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// This hooks the main game systems callbacks to allow the AI system to manage memory // This hooks the main game systems callbacks to allow the AI system to manage memory
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -98,7 +114,11 @@ public:
virtual void FrameUpdatePostEntityThink( void ); virtual void FrameUpdatePostEntityThink( void );
// Move it to the top of the LRU // Move it to the top of the LRU
#ifdef MAPBASE // From Alien Swarm SDK
void MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant = false, float flForcedRetireTime = 0.0f );
#else
void MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant = false ); void MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant = false );
#endif
void SetMaxRagdollCount( int iMaxCount ){ m_iMaxRagdolls = iMaxCount; } void SetMaxRagdollCount( int iMaxCount ){ m_iMaxRagdolls = iMaxCount; }
virtual void LevelInitPreEntity( void ); virtual void LevelInitPreEntity( void );
@ -106,8 +126,13 @@ public:
private: private:
typedef CHandle<CBaseAnimating> CRagdollHandle; typedef CHandle<CBaseAnimating> CRagdollHandle;
#ifdef MAPBASE
CUtlLinkedList< CRagdollEntry > m_LRU;
CUtlLinkedList< CRagdollEntry > m_LRUImportantRagdolls;
#else
CUtlLinkedList< CRagdollHandle > m_LRU; CUtlLinkedList< CRagdollHandle > m_LRU;
CUtlLinkedList< CRagdollHandle > m_LRUImportantRagdolls; CUtlLinkedList< CRagdollHandle > m_LRUImportantRagdolls;
#endif
int m_iMaxRagdolls; int m_iMaxRagdolls;
int m_iSimulatedRagdollCount; int m_iSimulatedRagdollCount;