Skip to content

Commit

Permalink
collide: Support legacy style .phy files
Browse files Browse the repository at this point in the history
These legacy style .phy files are literally just serialized compact surfaces
and nothing else, with some misc. data shoved into some dummy compartment.

Some props in shipping HL2 still use this format, as they have a .phy, even after their
.qc had the $collisionmodel removed, as they didn't get the stale .phy in the game files deleted.

Closes: #35
  • Loading branch information
Joshua-Ashton committed Aug 30, 2022
1 parent d75827b commit 25eecb1
Showing 1 changed file with 68 additions and 38 deletions.
106 changes: 68 additions & 38 deletions vphysics_jolt/vjolt_collide.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,6 @@ namespace ivp_compat
{
struct collideheader_t
{
int size;
int vphysicsID;
short version;
short modelType;
Expand Down Expand Up @@ -491,11 +490,12 @@ namespace ivp_compat
}
};

static constexpr int IVP_COMPACT_SURFACE_ID = MAKEID('I','V','P','S');
static constexpr int IVP_COMPACT_SURFACE_ID_SWAPPED = MAKEID('S','P','V','I');
static constexpr int IVP_COMPACT_MOPP_ID = MAKEID('M','O','P','P');
static constexpr int VPHYSICS_COLLISION_ID = MAKEID('V','P','H','Y');
static constexpr short VPHYSICS_COLLISION_VERSION = 0x0100;
static constexpr int IVP_COMPACT_SURFACE_SUPER_LEGACY = 0; // Really old .phy files, don't have anything here, and were just serialized compact headers directly.
static constexpr int IVP_COMPACT_SURFACE_ID = MAKEID('I','V','P','S');
static constexpr int IVP_COMPACT_SURFACE_ID_SWAPPED = MAKEID('S','P','V','I');
static constexpr int IVP_COMPACT_MOPP_ID = MAKEID('M','O','P','P');
static constexpr int VPHYSICS_COLLISION_ID = MAKEID('V','P','H','Y');
static constexpr short VPHYSICS_COLLISION_VERSION = 0x0100;

enum
{
Expand Down Expand Up @@ -556,14 +556,8 @@ namespace ivp_compat
vecOut.AddToTail( pNode->GetCompactLedge() );
}

CPhysCollide *DeserializeIVP_Poly( const collideheader_t *pCollideHeader )
CPhysCollide *DeserializeIVP_Poly( const compactsurface_t* pSurface )
{
const compactsurfaceheader_t *pSurfaceHeader = reinterpret_cast< const compactsurfaceheader_t* >( pCollideHeader + 1 );
const compactsurface_t *pSurface = reinterpret_cast< const compactsurface_t* >( pSurfaceHeader + 1 );

if ( pSurface->dummy[2] != IVP_COMPACT_SURFACE_ID )
return nullptr;

const compactledgenode_t *pFirstLedgeNode = reinterpret_cast< const compactledgenode_t * >(
reinterpret_cast< const char * >( pSurface ) + pSurface->offset_ledgetree_root );

Expand Down Expand Up @@ -594,6 +588,14 @@ namespace ivp_compat
return CPhysConvex::FromConvexShape( pShape )->ToPhysCollide();
}
}

CPhysCollide *DeserializeIVP_Poly( const collideheader_t *pCollideHeader )
{
const compactsurfaceheader_t *pSurfaceHeader = reinterpret_cast< const compactsurfaceheader_t* >( pCollideHeader + 1 );
const compactsurface_t *pSurface = reinterpret_cast< const compactsurface_t* >( pSurfaceHeader + 1 );

return DeserializeIVP_Poly( pSurface );
}
}

