Skip to content

Commit 2667a0b

Browse files
RaphaelIT7dimhotepus
authored andcommitted
[client] Fix SetModelScale having no clientside collisions
Origins: 1 - RaphaelIT7@dd24dae 2 - RaphaelIT7@4e6f0c1 3 - RaphaelIT7@f8faf4e 4 - RaphaelIT7@49f346e
1 parent 116c728 commit 2667a0b

File tree

5 files changed

+180
-1
lines changed

5 files changed

+180
-1
lines changed

game/client/c_baseanimating.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,12 @@ C_BaseAnimating::~C_BaseAnimating()
792792
m_pAttachedTo->RemoveBoneAttachment( this );
793793
m_pAttachedTo = NULL;
794794
}
795+
796+
if ( m_pScaledCollidable )
797+
{
798+
UTIL_RemoveScaledPhysCollide( m_pScaledCollidable );
799+
m_pScaledCollidable = NULL;
800+
}
795801
}
796802

797803
bool C_BaseAnimating::UsesPowerOfTwoFrameBufferTexture( void )
@@ -5196,9 +5202,18 @@ void C_BaseAnimating::Simulate()
51965202
}
51975203
}
51985204

5199-
52005205
bool C_BaseAnimating::TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
52015206
{
5207+
if ( GetModelScale() != 1.0f )
5208+
{
5209+
if ( m_pScaledCollidable != NULL )
5210+
{
5211+
physcollision->TraceBox( ray, m_pScaledCollidable, GetAbsOrigin(), GetAbsAngles(), &tr );
5212+
5213+
return tr.DidHit();
5214+
}
5215+
}
5216+
52025217
if ( ray.m_IsRay && IsSolidFlagSet( FSOLID_CUSTOMRAYTEST ))
52035218
{
52045219
if (!TestHitboxes( ray, fContentsMask, tr ))
@@ -6745,3 +6760,22 @@ void C_BaseAnimating::MoveBoneAttachments( C_BaseAnimating* attachTarget )
67456760
}
67466761
}
67476762
}
6763+
6764+
//-----------------------------------------------------------------------------
6765+
// Purpose: Update Collisions. (Same way it's done serverside. We only update it when Activate is called)
6766+
//-----------------------------------------------------------------------------
6767+
void C_BaseAnimating::Activate()
6768+
{
6769+
if ( GetModelScale() != 1.0f )
6770+
{
6771+
if ( m_pScaledCollidable )
6772+
{
6773+
UTIL_RemoveScaledPhysCollide( m_pScaledCollidable );
6774+
m_pScaledCollidable = NULL;
6775+
}
6776+
6777+
m_pScaledCollidable = UTIL_GetScaledPhysCollide( GetModelIndex(), GetModelScale() );
6778+
}
6779+
6780+
BaseClass::Activate();
6781+
}

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
@@ -641,6 +642,9 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback
641642
mutable MDLHandle_t m_hStudioHdr;
642643
CThreadFastMutex m_StudioHdrInitLock;
643644
bool m_bHasAttachedParticles;
645+
646+
private:
647+
CPhysCollide *m_pScaledCollidable;
644648
};
645649

646650
enum

game/client/c_baseentity.h

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

17121712
private:
17131713
bool m_bOldShouldDraw;
1714+
1715+
public:
1716+
virtual void OnModelChange( int oldModelIndex, int newModelIndex ) {};
17141717
};
17151718

17161719
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"
@@ -1289,3 +1293,127 @@ bool UTIL_HasLoadedAnyMap()
12891293

