Skip to content

Commit 6557093

Browse files
committed
[client] Fix SetModelScale having no clientside collisions
Origins: 1 - RaphaelIT7@dd24dae 2 - RaphaelIT7@4e6f0c1 3 - RaphaelIT7@f8faf4e 4 - RaphaelIT7@49f346e
1 parent d0fcf2f commit 6557093

5 files changed

Lines changed: 180 additions & 1 deletion

File tree

game/client/c_baseanimating.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,12 @@ C_BaseAnimating::~C_BaseAnimating()
789789
m_pAttachedTo->RemoveBoneAttachment( this );
790790
m_pAttachedTo = NULL;
791791
}
792+
793+
if ( m_pScaledCollidable )
794+
{
795+
UTIL_RemoveScaledPhysCollide( m_pScaledCollidable );
796+
m_pScaledCollidable = NULL;
797+
}
792798
}
793799

794800
bool C_BaseAnimating::UsesPowerOfTwoFrameBufferTexture( void )
@@ -5157,9 +5163,18 @@ void C_BaseAnimating::Simulate()
51575163
}
51585164
}
51595165

5160-
51615166
bool C_BaseAnimating::TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
51625167
{
5168+
if ( GetModelScale() != 1.0f )
5169+
{
5170+
if ( m_pScaledCollidable != NULL )
5171+
{
5172+
physcollision->TraceBox( ray, m_pScaledCollidable, GetAbsOrigin(), GetAbsAngles(), &tr );
5173+
5174+
return tr.DidHit();
5175+
}
5176+
}
5177+
51635178
if ( ray.m_IsRay && IsSolidFlagSet( FSOLID_CUSTOMRAYTEST ))
51645179
{
51655180
if (!TestHitboxes( ray, fContentsMask, tr ))
@@ -6706,3 +6721,22 @@ void C_BaseAnimating::MoveBoneAttachments( C_BaseAnimating* attachTarget )
67066721
}
67076722
}
67086723
}
6724+
6725+
//-----------------------------------------------------------------------------
6726+
// Purpose: Update Collisions. (Same way it's done serverside. We only update it when Activate is called)
6727+
//-----------------------------------------------------------------------------
6728+
void C_BaseAnimating::Activate()
6729+
{
6730+
if ( GetModelScale() != 1.0f )
6731+
{
6732+
if ( m_pScaledCollidable )
6733+
{
6734+
UTIL_RemoveScaledPhysCollide( m_pScaledCollidable );
6735+
m_pScaledCollidable = NULL;
6736+
}
6737+
6738+
m_pScaledCollidable = UTIL_GetScaledPhysCollide( GetModelIndex(), GetModelScale() );
6739+
}
6740+
6741+
BaseClass::Activate();
6742+
}

game/client/c_baseanimating.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback
449449

450450
virtual bool IsViewModel() const;
451451
void UpdateOnRemove( void ) override;
452+
virtual void Activate( void );
452453

453454
protected:
454455
// View models scale their attachment positions to account for FOV. To get the unmodified
@@ -640,6 +641,9 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback
640641
mutable MDLHandle_t m_hStudioHdr;
641642
CThreadFastMutex m_StudioHdrInitLock;
642643
bool m_bHasAttachedParticles;
644+
645+
private:
646+
CPhysCollide *m_pScaledCollidable;
643647
};
644648

645649
enum

game/client/c_baseentity.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,6 +1709,9 @@ class C_BaseEntity : public IClientEntity
17091709

17101710
private:
17111711
bool m_bOldShouldDraw;
1712+
1713+
public:
1714+
virtual void OnModelChange( int oldModelIndex, int newModelIndex ) {};
17121715
};
17131716

17141717
EXTERN_RECV_TABLE(DT_BaseEntity);

game/client/cdll_util.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
#include "view.h"
2929
#include "ixboxsystem.h"
3030
#include "inputsystem/iinputsystem.h"
31+
#include <unordered_map>
32+
#include <unordered_set>
33+
#include <vector>
34+
#include <vprof.h>
3135

3236
// memdbgon must be the last include file in a .cpp file!!!
3337
#include "tier0/memdbgon.h"
@@ -1315,3 +1319,127 @@ bool UTIL_HasLoadedAnyMap()
13151319

