feat(Portal Simulation): Portals now work with displacements.

Taken from Portal2 code.

feat(sv_allow_mobile_portals): Added `sv_allow_mobile_portals` doesn't
really work, most of it is not implemented yet.

feat(sv_autojump_): Added `sv_autojump_` does what it says - auto jumps.

fix(d1_canals_01): Fix crash when vortigaunt charges your suit.

fix(CRagdollPropAttached): Check if `pRefObject` is nullptr so we can
feed a combine apc to a barnacle.
This commit is contained in:
tupoy-ya 2023-10-01 18:30:10 +05:00
parent 881d4a91c9
commit 4bebd92781
No known key found for this signature in database
GPG Key ID: 3541E2B1B448A2DB
12 changed files with 390 additions and 28 deletions

View File

@ -261,8 +261,11 @@ void C_VortigauntChargeToken::NotifyShouldTransmit( ShouldTransmitState_t state
// Turn on
if ( state == SHOULDTRANSMIT_START )
{
m_hEffect = ParticleProp()->Create( "vortigaunt_charge_token", PATTACH_ABSORIGIN_FOLLOW );
m_hEffect->SetControlPointEntity( 0, this );
if ( m_hEffect )
{
m_hEffect = ParticleProp()->Create( "vortigaunt_charge_token", PATTACH_ABSORIGIN_FOLLOW );
m_hEffect->SetControlPointEntity( 0, this );
}
}
}
@ -392,8 +395,11 @@ void C_VortigauntEffectDispel::NotifyShouldTransmit( ShouldTransmitState_t state
// Turn on
if ( state == SHOULDTRANSMIT_START )
{
if( m_hEffect )
{
m_hEffect = ParticleProp()->Create( "vortigaunt_hand_glow", PATTACH_ABSORIGIN_FOLLOW );
m_hEffect->SetControlPointEntity( 0, this );
m_hEffect->SetControlPointEntity( 0, this );
}
}
}

View File

