Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion game/client/c_baseanimating.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,12 @@ C_BaseAnimating::~C_BaseAnimating()
m_pAttachedTo->RemoveBoneAttachment( this );
m_pAttachedTo = NULL;
}

if ( m_pScaledCollidable )
{
UTIL_RemoveScaledPhysCollide( m_pScaledCollidable );
m_pScaledCollidable = NULL;
}
}

bool C_BaseAnimating::UsesPowerOfTwoFrameBufferTexture( void )
Expand Down Expand Up @@ -5196,9 +5202,18 @@ void C_BaseAnimating::Simulate()
}
}


bool C_BaseAnimating::TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
{
if ( GetModelScale() != 1.0f )
{
if ( m_pScaledCollidable != NULL )
{
physcollision->TraceBox( ray, m_pScaledCollidable, GetAbsOrigin(), GetAbsAngles(), &tr );

return tr.DidHit();
}
}

if ( ray.m_IsRay && IsSolidFlagSet( FSOLID_CUSTOMRAYTEST ))
{
if (!TestHitboxes( ray, fContentsMask, tr ))
Expand Down Expand Up @@ -6745,3 +6760,22 @@ void C_BaseAnimating::MoveBoneAttachments( C_BaseAnimating* attachTarget )
}
}
}

//-----------------------------------------------------------------------------
// Purpose: Update Collisions. (Same way it's done serverside. We only update it when Activate is called)
//-----------------------------------------------------------------------------
void C_BaseAnimating::Activate()
{
if ( GetModelScale() != 1.0f )
{
if ( m_pScaledCollidable )
{
UTIL_RemoveScaledPhysCollide( m_pScaledCollidable );
m_pScaledCollidable = NULL;
}

m_pScaledCollidable = UTIL_GetScaledPhysCollide( GetModelIndex(), GetModelScale() );
}

BaseClass::Activate();
}
4 changes: 4 additions & 0 deletions game/client/c_baseanimating.h
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback

virtual bool IsViewModel() const;
void UpdateOnRemove( void ) override;
virtual void Activate( void );

protected:
// View models scale their attachment positions to account for FOV. To get the unmodified
Expand Down Expand Up @@ -641,6 +642,9 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback
mutable MDLHandle_t m_hStudioHdr;
CThreadFastMutex m_StudioHdrInitLock;
bool m_bHasAttachedParticles;

private:
CPhysCollide *m_pScaledCollidable;
};

enum
Expand Down
3 changes: 3 additions & 0 deletions game/client/c_baseentity.h
Original file line number Diff line number Diff line change
Expand Up @@ -1711,6 +1711,9 @@ class C_BaseEntity : public IClientEntity

private:
bool m_bOldShouldDraw;

public:
virtual void OnModelChange( int oldModelIndex, int newModelIndex ) {};
};

EXTERN_RECV_TABLE(DT_BaseEntity);
Expand Down
128 changes: 128 additions & 0 deletions game/client/cdll_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
#include "view.h"
#include "ixboxsystem.h"
#include "inputsystem/iinputsystem.h"
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <vprof.h>

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
Expand Down Expand Up @@ -1289,3 +1293,127 @@ bool UTIL_HasLoadedAnyMap()

return g_pFullFileSystem->FileExists( szFilename, "MOD" );
}

struct CPhysEntry
{
int references = 1;
int modelIndex = 0;
float scale = 1.0f;
};

