diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/portal/PortalSimulation.h | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/shared/portal/PortalSimulation.h')
| -rw-r--r-- | game/shared/portal/PortalSimulation.h | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/game/shared/portal/PortalSimulation.h b/game/shared/portal/PortalSimulation.h new file mode 100644 index 0000000..91c6651 --- /dev/null +++ b/game/shared/portal/PortalSimulation.h @@ -0,0 +1,481 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Provides structures and classes necessary to simulate a portal. +// +// $NoKeywords: $ +//=====================================================================================// + +#ifndef PORTALSIMULATION_H +#define PORTALSIMULATION_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/polyhedron.h" +#include "const.h" +#include "tier1/utlmap.h" +#include "tier1/utlvector.h" + +#define PORTAL_SIMULATORS_EMBED_GUID //define this to embed a unique integer with each portal simulator for debugging purposes + +struct StaticPropPolyhedronGroups_t //each static prop is made up of a group of polyhedrons, these help us pull those groups from an array +{ + int iStartIndex; + int iNumPolyhedrons; +}; + +enum PortalSimulationEntityFlags_t +{ + PSEF_OWNS_ENTITY = (1 << 0), //this environment is responsible for the entity's physics objects + PSEF_OWNS_PHYSICS = (1 << 1), + PSEF_IS_IN_PORTAL_HOLE = (1 << 2), //updated per-phyframe + PSEF_CLONES_ENTITY_FROM_MAIN = (1 << 3), //entity is close enough to the portal to affect objects intersecting the portal + //PSEF_HAS_LINKED_CLONE = (1 << 1), //this environment has a clone of the entity which is transformed from its linked portal +}; + +enum PS_PhysicsObjectSourceType_t +{ + PSPOST_LOCAL_BRUSHES, + PSPOST_REMOTE_BRUSHES, + PSPOST_LOCAL_STATICPROPS, + PSPOST_REMOTE_STATICPROPS, + PSPOST_HOLYWALL_TUBE +}; + +struct PortalTransformAsAngledPosition_t //a matrix transformation from this portal to the linked portal, stored as vector and angle transforms +{ + Vector ptOriginTransform; + QAngle qAngleTransform; +}; + +inline bool LessFunc_Integer( const int &a, const int &b ) { return a < b; }; + + +class CPortalSimulatorEventCallbacks //sends out notifications of events to game specific code +{ +public: + virtual void PortalSimulator_TookOwnershipOfEntity( CBaseEntity *pEntity ) { }; + virtual void PortalSimulator_ReleasedOwnershipOfEntity( CBaseEntity *pEntity ) { }; + + virtual void PortalSimulator_TookPhysicsOwnershipOfEntity( CBaseEntity *pEntity ) { }; + virtual void PortalSimulator_ReleasedPhysicsOwnershipOfEntity( CBaseEntity *pEntity ) { }; +}; + +//==================================================================================== +// To any coder trying to understand the following nested structures.... +// +// You may be wondering... why? wtf? +// +// The answer. The previous incarnation of server side portal simulation suffered +// terribly from evolving variables with increasingly cryptic names with no clear +// definition of what part of the system the variable was involved with. +// +// It's my hope that a nested structure with clear boundaries will eliminate that +// horrible, awful, nasty, frustrating confusion. (It was really really bad). This +// system has the added benefit of pseudo-forcing a naming structure. +// +// Lastly, if it all roots in one struct, we can const reference it out to allow +// easy reads without writes +// +// It's broken out like this to solve a few problems.... +// 1. It cleans up intellisense when you don't actually define a structure +// within a structure. +// 2. Shorter typenames when you want to have a pointer/reference deep within +// the nested structure. +// 3. Needed at least one level removed from CPortalSimulator so +// pointers/references could be made while the primary instance of the +// data was private/protected. +// +// It may be slightly difficult to understand in it's broken out structure, but +// intellisense brings all the data together in a very cohesive manner for +// working with. +//==================================================================================== + +struct PS_PlacementData_t //stuff useful for geometric operations +{ + Vector ptCenter; + QAngle qAngles; + Vector vForward; + Vector vUp; + Vector vRight; + VPlane PortalPlane; + VMatrix matThisToLinked; + VMatrix matLinkedToThis; + 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 + PS_PlacementData_t( void ) + { + memset( this, 0, sizeof( PS_PlacementData_t ) ); + } +}; + +struct PS_SD_Static_World_Brushes_t +{ + CUtlVector<CPolyhedron *> Polyhedrons; //the building blocks of more complex collision + CPhysCollide *pCollideable; +#ifndef CLIENT_DLL + IPhysicsObject *pPhysicsObject; + PS_SD_Static_World_Brushes_t() : pCollideable(NULL), pPhysicsObject(NULL) {}; +#else + PS_SD_Static_World_Brushes_t() : pCollideable(NULL) {}; +#endif + +}; + + +struct PS_SD_Static_World_StaticProps_ClippedProp_t +{ + StaticPropPolyhedronGroups_t PolyhedronGroup; + CPhysCollide * pCollide; +#ifndef CLIENT_DLL + IPhysicsObject * pPhysicsObject; +#endif + IHandleEntity * pSourceProp; + + int iTraceContents; + short iTraceSurfaceProps; + static CBaseEntity * pTraceEntity; + static const char * szTraceSurfaceName; //same for all static props, here just for easy reference + static const int iTraceSurfaceFlags; //same for all static props, here just for easy reference +}; + +struct PS_SD_Static_World_StaticProps_t +{ + CUtlVector<CPolyhedron *> Polyhedrons; //the building blocks of more complex collision + CUtlVector<PS_SD_Static_World_StaticProps_ClippedProp_t> ClippedRepresentations; + bool bCollisionExists; //the shortcut to know if collideables exist for each prop + bool bPhysicsExists; //the shortcut to know if physics obects exist for each prop + PS_SD_Static_World_StaticProps_t( void ) : bCollisionExists( false ), bPhysicsExists( false ) { }; +}; + +struct PS_SD_Static_World_t //stuff in front of the portal +{ + PS_SD_Static_World_Brushes_t Brushes; + PS_SD_Static_World_StaticProps_t StaticProps; +}; + +struct PS_SD_Static_Wall_Local_Tube_t //a minimal tube, an object must fit inside this to be eligible for portaling +{ + CUtlVector<CPolyhedron *> Polyhedrons; //the building blocks of more complex collision + CPhysCollide *pCollideable; + +#ifndef CLIENT_DLL + IPhysicsObject *pPhysicsObject; + PS_SD_Static_Wall_Local_Tube_t() : pCollideable(NULL), pPhysicsObject(NULL) {}; +#else + PS_SD_Static_Wall_Local_Tube_t() : pCollideable(NULL) {}; +#endif +}; + +struct PS_SD_Static_Wall_Local_Brushes_t +{ + CUtlVector<CPolyhedron *> Polyhedrons; //the building blocks of more complex collision + CPhysCollide *pCollideable; + +#ifndef CLIENT_DLL + IPhysicsObject *pPhysicsObject; + PS_SD_Static_Wall_Local_Brushes_t() : pCollideable(NULL), pPhysicsObject(NULL) {}; +#else + PS_SD_Static_Wall_Local_Brushes_t() : pCollideable(NULL) {}; +#endif +}; + +struct PS_SD_Static_Wall_Local_t //things in the wall that are completely independant of having a linked portal +{ + PS_SD_Static_Wall_Local_Tube_t Tube; + PS_SD_Static_Wall_Local_Brushes_t Brushes; +}; + +struct PS_SD_Static_Wall_RemoteTransformedToLocal_Brushes_t +{ + IPhysicsObject *pPhysicsObject; + PS_SD_Static_Wall_RemoteTransformedToLocal_Brushes_t() : pPhysicsObject(NULL) {}; +}; + +struct PS_SD_Static_Wall_RemoteTransformedToLocal_StaticProps_t +{ + CUtlVector<IPhysicsObject *> PhysicsObjects; +}; + +struct PS_SD_Static_Wall_RemoteTransformedToLocal_t //things taken from the linked portal's "World" collision and transformed into local space +{ + PS_SD_Static_Wall_RemoteTransformedToLocal_Brushes_t Brushes; + PS_SD_Static_Wall_RemoteTransformedToLocal_StaticProps_t StaticProps; +}; + +struct PS_SD_Static_Wall_t //stuff behind the portal +{ + PS_SD_Static_Wall_Local_t Local; +#ifndef CLIENT_DLL + PS_SD_Static_Wall_RemoteTransformedToLocal_t RemoteTransformedToLocal; +#endif +}; + +struct PS_SD_Static_SurfaceProperties_t //surface properties to pretend every collideable here is using +{ + int contents; + csurface_t surface; + CBaseEntity *pEntity; +}; + +struct PS_SD_Static_t //stuff that doesn't move around +{ + PS_SD_Static_World_t World; + PS_SD_Static_Wall_t Wall; + PS_SD_Static_SurfaceProperties_t SurfaceProperties; +}; + +class CPhysicsShadowClone; + +struct PS_SD_Dynamic_PhysicsShadowClones_t +{ + CUtlVector<CBaseEntity *> ShouldCloneFromMain; //a list of entities that should be cloned from main if physics simulation is enabled + //in single-environment mode, this helps us track who should collide with who + + CUtlVector<CPhysicsShadowClone *> FromLinkedPortal; +}; + +struct PS_SD_Dynamic_t //stuff that moves around +{ + unsigned int EntFlags[MAX_EDICTS]; //flags maintained for every entity in the world based on its index + + PS_SD_Dynamic_PhysicsShadowClones_t ShadowClones; + + CUtlVector<CBaseEntity *> OwnedEntities; + + PS_SD_Dynamic_t() + { + memset( EntFlags, 0, sizeof( EntFlags ) ); + } +}; + +class CPSCollisionEntity; + +struct PS_SimulationData_t //compartmentalized data for coherent management +{ + PS_SD_Static_t Static; + +#ifndef CLIENT_DLL + PS_SD_Dynamic_t Dynamic; + + IPhysicsEnvironment *pPhysicsEnvironment; + CPSCollisionEntity *pCollisionEntity; //the entity we'll be tying physics objects to for collision + + PS_SimulationData_t() : pPhysicsEnvironment(NULL), pCollisionEntity(NULL) {}; +#endif +}; + +struct PS_InternalData_t +{ + PS_PlacementData_t Placement; + PS_SimulationData_t Simulation; +}; + + +class CPortalSimulator +{ +public: + CPortalSimulator( void ); + ~CPortalSimulator( void ); + + void MoveTo( const Vector &ptCenter, const QAngle &angles ); + void ClearEverything( void ); + + void AttachTo( CPortalSimulator *pLinkedPortalSimulator ); + void DetachFromLinked( void ); //detach portals to sever the connection, saves work when planning on moving both portals + CPortalSimulator *GetLinkedPortalSimulator( void ) const; + + void SetPortalSimulatorCallbacks( CPortalSimulatorEventCallbacks *pCallbacks ); + + bool IsReadyToSimulate( void ) const; //is active and linked to another portal + + void SetCollisionGenerationEnabled( bool bEnabled ); //enable/disable collision generation for the hole in the wall, needed for proper vphysics simulation + bool IsCollisionGenerationEnabled( void ) const; + + void SetVPhysicsSimulationEnabled( bool bEnabled ); //enable/disable vphysics simulation. Will automatically update the linked portal to be the same + bool IsSimulatingVPhysics( void ) const; //this portal is setup to handle any physically simulated object, false means the portal is handling player movement only + + bool EntityIsInPortalHole( CBaseEntity *pEntity ) const; //true if the entity is within the portal cutout bounds and crossing the plane. Not just *near* the portal + bool EntityHitBoxExtentIsInPortalHole( CBaseAnimating *pBaseAnimating ) const; //true if the entity is within the portal cutout bounds and crossing the plane. Not just *near* the portal + void RemoveEntityFromPortalHole( CBaseEntity *pEntity ); //if the entity is in the portal hole, this forcibly moves it out by any means possible + + bool RayIsInPortalHole( const Ray_t &ray ) const; //traces a ray against the same detector for EntityIsInPortalHole(), bias is towards false positives + +#ifndef CLIENT_DLL + int GetMoveableOwnedEntities( CBaseEntity **pEntsOut, int iEntOutLimit ); //gets owned entities that aren't either world or static props. Excludes fake portal ents such as physics clones + + static CPortalSimulator *GetSimulatorThatOwnsEntity( const CBaseEntity *pEntity ); //fairly cheap to call + static CPortalSimulator *GetSimulatorThatCreatedPhysicsObject( const IPhysicsObject *pObject, PS_PhysicsObjectSourceType_t *pOut_SourceType = NULL ); + static void Pre_UTIL_Remove( CBaseEntity *pEntity ); + static void Post_UTIL_Remove( CBaseEntity *pEntity ); + + //these three really should be made internal and the public interface changed to a "watch this entity" setup + void TakeOwnershipOfEntity( CBaseEntity *pEntity ); //general ownership, not necessarily physics ownership + void ReleaseOwnershipOfEntity( CBaseEntity *pEntity, bool bMovingToLinkedSimulator = false ); //if bMovingToLinkedSimulator is true, the code skips some steps that are going to be repeated when the entity is added to the other simulator + void ReleaseAllEntityOwnership( void ); //go back to not owning any entities + + //void TeleportEntityToLinkedPortal( CBaseEntity *pEntity ); + void StartCloningEntity( CBaseEntity *pEntity ); + void StopCloningEntity( CBaseEntity *pEntity ); + + bool OwnsEntity( const CBaseEntity *pEntity ) const; + bool OwnsPhysicsForEntity( const CBaseEntity *pEntity ) const; + + bool CreatedPhysicsObject( const IPhysicsObject *pObject, PS_PhysicsObjectSourceType_t *pOut_SourceType = NULL ) const; //true if the physics object was generated by this portal simulator + + static void PrePhysFrame( void ); + static void PostPhysFrame( void ); + +#endif //#ifndef CLIENT_DLL + +#ifdef PORTAL_SIMULATORS_EMBED_GUID + int GetPortalSimulatorGUID( void ) const { return m_iPortalSimulatorGUID; }; +#endif + +protected: + bool m_bLocalDataIsReady; //this side of the portal is properly setup, no guarantees as to linkage to another portal + bool m_bSimulateVPhysics; + bool m_bGenerateCollision; + bool m_bSharedCollisionConfiguration; //when portals are in certain configurations, they need to cross-clip and share some collision data and things get nasty. For the love of all that is holy, pray that this is false. + CPortalSimulator *m_pLinkedPortal; + bool m_bInCrossLinkedFunction; //A flag to mark that we're already in a linked function and that the linked portal shouldn't call our side + CPortalSimulatorEventCallbacks *m_pCallbacks; +#ifdef PORTAL_SIMULATORS_EMBED_GUID + int m_iPortalSimulatorGUID; +#endif + + struct + { + bool bPolyhedronsGenerated; + bool bLocalCollisionGenerated; + bool bLinkedCollisionGenerated; + bool bLocalPhysicsGenerated; + bool bLinkedPhysicsGenerated; + } m_CreationChecklist; + + friend class CPSCollisionEntity; + +#ifndef CLIENT_DLL //physics handled purely by server side + void TakePhysicsOwnership( CBaseEntity *pEntity ); + void ReleasePhysicsOwnership( CBaseEntity *pEntity, bool bContinuePhysicsCloning = true, bool bMovingToLinkedSimulator = false ); + + void CreateAllPhysics( void ); + void CreateMinimumPhysics( void ); //stuff needed by any part of physics simulations + void CreateLocalPhysics( void ); + void CreateLinkedPhysics( void ); + + void ClearAllPhysics( void ); + void ClearMinimumPhysics( void ); + void ClearLocalPhysics( void ); + void ClearLinkedPhysics( void ); + + void ClearLinkedEntities( void ); //gets rid of transformed shadow clones +#endif + + void CreateAllCollision( void ); + void CreateLocalCollision( void ); + void CreateLinkedCollision( void ); + + void ClearAllCollision( void ); + void ClearLinkedCollision( void ); + void ClearLocalCollision( void ); + + void CreatePolyhedrons( void ); //carves up the world around the portal's position into sets of polyhedrons + void ClearPolyhedrons( void ); + + void UpdateLinkMatrix( void ); + + void MarkAsOwned( CBaseEntity *pEntity ); + void MarkAsReleased( CBaseEntity *pEntity ); + + PS_InternalData_t m_InternalData; + +public: + const PS_InternalData_t &m_DataAccess; + + friend class CPS_AutoGameSys_EntityListener; +}; + +extern CUtlVector<CPortalSimulator *> const &g_PortalSimulators; + + +#ifndef CLIENT_DLL +class CPSCollisionEntity : public CBaseEntity +{ + DECLARE_CLASS( CPSCollisionEntity, CBaseEntity ); +private: + CPortalSimulator *m_pOwningSimulator; + +public: + CPSCollisionEntity( void ); + virtual ~CPSCollisionEntity( void ); + + virtual void Spawn( void ); + virtual void Activate( void ); + virtual int ObjectCaps( void ); + virtual IPhysicsObject *VPhysicsGetObject( void ); + virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); + virtual void UpdateOnRemove( void ); + virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const; + virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ) {} + virtual void VPhysicsFriction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit ) {} + + static bool IsPortalSimulatorCollisionEntity( const CBaseEntity *pEntity ); + friend class CPortalSimulator; +}; +#endif + + + + + + + + + + + + + + + + +#ifndef CLIENT_DLL +inline bool CPortalSimulator::OwnsEntity( const CBaseEntity *pEntity ) const +{ + return ((m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_OWNS_ENTITY) != 0); +} + +inline bool CPortalSimulator::OwnsPhysicsForEntity( const CBaseEntity *pEntity ) const +{ + return ((m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_OWNS_PHYSICS) != 0); +} +#endif + +inline bool CPortalSimulator::IsReadyToSimulate( void ) const +{ + return m_bLocalDataIsReady && m_pLinkedPortal && m_pLinkedPortal->m_bLocalDataIsReady; +} + +inline bool CPortalSimulator::IsSimulatingVPhysics( void ) const +{ + return m_bSimulateVPhysics; +} + +inline bool CPortalSimulator::IsCollisionGenerationEnabled( void ) const +{ + return m_bGenerateCollision; +} + +inline CPortalSimulator *CPortalSimulator::GetLinkedPortalSimulator( void ) const +{ + return m_pLinkedPortal; +} + + + + +#endif //#ifndef PORTALSIMULATION_H + |