12901294
return g_pFullFileSystem->FileExists( szFilename, "MOD" );
12911295
}
1296+
1297+
struct CPhysEntry
1298+
{
1299+
int references = 1;
1300+
int modelIndex = 0;
1301+
float scale = 1.0f;
1302+
};
1303+
1304+
std::unordered_map<CPhysCollide*, CPhysEntry> g_pScaledReferences;
1305+
std::unordered_map<int, std::unordered_map<float, CPhysCollide*>*> g_pScaledCollidables;
1306+
CPhysCollide *UTIL_GetScaledPhysCollide( int modelIndex, float scale ) // Based off UTIL_CreateScaledPhysObject
1307+
{
1308+
VPROF( "UTIL_GetScaledPhysCollide", VPROF_BUDGETGROUP_PHYSICS );
1309+
1310+
if (scale == 1.0f)
1311+
return NULL;
1312+
1313+
std::unordered_map<float, CPhysCollide*>* scaledCollidables = nullptr;
1314+
auto iModel = g_pScaledCollidables.find( modelIndex );
1315+
if ( iModel != g_pScaledCollidables.end() )
1316+
{
1317+
std::unordered_map<float, CPhysCollide*>* collidables = iModel->second;
1318+
auto iCollidable = collidables->find( scale );
1319+
if ( iCollidable != collidables->end() )
1320+
{
1321+
auto it = g_pScaledReferences.find( iCollidable->second );
1322+
if ( it != g_pScaledReferences.end() )
1323+
{
1324+
++it->second.references;
1325+
} else {
1326+
DevWarning( "UTIL_GetScaledPhysCollide: Failed to find reference counter!\n" );
1327+
}
1328+
1329+
return iCollidable->second;
1330+
} else {
1331+
scaledCollidables = collidables;
1332+
}
1333+
} else {
1334+
scaledCollidables = new std::unordered_map<float, CPhysCollide*>;
1335+
g_pScaledCollidables[modelIndex] = scaledCollidables;
1336+
}
1337+
1338+
ICollisionQuery *pQuery = physcollision->CreateQueryModel( modelinfo->GetVCollide( modelIndex )->solids[0] );
1339+
if ( pQuery == NULL )
1340+
{
1341+
Warning( "UTIL_GetScaledPhysCollide: Failed to created scaled CPhysCollide for model %s!\n", modelinfo->GetModelName( modelinfo->GetModel( modelIndex ) ) );
1342+
return NULL;
1343+
}
1344+
1345+
const int nNumConvex = pQuery->ConvexCount();
1346+
CPhysPolysoup *pPolySoups = physcollision->PolysoupCreate();
1347+
1348+
for ( int i = 0; i < nNumConvex; ++i )
1349+
{
1350+
int nNumTris = pQuery->TriangleCount( i );
1351+
int nNumVerts = nNumTris * 3;
1352+
1353+
Vector *pVerts = (Vector *) stackalloc( sizeof(Vector) * nNumVerts );
1354+
for ( int j = 0; j < nNumTris; ++j )
1355+
{
1356+
int p = j*3;
1357+
pQuery->GetTriangleVerts( i, j, pVerts+p );
1358+
*(pVerts+p) *= scale;
1359+
*(pVerts+p+1) *= scale;
1360+
*(pVerts+p+2) *= scale;
1361+
}
1362+
1363+
for ( int j = 0; j < nNumVerts; j += 3 )
1364+
{
1365+
physcollision->PolysoupAddTriangle( pPolySoups, pVerts[j], pVerts[j + 1], pVerts[j + 2], 0 );
1366+
}
1367+
}
1368+
1369+
physcollision->DestroyQueryModel( pQuery );
1370+
1371+
CPhysCollide* physCollide = physcollision->ConvertPolysoupToCollide( pPolySoups, true );
1372+
physcollision->PolysoupDestroy( pPolySoups );
1373+
if ( physCollide == NULL )
1374+
{
1375+
Warning( "UTIL_GetScaledPhysCollide: Failed to created scaled CPhysCollide for model %s %f!\n", modelinfo->GetModelName( modelinfo->GetModel( modelIndex ) ), scale );
1376+
return NULL;
1377+
}
1378+
1379+
(*scaledCollidables)[scale] = physCollide;
1380+
1381+
CPhysEntry entry;
1382+
entry.modelIndex = modelIndex;
1383+
entry.scale = scale;
1384+
g_pScaledReferences[physCollide] = entry;
1385+
1386+
return physCollide;
1387+
}
1388+
1389+
void UTIL_RemoveScaledPhysCollide( CPhysCollide *physCollide )
1390+
{
1391+
VPROF( "UTIL_RemoveScaledPhysCollide", VPROF_BUDGETGROUP_PHYSICS );
1392+
1393+
auto it = g_pScaledReferences.find( physCollide );
1394+
if ( it != g_pScaledReferences.end() )
1395+
{
1396+
--it->second.references;
1397+
if (it->second.references > 0)
1398+
return;
1399+
} else {
1400+
DevWarning( "UTIL_GetScaledPhysCollide: Failed to find reference counter!\n" );
1401+
}
1402+
1403+
auto iModel = g_pScaledCollidables.find( it->second.modelIndex );
1404+
if ( iModel == g_pScaledCollidables.end() )
1405+
return;
1406+
1407+
std::unordered_map<float, CPhysCollide*> scaledCollibales = *iModel->second;
1408+
auto iEntry = scaledCollibales.find( it->second.scale );
1409+
if ( iEntry == scaledCollibales.end() )
1410+
return;
1411+
1412+
scaledCollibales.erase( iEntry->first );
1413+
physcollision->DestroyCollide( physCollide );
1414+
1415+
if ( scaledCollibales.size() == 0 )
1416+
g_pScaledCollidables.erase( iModel );
1417+
1418+
DevMsg( "UTIL_RemoveScaledPhysCollide: Freed model %s\n", modelinfo->GetModelName(modelinfo->GetModel(it->second.modelIndex)) );
1419+
}

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)