std::unordered_map<CPhysCollide*, CPhysEntry> g_pScaledReferences;
std::unordered_map<int, std::unordered_map<float, CPhysCollide*>*> g_pScaledCollidables;
CPhysCollide *UTIL_GetScaledPhysCollide( int modelIndex, float scale ) // Based off UTIL_CreateScaledPhysObject
{
VPROF( "UTIL_GetScaledPhysCollide", VPROF_BUDGETGROUP_PHYSICS );

if (scale == 1.0f)
return NULL;

std::unordered_map<float, CPhysCollide*>* scaledCollidables = nullptr;
auto iModel = g_pScaledCollidables.find( modelIndex );
if ( iModel != g_pScaledCollidables.end() )
{
std::unordered_map<float, CPhysCollide*>* collidables = iModel->second;
auto iCollidable = collidables->find( scale );
if ( iCollidable != collidables->end() )
{
auto it = g_pScaledReferences.find( iCollidable->second );
if ( it != g_pScaledReferences.end() )
{
++it->second.references;
} else {
DevWarning( "UTIL_GetScaledPhysCollide: Failed to find reference counter!\n" );
}

return iCollidable->second;
} else {
scaledCollidables = collidables;
}
} else {
scaledCollidables = new std::unordered_map<float, CPhysCollide*>;
g_pScaledCollidables[modelIndex] = scaledCollidables;
}

ICollisionQuery *pQuery = physcollision->CreateQueryModel( modelinfo->GetVCollide( modelIndex )->solids[0] );
if ( pQuery == NULL )
{
Warning( "UTIL_GetScaledPhysCollide: Failed to created scaled CPhysCollide for model %s!\n", modelinfo->GetModelName( modelinfo->GetModel( modelIndex ) ) );
return NULL;
}

const int nNumConvex = pQuery->ConvexCount();
CPhysPolysoup *pPolySoups = physcollision->PolysoupCreate();

for ( int i = 0; i < nNumConvex; ++i )
{
int nNumTris = pQuery->TriangleCount( i );
int nNumVerts = nNumTris * 3;

Vector *pVerts = (Vector *) stackalloc( sizeof(Vector) * nNumVerts );
for ( int j = 0; j < nNumTris; ++j )
{
int p = j*3;
pQuery->GetTriangleVerts( i, j, pVerts+p );
*(pVerts+p) *= scale;
*(pVerts+p+1) *= scale;
*(pVerts+p+2) *= scale;
}

for ( int j = 0; j < nNumVerts; j += 3 )
{
physcollision->PolysoupAddTriangle( pPolySoups, pVerts[j], pVerts[j + 1], pVerts[j + 2], 0 );
}
}

physcollision->DestroyQueryModel( pQuery );

CPhysCollide* physCollide = physcollision->ConvertPolysoupToCollide( pPolySoups, true );
physcollision->PolysoupDestroy( pPolySoups );
if ( physCollide == NULL )
{
Warning( "UTIL_GetScaledPhysCollide: Failed to created scaled CPhysCollide for model %s %f!\n", modelinfo->GetModelName( modelinfo->GetModel( modelIndex ) ), scale );
return NULL;
}

(*scaledCollidables)[scale] = physCollide;

CPhysEntry entry;
entry.modelIndex = modelIndex;
entry.scale = scale;
g_pScaledReferences[physCollide] = entry;

return physCollide;
}

void UTIL_RemoveScaledPhysCollide( CPhysCollide *physCollide )
{
VPROF( "UTIL_RemoveScaledPhysCollide", VPROF_BUDGETGROUP_PHYSICS );

auto it = g_pScaledReferences.find( physCollide );
if ( it != g_pScaledReferences.end() )
{
--it->second.references;
if (it->second.references > 0)
return;
} else {
DevWarning( "UTIL_GetScaledPhysCollide: Failed to find reference counter!\n" );
}

auto iModel = g_pScaledCollidables.find( it->second.modelIndex );
if ( iModel == g_pScaledCollidables.end() )
return;

std::unordered_map<float, CPhysCollide*> scaledCollibales = *iModel->second;
auto iEntry = scaledCollibales.find( it->second.scale );
if ( iEntry == scaledCollibales.end() )
return;

scaledCollibales.erase( iEntry->first );
physcollision->DestroyCollide( physCollide );

if ( scaledCollibales.size() == 0 )
g_pScaledCollidables.erase( iModel );

DevMsg( "UTIL_RemoveScaledPhysCollide: Freed model %s\n", modelinfo->GetModelName(modelinfo->GetModel(it->second.modelIndex)) );
}
10 changes: 10 additions & 0 deletions game/client/cdll_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class IClientEntity;
class CHudTexture;
class CGameTrace;
class C_BaseEntity;
class C_BaseAnimating;
class CPhysCollide;

struct Ray_t;
struct client_textmessage_t;
Expand Down Expand Up @@ -184,4 +186,12 @@ int UTIL_GetMapKeyCount( const char *pszCustomKey );
// Returns true if the user has loaded any maps, false otherwise.
bool UTIL_HasLoadedAnyMap();

// SetModelScale being clientside broken fix
// Returns the given CPhysCollide for the given model index and scale. If not found it will create it.
CPhysCollide* UTIL_GetScaledPhysCollide( int modelIndex, float scale );

// Frees the given CPhysCollide if the internal reference count reaches 0.
// NOTE: Only supports CPhysCollide created by UTIL_GetScaledPhysCollide!
void UTIL_RemoveScaledPhysCollide( CPhysCollide *physCollide );

#endif // !UTIL_H