From b2110d035420085cb6042e80e863d86f554f4188 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 21 Nov 2022 00:51:54 -0600 Subject: [PATCH] Added NPC PVS checking for point_cameras --- sp/src/game/server/ai_basenpc.cpp | 7 ++++ sp/src/game/server/point_camera.cpp | 52 +++++++++++++++++++++++++++++ sp/src/game/server/point_camera.h | 5 +++ 3 files changed, 64 insertions(+) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index c503a09c..299aa5c4 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -98,6 +98,7 @@ #ifdef MAPBASE #include "mapbase/matchers.h" #include "items.h" +#include "point_camera.h" #endif #ifdef MAPBASE_VSCRIPT @@ -4301,6 +4302,12 @@ bool CAI_BaseNPC::CheckPVSCondition() { bool bInPVS = ( UTIL_FindClientInPVS( edict() ) != NULL ) || (UTIL_ClientPVSIsExpanded() && UTIL_FindClientInVisibilityPVS( edict() )); +#ifdef MAPBASE + // We can be in a player's PVS if there is an active point_camera nearby (fixes issues with choreo) + if (!bInPVS && UTIL_FindRTCameraInEntityPVS( edict() )) + bInPVS = true; +#endif + if ( bInPVS ) SetCondition( COND_IN_PVS ); else diff --git a/sp/src/game/server/point_camera.cpp b/sp/src/game/server/point_camera.cpp index 626bc61b..72a40b26 100644 --- a/sp/src/game/server/point_camera.cpp +++ b/sp/src/game/server/point_camera.cpp @@ -28,6 +28,58 @@ CPointCamera* GetPointCameraList() return g_PointCameraList.m_pClassList; } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Returns true if a camera is in the PVS of the specified entity +//----------------------------------------------------------------------------- +edict_t *UTIL_FindRTCameraInEntityPVS( edict_t *pEdict ) +{ + CBaseEntity *pe = GetContainingEntity( pEdict ); + if ( !pe ) + return NULL; + + bool bGotPVS = false; + Vector org; + static byte pvs[ MAX_MAP_CLUSTERS/8 ]; + static int pvssize = sizeof( pvs ); + + for ( CPointCamera *pCameraEnt = GetPointCameraList(); pCameraEnt != NULL; pCameraEnt = pCameraEnt->m_pNext ) + { + if (!pCameraEnt->IsActive()) + continue; + + if (!bGotPVS) + { + // Getting the PVS during the loop like this makes sure we only get the PVS if there's actually an active camera in the level + org = pe->EyePosition(); + int clusterIndex = engine->GetClusterForOrigin( org ); + Assert( clusterIndex >= 0 ); + engine->GetPVSForCluster( clusterIndex, pvssize, pvs ); + bGotPVS = true; + } + + Vector vecCameraEye = pCameraEnt->EyePosition(); + + Vector vecCameraDirection; + pCameraEnt->GetVectors( &vecCameraDirection, NULL, NULL ); + + Vector los = (org - vecCameraEye); + float flDot = DotProduct( los, vecCameraDirection ); + + // Make sure we're in the camera's FOV before checking PVS + if ( flDot <= cos( DEG2RAD( pCameraEnt->GetFOV() / 2 ) ) ) + continue; + + if ( engine->CheckOriginInPVS( vecCameraEye, pvs, pvssize ) ) + { + return pCameraEnt->edict(); + } + } + + return NULL; +} +#endif + // These are already built into CBaseEntity // DEFINE_KEYFIELD( m_iName, FIELD_STRING, "targetname" ), // DEFINE_KEYFIELD( m_iParent, FIELD_STRING, "parentname" ), diff --git a/sp/src/game/server/point_camera.h b/sp/src/game/server/point_camera.h index c669ab82..9cb7d3c4 100644 --- a/sp/src/game/server/point_camera.h +++ b/sp/src/game/server/point_camera.h @@ -42,6 +42,7 @@ public: void InputSetRenderTarget( inputdata_t &inputdata ) { m_iszRenderTarget = inputdata.value.StringID(); } float GetFOV() const { return m_FOV; } + bool IsActive() const { return m_bIsOn; } #endif private: @@ -117,4 +118,8 @@ private: #endif CPointCamera *GetPointCameraList(); + +#ifdef MAPBASE +edict_t *UTIL_FindRTCameraInEntityPVS( edict_t *pEdict ); +#endif #endif // CAMERA_H