13161320
return g_pFullFileSystem->FileExists( szFilename, "MOD" );
13171321
}
1322+
1323+
struct CPhysEntry
1324+
{
1325+
int references = 1;
1326+
int modelIndex = 0;
1327+
float scale = 1.0f;
1328+
};
1329+
1330+
std::unordered_map<CPhysCollide*, CPhysEntry> g_pScaledReferences;
1331+
std::unordered_map<int, std::unordered_map<float, CPhysCollide*>*> g_pScaledCollidables;
1332+
CPhysCollide *UTIL_GetScaledPhysCollide( int modelIndex, float scale ) // Based off UTIL_CreateScaledPhysObject
1333+
{
1334+
VPROF( "UTIL_GetScaledPhysCollide", VPROF_BUDGETGROUP_PHYSICS );
1335+
1336+
if (scale == 1.0f)
1337+
return NULL;
1338+
1339+
std::unordered_map<float, CPhysCollide*>* scaledCollidables = nullptr;
1340+
auto iModel = g_pScaledCollidables.find( modelIndex );
1341+
if ( iModel != g_pScaledCollidables.end() )
1342+
{
1343+
std::unordered_map<float, CPhysCollide*>* collidables = iModel->second;
1344+
auto iCollidable = collidables->find( scale );
1345+
if ( iCollidable != collidables->end() )
1346+
{
1347+
auto it = g_pScaledReferences.find( iCollidable->second );
1348+
if ( it != g_pScaledReferences.end() )
1349+
{
1350+
++it->second.references;
1351+
} else {
1352+
DevWarning( "UTIL_GetScaledPhysCollide: Failed to find reference counter!\n" );
1353+
}
1354+
1355+
return iCollidable->second;
1356+
} else {
1357+
scaledCollidables = collidables;
1358+
}
1359+
} else {
1360+
scaledCollidables = new std::unordered_map<float, CPhysCollide*>;
1361+
g_pScaledCollidables[modelIndex] = scaledCollidables;
1362+
}
1363+
1364+
ICollisionQuery *pQuery = physcollision->CreateQueryModel( modelinfo->GetVCollide( modelIndex )->solids[0] );
1365+
if ( pQuery == NULL )
1366+
{
1367+
Warning( "UTIL_GetScaledPhysCollide: Failed to created scaled CPhysCollide for model %s!\n", modelinfo->GetModelName( modelinfo->GetModel( modelIndex ) ) );
1368+
return NULL;
1369+
}
1370+
1371+
const int nNumConvex = pQuery->ConvexCount();
1372+
CPhysPolysoup *pPolySoups = physcollision->PolysoupCreate();
1373+
1374+
for ( int i = 0; i < nNumConvex; ++i )
1375+
{
1376+
int nNumTris = pQuery->TriangleCount( i );
1377+
int nNumVerts = nNumTris * 3;
1378+
1379+
Vector *pVerts = (Vector *) stackalloc( sizeof(Vector) * nNumVerts );
1380+
for ( int j = 0; j < nNumTris; ++j )
1381+
{
1382+
int p = j*3;
1383+
pQuery->GetTriangleVerts( i, j, pVerts+p );
1384+
*(pVerts+p) *= scale;
1385+
*(pVerts+p+1) *= scale;
1386+
*(pVerts+p+2) *= scale;
1387+
}
1388+
1389+
for ( int j = 0; j < nNumVerts; j += 3 )
1390+
{
1391+
physcollision->PolysoupAddTriangle( pPolySoups, pVerts[j], pVerts[j + 1], pVerts[j + 2], 0 );
1392+
}
1393+
}
1394+
1395+
physcollision->DestroyQueryModel( pQuery );
1396+
1397+
CPhysCollide* physCollide = physcollision->ConvertPolysoupToCollide( pPolySoups, true );
1398+
physcollision->PolysoupDestroy( pPolySoups );
1399+
if ( physCollide == NULL )
1400+
{
1401+
Warning( "UTIL_GetScaledPhysCollide: Failed to created scaled CPhysCollide for model %s %f!\n", modelinfo->GetModelName( modelinfo->GetModel( modelIndex ) ), scale );
1402+
return NULL;
1403+
}
1404+
1405+
(*scaledCollidables)[scale] = physCollide;
1406+
1407+
CPhysEntry entry;
1408+
entry.modelIndex = modelIndex;
1409+
entry.scale = scale;
1410+
g_pScaledReferences[physCollide] = entry;
1411+
1412+
return physCollide;
1413+
}
1414+
1415+
void UTIL_RemoveScaledPhysCollide( CPhysCollide *physCollide )
1416+
{
1417+
VPROF( "UTIL_RemoveScaledPhysCollide", VPROF_BUDGETGROUP_PHYSICS );
1418+
1419+
auto it = g_pScaledReferences.find( physCollide );
1420+
if ( it != g_pScaledReferences.end() )
1421+
{
1422+
--it->second.references;
1423+
if (it->second.references > 0)
1424+
return;
1425+
} else {
1426+
DevWarning( "UTIL_GetScaledPhysCollide: Failed to find reference counter!\n" );
1427+
}
1428+
1429+
auto iModel = g_pScaledCollidables.find( it->second.modelIndex );
1430+
if ( iModel == g_pScaledCollidables.end() )
1431+
return;
1432+
1433+
std::unordered_map<float, CPhysCollide*> scaledCollibales = *iModel->second;
1434+
auto iEntry = scaledCollibales.find( it->second.scale );
1435+
if ( iEntry == scaledCollibales.end() )
1436+
return;
1437+
1438+
scaledCollibales.erase( iEntry->first );
1439+
physcollision->DestroyCollide( physCollide );
1440+
1441+
if ( scaledCollibales.size() == 0 )
1442+
g_pScaledCollidables.erase( iModel );
1443+
1444+
DevMsg( "UTIL_RemoveScaledPhysCollide: Freed model %s\n", modelinfo->GetModelName(modelinfo->GetModel(it->second.modelIndex)) );
1445+
}

game/client/cdll_util.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class IClientEntity;
3232
class CHudTexture;
3333
class CGameTrace;
3434
class C_BaseEntity;
35+
class C_BaseAnimating;
36+
class CPhysCollide;
3537

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

189+
// SetModelScale being clientside broken fix
190+
// Returns the given CPhysCollide for the given model index and scale. If not found it will create it.
191+
CPhysCollide* UTIL_GetScaledPhysCollide( int modelIndex, float scale );
192+
193+
// Frees the given CPhysCollide if the internal reference count reaches 0.
194+
// NOTE: Only supports CPhysCollide created by UTIL_GetScaledPhysCollide!
195+
void UTIL_RemoveScaledPhysCollide( CPhysCollide *physCollide );
196+
187197
#endif // !UTIL_H

0 commit comments

Comments
 (0)