@ -1509,6 +1509,9 @@ void CRagdollPropAttached::InitRagdollAttached(
IPhysicsObject *pRefObject = m_ragdoll.list[ragdollAttachedIndex].pObject;
if( !pRefObject )
return;
Vector attachmentPointRagdollSpace;
pRefObject->WorldToLocal( &attachmentPointRagdollSpace, worldAttachOrigin );

View File

@ -34,7 +34,7 @@ bool g_bBumpedByLinkedPortal;
ConVar sv_portal_placement_debug ("sv_portal_placement_debug", "0", FCVAR_REPLICATED );
ConVar sv_portal_placement_never_bump ("sv_portal_placement_never_bump", "0", FCVAR_REPLICATED | FCVAR_CHEAT );
extern ConVar sv_allow_mobile_portals;
bool IsMaterialInList( const csurface_t &surface, char *g_ppszMaterials[] )
{
@ -1188,22 +1188,7 @@ float VerifyPortalPlacement( const CProp_Portal *pIgnorePortal, Vector &vOrigin,
return PORTAL_ANALOG_SUCCESS_INVALID_SURFACE;
}
// Check if the surface is moving
Vector vVelocityCheck;
AngularImpulse vAngularImpulseCheck;
IPhysicsObject *pPhysicsObject = tr.m_pEnt->VPhysicsGetObject();
if ( pPhysicsObject )
{
pPhysicsObject->GetVelocity( &vVelocityCheck, &vAngularImpulseCheck );
}
else
{
tr.m_pEnt->GetVelocity( &vVelocityCheck, &vAngularImpulseCheck );
}
if ( vVelocityCheck != vec3_origin || vAngularImpulseCheck != vec3_origin )
if ( !sv_allow_mobile_portals.GetBool() && UTIL_IsEntityMovingOrRotating( tr.m_pEnt )/*(vVelocityCheck != vec3_origin || vAngularImpulseCheck != vec3_origin)*/ )
{
if ( sv_portal_placement_debug.GetBool() )
{

View File

@ -1371,7 +1371,7 @@ void CProp_Portal::Touch( CBaseEntity *pOther )
DoFizzleEffect( PORTAL_FIZZLE_KILLED, false );
Fizzle();
}
else if ( tr.m_pEnt && tr.m_pEnt->IsMoving() )
else if ( !sv_allow_mobile_portals.GetBool() && tr.m_pEnt && tr.m_pEnt->IsMoving() )
{
DevMsg( "Surface behind portal is moving.\n" );

View File

@ -162,5 +162,6 @@ inline const VMatrix& CProp_Portal::MatrixThisToLinked() const
return m_matrixThisToLinked;
}
extern ConVar sv_allow_mobile_portals;
#endif //#ifndef PROP_PORTAL_H

View File

@ -402,7 +402,7 @@ float CWeaponPortalgun::TraceFirePortal( bool bPortal2, const Vector &vTraceStar
qFinalAngles = pPortal->m_qDelayedAngles;
}
return PORTAL_ANALOG_SUCCESS_BUMPED;
return PORTAL_ANALOG_SUCCESS_PASSTHROUGH_SURFACE;
}
// Trace to the surface to see if there's a rotating door in the way

View File

@ -34,7 +34,7 @@ extern IFileSystem *filesystem;
#include "env_player_surface_trigger.h"
static ConVar dispcoll_drawplane( "dispcoll_drawplane", "0" );
#endif
static ConVar sv_autojump_( "sv_autojump_", "0" );
// tickcount currently isn't set during prediction, although gpGlobals->curtime and
// gpGlobals->frametime are. We should probably set tickcount (to player->m_nTickBase),
@ -2347,7 +2347,6 @@ void CGameMovement::PlaySwimSound()
MoveHelper()->StartSound( mv->GetAbsOrigin(), "Player.Swim" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
@ -2404,8 +2403,11 @@ bool CGameMovement::CheckJumpButton( void )
return false;
#endif
if ( mv->m_nOldButtons & IN_JUMP )
if ( (mv->m_nOldButtons & IN_JUMP) &&
(!sv_autojump_.GetBool() && player->GetGroundEntity()) )
{
return false; // don't pogo stick
}
// Cannot jump will in the unduck transition.
if ( player->m_Local.m_bDucking && ( player->GetFlags() & FL_DUCKING ) )
@ -2526,6 +2528,7 @@ bool CGameMovement::CheckJumpButton( void )
// Flag that we jumped.
mv->m_nOldButtons |= IN_JUMP; // don't jump again until released
return true;
}

View File

@ -8,6 +8,7 @@
#include "cbase.h"
#include "PortalSimulation.h"
#include "convar.h"
#include "vphysics_interface.h"
#include "physics.h"
#include "portal_shareddefs.h"
@ -16,6 +17,7 @@
#include "filesystem.h"
#include "collisionutils.h"
#include "tier1/callqueue.h"
#include "vphysics/virtualmesh.h"
#ifndef CLIENT_DLL
@ -44,6 +46,7 @@ extern IPhysicsConstraintEvent *g_pConstraintEvents;
static ConVar sv_portal_collision_sim_bounds_x( "sv_portal_collision_sim_bounds_x", "200", FCVAR_REPLICATED, "Size of box used to grab collision geometry around placed portals. These should be at the default size or larger only!" );
static ConVar sv_portal_collision_sim_bounds_y( "sv_portal_collision_sim_bounds_y", "200", FCVAR_REPLICATED, "Size of box used to grab collision geometry around placed portals. These should be at the default size or larger only!" );
static ConVar sv_portal_collision_sim_bounds_z( "sv_portal_collision_sim_bounds_z", "252", FCVAR_REPLICATED, "Size of box used to grab collision geometry around placed portals. These should be at the default size or larger only!" );
ConVar portal_clone_displacements ( "portal_clone_displacements", "1", FCVAR_REPLICATED | FCVAR_CHEAT );
//#define DEBUG_PORTAL_SIMULATION_CREATION_TIMES //define to output creation timings to developer 2
//#define DEBUG_PORTAL_COLLISION_ENVIRONMENTS //define this to allow for glview collision dumps of portal simulators
@ -1208,6 +1211,19 @@ void CPortalSimulator::CreateLocalPhysics( void )
m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
}
if( m_InternalData.Simulation.Static.World.Displacements.pCollideable != NULL )
{
m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( m_InternalData.Simulation.Static.World.Displacements.pCollideable, m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, vec3_origin, vec3_angle, &params );
if( (m_InternalData.Simulation.pCollisionEntity != NULL) && (m_InternalData.Simulation.pCollisionEntity->VPhysicsGetObject() == NULL) )
{
m_InternalData.Simulation.pCollisionEntity->VPhysicsSetObject(m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject);
m_InternalData.Simulation.pCollisionEntity = NULL;
}
m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
}
//Assert( m_InternalData.Simulation.Static.World.StaticProps.PhysicsObjects.Count() == 0 ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
#ifdef _DEBUG
for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
@ -1435,12 +1451,20 @@ void CPortalSimulator::ClearLocalPhysics( void )
m_InternalData.Simulation.pPhysicsEnvironment->CleanupDeleteList();
m_InternalData.Simulation.pPhysicsEnvironment->SetQuickDelete( true ); //if we don't do this, things crash the next time we cleanup the delete list while checking mindists
//world brushes
if( m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject )
{
m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject );
m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject = NULL;
}
//world displacement surfaces
if( m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject )
{
m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject );
m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject = NULL;
}
if( m_InternalData.Simulation.Static.World.StaticProps.bPhysicsExists &&
(m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count() != 0) )
{
@ -1646,6 +1670,181 @@ bool CPortalSimulator::CreateLocalCollision( void )
STOPDEBUGTIMER( worldBrushTimer );
DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sWorld Brushes=%fms\n", GetPortalSimulatorGUID(), TABSPACING, worldBrushTimer.GetDuration().GetMillisecondsF() ); );
// Displacements
if ( portal_clone_displacements.GetBool() )
{
//scale the extents to usable sizes
float flScaleX = sv_portal_collision_sim_bounds_x.GetFloat();
if ( flScaleX < 200.0f )
flScaleX = 200.0f;
float flScaleY = sv_portal_collision_sim_bounds_y.GetFloat();
if ( flScaleY < 200.0f )
flScaleY = 200.0f;
float flScaleZ = sv_portal_collision_sim_bounds_z.GetFloat();
if ( flScaleZ < 252.0f )
flScaleZ = 252.0f;
VPlane displacementRejectRegions[6];
displacementRejectRegions[0].m_Normal = -m_InternalData.Placement.vForward;
displacementRejectRegions[0].m_Dist = displacementRejectRegions[0].m_Normal.Dot( m_InternalData.Placement.ptCenter );
displacementRejectRegions[1].m_Normal = m_InternalData.Placement.vForward;
displacementRejectRegions[1].m_Dist = displacementRejectRegions[1].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + flScaleX;
displacementRejectRegions[2].m_Normal = m_InternalData.Placement.vRight;
displacementRejectRegions[2].m_Dist = displacementRejectRegions[2].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + flScaleY;
displacementRejectRegions[3].m_Normal = -m_InternalData.Placement.vRight;
displacementRejectRegions[3].m_Dist = displacementRejectRegions[3].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + flScaleY;
displacementRejectRegions[4].m_Normal = m_InternalData.Placement.vUp;
displacementRejectRegions[4].m_Dist = displacementRejectRegions[4].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + flScaleZ;
displacementRejectRegions[5].m_Normal = -m_InternalData.Placement.vUp;
displacementRejectRegions[5].m_Dist = displacementRejectRegions[5].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + flScaleZ;
CREATEDEBUGTIMER( dispTimer );
STARTDEBUGTIMER( dispTimer );
Assert( m_InternalData.Simulation.Static.World.Displacements.pCollideable == NULL );
virtualmeshlist_t DisplacementMeshes[32];
int iMeshes = enginetrace->GetMeshesFromDisplacementsInAABB( m_InternalData.Placement.vecCurAABBMins, m_InternalData.Placement.vecCurAABBMaxs, DisplacementMeshes, ARRAYSIZE(DisplacementMeshes) );
if( iMeshes > 0 )
{
CPhysPolysoup *pDispCollideSoup = physcollision->PolysoupCreate();
// Count total triangles added to this poly soup- Can't support more than 65535.
int iTriCount = 0;
for( int i = 0; (i != iMeshes) && (iTriCount < 65535); ++i )
{
virtualmeshlist_t *pMesh = &DisplacementMeshes[i];
for ( int j = 0; j < pMesh->indexCount; j+=3 )
{
Vector *points[3] = { &pMesh->pVerts[ pMesh->indices[j+0] ], &pMesh->pVerts[ pMesh->indices[j+1] ], &pMesh->pVerts[ pMesh->indices[j+2] ] };
//test for triangles that lie completely outside our collision area
{
int k;
for( k = 0; k != ARRAYSIZE( displacementRejectRegions ); ++k )
{
//test all 3 points on each plane
if( (displacementRejectRegions[k].DistTo( *points[0] ) >= 0.0f) &&
(displacementRejectRegions[k].DistTo( *points[1] ) >= 0.0f) &&
(displacementRejectRegions[k].DistTo( *points[2] ) >= 0.0f) )
{
break; //break out if all 3 are in front of a rejection plane
}
}
if( k != ARRAYSIZE( displacementRejectRegions ) )
{
//was fully rejected by a plane
continue;
}
}
//clip to portal plane
{
//we do however need to clip to the wall plane
int iFront = 0;
int iBack = 0;
float fDists[3];
int iForwardPoints[3];
int iBackPoints[3];
for( int k = 0; k != 3; ++k )
{
fDists[k] = m_InternalData.Placement.PortalPlane.DistTo( *points[k] );
if( fDists[k] >= 0.0f )
{
iForwardPoints[iFront] = k;
++iFront;
}
else
{
iBackPoints[iBack] = k;
++iBack;
}
}
if( iFront != 0 )
{
if( iBack != 0 )
{
//need to clip the triangle
Vector vClippedPoints[2]; //guaranteed to intersect exactly twice
if( iBack == 2 )
{
if( fDists[iForwardPoints[0]] < 0.1f )
continue;
//easy case.
float fTotalDist = fDists[iForwardPoints[0]] - fDists[iBackPoints[0]];
if( fTotalDist < 0.1f )
continue;
vClippedPoints[0] = ((*points[iBackPoints[0]]) * (fDists[iForwardPoints[0]]/fTotalDist)) - ((*points[iForwardPoints[0]]) * (fDists[iBackPoints[0]]/fTotalDist));
points[iBackPoints[0]] = &vClippedPoints[0];
fTotalDist = fDists[iForwardPoints[0]] - fDists[iBackPoints[1]];
if( fTotalDist < 0.1f )
continue;
vClippedPoints[1] = ((*points[iBackPoints[1]]) * (fDists[iForwardPoints[0]]/fTotalDist)) - ((*points[iForwardPoints[0]]) * (fDists[iBackPoints[1]]/fTotalDist));
points[iBackPoints[1]] = &vClippedPoints[1];
physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex );
++iTriCount;
}
else
{
if( fDists[iBackPoints[0]] > -0.1f )
{
physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex );
++iTriCount;
continue;
}
//need to create 2 triangles
float fTotalDist = fDists[iForwardPoints[0]] - fDists[iBackPoints[0]];
vClippedPoints[0] = ((*points[iBackPoints[0]]) * (fDists[iForwardPoints[0]]/fTotalDist)) - ((*points[iForwardPoints[0]]) * (fDists[iBackPoints[0]]/fTotalDist));
fTotalDist = fDists[iForwardPoints[1]] - fDists[iBackPoints[0]];
vClippedPoints[1] = ((*points[iBackPoints[0]]) * (fDists[iForwardPoints[1]]/fTotalDist)) - ((*points[iForwardPoints[1]]) * (fDists[iBackPoints[0]]/fTotalDist));
points[iBackPoints[0]] = &vClippedPoints[0];
physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex );
++iTriCount;
points[iBackPoints[0]] = &vClippedPoints[1];
points[iForwardPoints[0]] = &vClippedPoints[0];
physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex );
++iTriCount;
}
}
else
{
//triangle resides wholly in front of the portal plane
physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex );
++iTriCount;
}
if( iTriCount >= 65535 )
{
break;
}
}
}
}// triangle loop
}
m_InternalData.Simulation.Static.World.Displacements.pCollideable = physcollision->ConvertPolysoupToCollide( pDispCollideSoup, false );
// clean up poly soup
physcollision->PolysoupDestroy( pDispCollideSoup );
}
//m_InternalData.Simulation.Static.World.Displacements.pCollideable = enginetrace->GetCollidableFromDisplacementsInAABB( m_InternalData.Placement.vecCurAABBMins, m_InternalData.Placement.vecCurAABBMaxs );
STOPDEBUGTIMER( dispTimer );
DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sDisplacement Surfaces=%fms\n", GetPortalSimulatorGUID(), TABSPACING, dispTimer.GetDuration().GetMillisecondsF() ); );
}
CREATEDEBUGTIMER( worldPropTimer );
STARTDEBUGTIMER( worldPropTimer );
#ifdef _DEBUG
@ -1806,6 +2005,12 @@ void CPortalSimulator::ClearLocalCollision( void )
m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable = NULL;
}
if( m_InternalData.Simulation.Static.World.Displacements.pCollideable )
{
physcollision->DestroyCollide( m_InternalData.Simulation.Static.World.Displacements.pCollideable );
m_InternalData.Simulation.Static.World.Displacements.pCollideable = NULL;
}
if( m_InternalData.Simulation.Static.World.Brushes.pCollideable )
{
physcollision->DestroyCollide( m_InternalData.Simulation.Static.World.Brushes.pCollideable );
@ -1919,6 +2124,9 @@ void CPortalSimulator::CreatePolyhedrons( void )
if( ptTest.z > vAABBMaxs.z ) vAABBMaxs.z = ptTest.z;
}
m_InternalData.Placement.vecCurAABBMins = vAABBMins;
m_InternalData.Placement.vecCurAABBMaxs = vAABBMaxs;
//Brushes
{
Assert( m_InternalData.Simulation.Static.World.Brushes.Polyhedrons.Count() == 0 );
@ -2413,7 +2621,7 @@ void CPortalSimulator::PrePhysFrame( void )
Assert( (pEntity != NULL) && (pEntity->IsMarkedForDeletion() == false) );
IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject();
if( (pPhysObject == NULL) || pPhysObject->IsAsleep() )
if( pPhysObject == NULL /*|| pPhysObject->IsAsleep() */)
continue;
int iEntIndex = pEntity->entindex();
@ -2572,7 +2780,15 @@ bool CPortalSimulator::CreatedPhysicsObject( const IPhysicsObject *pObject, PS_P
*pOut_SourceType = PSPOST_HOLYWALL_TUBE;
return true;
}
}
if( pObject == m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject )
{
if( pOut_SourceType )
*pOut_SourceType = PSPOST_LOCAL_DISPLACEMENT;
return true;
}
return false;
}
@ -2980,6 +3196,14 @@ int CPSCollisionEntity::VPhysicsGetObjectList( IPhysicsObject **pList, int listM
return iRetVal;
}
if( m_pOwningSimulator->m_DataAccess.Simulation.Static.World.Displacements.pPhysicsObject != NULL )
{
pList[iRetVal] = m_pOwningSimulator->m_DataAccess.Simulation.Static.World.Displacements.pPhysicsObject;
++iRetVal;
if( iRetVal == listMax )
return iRetVal;
}
return iRetVal;
}
@ -3028,6 +3252,9 @@ void DumpActiveCollision( const CPortalSimulator *pPortalSimulator, const char *
}
}
if ( pPortalSimulator->GetInternalData().Simulation.Static.World.Displacements.pCollideable )
PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Simulation.Static.World.Displacements.pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALBRUSH, szFileName );
if( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pCollideable )
PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALBRUSH, szFileName );