void JoltPhysicsCollision::VCollideLoad( vcollide_t *pOutput, int solidCount, const char *pBuffer, int size, bool swap /*= false*/ )
Expand All @@ -614,41 +616,69 @@ void JoltPhysicsCollision::VCollideLoad( vcollide_t *pOutput, int solidCount, co
// this mess! :p
pOutput->solids[ i ] = nullptr;

const int solidSize = *reinterpret_cast<const int *>( pCursor );
pCursor += sizeof( int );

const ivp_compat::collideheader_t *pCollideHeader = reinterpret_cast<const ivp_compat::collideheader_t *>( pCursor );

if ( pCollideHeader->vphysicsID != ivp_compat::VPHYSICS_COLLISION_ID ||
pCollideHeader->version != ivp_compat::VPHYSICS_COLLISION_VERSION )
if ( pCollideHeader->vphysicsID == ivp_compat::VPHYSICS_COLLISION_ID )
{
Log_Warning( LOG_VJolt, "Skipped solid %d due to invalid header (id: %.4s, version: 0x%x)\n", i, &pCollideHeader->vphysicsID, pCollideHeader->version );
continue;
}
// This is the main path that everything falls down for a modern
// .phy file with the collide header.

switch ( pCollideHeader->modelType )
{
case ivp_compat::COLLIDE_POLY:
pOutput->solids[ i ] = DeserializeIVP_Poly( pCollideHeader );
break;
if ( pCollideHeader->version != ivp_compat::VPHYSICS_COLLISION_VERSION )
Log_Warning( LOG_VJolt, "Solid with unknown version: 0x%x, may crash!\n", pCollideHeader->version );

case ivp_compat::COLLIDE_MOPP:
Log_Warning( LOG_VJolt, "Unsupported solid type COLLIDE_MOPP on solid %d. Skipping...\n", i );
break;
switch ( pCollideHeader->modelType )
{
case ivp_compat::COLLIDE_POLY:
pOutput->solids[ i ] = DeserializeIVP_Poly( pCollideHeader );
break;

case ivp_compat::COLLIDE_MOPP:
Log_Warning( LOG_VJolt, "Unsupported solid type COLLIDE_MOPP on solid %d. Skipping...\n", i );
break;

case ivp_compat::COLLIDE_BALL:
Log_Warning( LOG_VJolt, "Unsupported solid type COLLIDE_BALL on solid %d. Skipping...\n", i );
break;
case ivp_compat::COLLIDE_BALL:
Log_Warning( LOG_VJolt, "Unsupported solid type COLLIDE_BALL on solid %d. Skipping...\n", i );
break;

case ivp_compat::COLLIDE_VIRTUAL:
Log_Warning( LOG_VJolt, "Unsupported solid type COLLIDE_VIRTUAL on solid %d. Skipping...\n", i );
break;
case ivp_compat::COLLIDE_VIRTUAL:
Log_Warning( LOG_VJolt, "Unsupported solid type COLLIDE_VIRTUAL on solid %d. Skipping...\n", i );
break;

default:
Log_Warning( LOG_VJolt, "Unsupported solid type 0x%x on solid %d. Skipping...\n", (int)pCollideHeader->modelType, i );
break;
default:
Log_Warning( LOG_VJolt, "Unsupported solid type 0x%x on solid %d. Skipping...\n", (int)pCollideHeader->modelType, i );
break;
}
}
else
{
// This must be a legacy style .phy where it is just a dumped compact surface.
// Some props in shipping HL2 still use this format, as they have a .phy, even after their
// .qc had the $collisionmodel removed, as they didn't get the stale .phy in the game files deleted.

const ivp_compat::compactsurface_t *pCompactSurface = reinterpret_cast<const ivp_compat::compactsurface_t *>( pCursor );
const int legacyModelType = pCompactSurface->dummy[2];
switch ( legacyModelType )
{
case ivp_compat::IVP_COMPACT_SURFACE_SUPER_LEGACY:
case ivp_compat::IVP_COMPACT_SURFACE_ID:
case ivp_compat::IVP_COMPACT_SURFACE_ID_SWAPPED:
pOutput->solids[i] = DeserializeIVP_Poly( pCompactSurface );
break;

case ivp_compat::IVP_COMPACT_MOPP_ID:
Log_Warning( LOG_VJolt, "Unsupported legacy solid type IVP_COMPACT_MOPP_ID on solid %d. Skipping...\n", i );
break;

default:
Log_Warning( LOG_VJolt, "Unsupported legacy solid type 0x%x on solid %d. Skipping...\n", legacyModelType, i);
break;
}
}

// Size does not include the size of "size", ironically!
// add sizeof( int ) for that.
pCursor += pCollideHeader->size + sizeof( int );
pCursor += solidSize;
}

// The rest of the buffer is KV.
Expand Down

0 comments on commit 25eecb1

Please sign in to comment.