View File

@ -40,7 +40,8 @@ enum PS_PhysicsObjectSourceType_t
PSPOST_REMOTE_BRUSHES,
PSPOST_LOCAL_STATICPROPS,
PSPOST_REMOTE_STATICPROPS,
PSPOST_HOLYWALL_TUBE
PSPOST_HOLYWALL_TUBE,
PSPOST_LOCAL_DISPLACEMENT
};
struct PortalTransformAsAngledPosition_t //a matrix transformation from this portal to the linked portal, stored as vector and angle transforms
@ -105,6 +106,8 @@ struct PS_PlacementData_t //stuff useful for geometric operations
PortalTransformAsAngledPosition_t ptaap_ThisToLinked;
PortalTransformAsAngledPosition_t ptaap_LinkedToThis;
CPhysCollide *pHoleShapeCollideable; //used to test if a collideable is in the hole, should NOT be collided against in general
Vector vecCurAABBMins;
Vector vecCurAABBMaxs;
PS_PlacementData_t( void )
{
memset( this, 0, sizeof( PS_PlacementData_t ) );
@ -124,6 +127,17 @@ struct PS_SD_Static_World_Brushes_t
};
struct PS_SD_Static_World_Displacements_t
{
CPhysCollide *pCollideable;
#ifndef CLIENT_DLL
IPhysicsObject *pPhysicsObject;
PS_SD_Static_World_Displacements_t() : pCollideable(NULL), pPhysicsObject(NULL) {};
#else
PS_SD_Static_World_Displacements_t() : pCollideable(NULL) {};
#endif
};
struct PS_SD_Static_World_StaticProps_ClippedProp_t
{
@ -153,6 +167,7 @@ struct PS_SD_Static_World_StaticProps_t
struct PS_SD_Static_World_t //stuff in front of the portal
{
PS_SD_Static_World_Brushes_t Brushes;
PS_SD_Static_World_Displacements_t Displacements;
PS_SD_Static_World_StaticProps_t StaticProps;
};

View File

@ -35,6 +35,9 @@ ConVar sv_portal_trace_vs_holywall ("sv_portal_trace_vs_holywall", "1", FCVAR_RE
ConVar sv_portal_trace_vs_staticprops ("sv_portal_trace_vs_staticprops", "1", FCVAR_REPLICATED | FCVAR_CHEAT, "Use traces against portal environment static prop geometry" );
ConVar sv_use_find_closest_passable_space ("sv_use_find_closest_passable_space", "1", FCVAR_REPLICATED | FCVAR_CHEAT, "Enables heavy-handed player teleporting stuck fix code." );
ConVar sv_use_transformed_collideables("sv_use_transformed_collideables", "1", FCVAR_REPLICATED | FCVAR_CHEAT, "Disables traces against remote portal moving entities using transforms to bring them into local space." );
extern ConVar portal_clone_displacements;
class CTransformedCollideable : public ICollideable //wraps an existing collideable, but transforms everything that pertains to world space by another transform
{
public:
@ -623,6 +626,16 @@ void UTIL_Portal_TraceRay( const CProp_Portal *pPortal, const Ray_t &ray, unsign
bCopyBackBrushTraceData = true;
}
if( portalSimulator.m_DataAccess.Simulation.Static.World.Displacements.pCollideable && sv_portal_trace_vs_world.GetBool() && portal_clone_displacements.GetBool() )
{
physcollision->TraceBox( ray, portalSimulator.m_DataAccess.Simulation.Static.World.Displacements.pCollideable, vec3_origin, vec3_angle, &TempTrace );
if( (TempTrace.startsolid == false) && (TempTrace.fraction < pTrace->fraction) ) //never allow something to be stuck in the tube, it's more of a last-resort guide than a real collideable
{
*pTrace = TempTrace;
bCopyBackBrushTraceData = true;
}
}
if( bTraceHolyWall )
{
if( portalSimulator.m_DataAccess.Simulation.Static.Wall.Local.Tube.pCollideable )
@ -938,6 +951,18 @@ void UTIL_Portal_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, c
}
}
if( pPortalSimulator->m_DataAccess.Simulation.Static.World.Displacements.pCollideable &&
sv_portal_trace_vs_world.GetBool() &&
portal_clone_displacements.GetBool() )
{
physcollision->TraceBox( entRay, MASK_ALL, NULL, pPortalSimulator->m_DataAccess.Simulation.Static.World.Displacements.pCollideable, vec3_origin, vec3_angle, &tempTrace );
if ( tempTrace.startsolid || (tempTrace.fraction < pTrace->fraction) )
{
*pTrace = tempTrace;
}
}
//if( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pCollideable &&
if( pLinkedPortalSimulator &&
pLinkedPortalSimulator->m_DataAccess.Simulation.Static.World.Brushes.pCollideable &&
@ -955,6 +980,20 @@ void UTIL_Portal_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, c
}
}
if( pLinkedPortalSimulator &&
pLinkedPortalSimulator->m_DataAccess.Simulation.Static.World.Displacements.pCollideable &&
sv_portal_trace_vs_world.GetBool() &&
sv_portal_trace_vs_holywall.GetBool() &&
portal_clone_displacements.GetBool() )
{
physcollision->TraceBox( entRay, MASK_ALL, NULL, pLinkedPortalSimulator->m_DataAccess.Simulation.Static.World.Displacements.pCollideable, pPortalSimulator->m_DataAccess.Placement.ptaap_LinkedToThis.ptOriginTransform, pPortalSimulator->m_DataAccess.Placement.ptaap_LinkedToThis.qAngleTransform, &tempTrace );
if ( tempTrace.startsolid || (tempTrace.fraction < pTrace->fraction) )
{
*pTrace = tempTrace;
}
}
if ( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pCollideable &&
sv_portal_trace_vs_holywall.GetBool() )
{
@ -1717,6 +1756,58 @@ PaintPowerType UTIL_Paint_TracePower(CBaseEntity *pBrushEntity,Vector contactPoi
return NO_POWER;
}
bool UTIL_IsEntityMovingOrRotating( CBaseEntity* pEntity )
{
Vector vLinearVelocity;
AngularImpulse vAngularVelocity;
IPhysicsObject *pEntityPhysicsObject = pEntity->VPhysicsGetObject();
#ifdef GAME_DLL
if ( pEntityPhysicsObject )
{
pEntityPhysicsObject->GetVelocity( &vLinearVelocity, &vAngularVelocity );
}
else
{
pEntity->GetVelocity( &vLinearVelocity, &vAngularVelocity );
}
#else
vLinearVelocity = pEntity->GetAbsVelocity();
// vAngularVelocity = vec3_origin; //TODO: Find client equivalent of server code above for angular impulse
QAngleToAngularImpulse( pEntity->GetLocalAngularVelocity(), vAngularVelocity );
#endif
if ( pEntity->GetAbsVelocity() != vec3_origin )
return true;
//ugh, func_brush attached to an animating entity doesn't give the entity a velocity. Check implicit velocity
if( pEntityPhysicsObject && pEntityPhysicsObject->IsMoveable() )
{
Vector vOtherImplicitVelocity;
pEntityPhysicsObject->GetImplicitVelocity( &vOtherImplicitVelocity, NULL );
if( vOtherImplicitVelocity.LengthSqr() > 1e-1 )
return true;
}
#ifdef GAME_DLL
CBaseEntity *pCheck = pEntity;
while( pCheck )
{
if( pCheck->GetLocalAngularVelocity() != vec3_angle )
return true;
pCheck = pCheck->GetParent();
}
#endif
// don't check for the speed, and check for position offset from when the portal is placed instead.
/*if ( vLinearVelocity.LengthSqr() > 1e-1 || vAngularVelocity.LengthSqr() > 1e-1 )
return true;*/
return false;
}
#ifdef CLIENT_DLL
void UTIL_TransformInterpolatedAngle( CInterpolatedVar< QAngle > &qInterped, matrix3x4_t matTransform, bool bSkipNewest )
{

View File

@ -92,6 +92,7 @@ void UTIL_Portal_NDebugOverlay( const Vector &ptPortalCenter, const QAngle &qPor
void UTIL_Portal_NDebugOverlay( const CProp_Portal *pPortal, int r, int g, int b, int a, bool noDepthTest, float duration );
bool FindClosestPassableSpace( CBaseEntity *pEntity, const Vector &vIndecisivePush, unsigned int fMask = MASK_SOLID ); //assumes the object is already in a mostly passable space
bool UTIL_IsEntityMovingOrRotating( CBaseEntity* pEntity );
bool UTIL_IsPaintableSurface( const csurface_t *surface );
PaintPowerType UTIL_Paint_TracePower(CBaseEntity *pBrushEntity,Vector contactPoint,Vector *vContactNormal);

View File

@ -15,6 +15,36 @@
CUtlVector<CProp_Portal *> CProp_Portal_Shared::AllPortals;
void MobilePortalsUpdatedCallback( IConVar *var, const char *pOldValue, float flOldValue );
ConVar sv_allow_mobile_portals( "sv_allow_mobile_portals", "0", FCVAR_REPLICATED, "", MobilePortalsUpdatedCallback );
void MobilePortalsUpdatedCallback( IConVar *var, const char *pOldValue, float flOldValue )
{
if ( sv_allow_mobile_portals.GetFloat() == flOldValue )
return;
static ConVarRef sv_cheats ( "sv_cheats" );
bool bCheatsAllowed = (sv_cheats.IsValid() && sv_cheats.GetBool() );
if ( !bCheatsAllowed )
{
#ifdef CLIENT_DLL
DevMsg( engine->GetLevelName() );
if ( V_stricmp( engine->GetLevelName(), "sp_a2_bts5" ) == 0 )
#else
if ( V_stricmp( gpGlobals->mapname.ToCStr(), "sp_a2_bts5" ) == 0 )
#endif
{
bCheatsAllowed = true;
}
}
if ( !bCheatsAllowed )
{
var->SetValue( 0 );
}
}
const Vector CProp_Portal_Shared::vLocalMins( 0.0f, -PORTAL_HALF_WIDTH, -PORTAL_HALF_HEIGHT );
const Vector CProp_Portal_Shared::vLocalMaxs( 64.0f, PORTAL_HALF_WIDTH, PORTAL_HALF_HEIGHT );