Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

481 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Provides structures and classes necessary to simulate a portal.
  4. //
  5. // $NoKeywords: $
  6. //=====================================================================================//
  7. #ifndef PORTALSIMULATION_H
  8. #define PORTALSIMULATION_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "mathlib/polyhedron.h"
  13. #include "const.h"
  14. #include "tier1/utlmap.h"
  15. #include "tier1/utlvector.h"
  16. #define PORTAL_SIMULATORS_EMBED_GUID //define this to embed a unique integer with each portal simulator for debugging purposes
  17. struct StaticPropPolyhedronGroups_t //each static prop is made up of a group of polyhedrons, these help us pull those groups from an array
  18. {
  19. int iStartIndex;
  20. int iNumPolyhedrons;
  21. };
  22. enum PortalSimulationEntityFlags_t
  23. {
  24. PSEF_OWNS_ENTITY = (1 << 0), //this environment is responsible for the entity's physics objects
  25. PSEF_OWNS_PHYSICS = (1 << 1),
  26. PSEF_IS_IN_PORTAL_HOLE = (1 << 2), //updated per-phyframe
  27. PSEF_CLONES_ENTITY_FROM_MAIN = (1 << 3), //entity is close enough to the portal to affect objects intersecting the portal
  28. //PSEF_HAS_LINKED_CLONE = (1 << 1), //this environment has a clone of the entity which is transformed from its linked portal
  29. };
  30. enum PS_PhysicsObjectSourceType_t
  31. {
  32. PSPOST_LOCAL_BRUSHES,
  33. PSPOST_REMOTE_BRUSHES,
  34. PSPOST_LOCAL_STATICPROPS,
  35. PSPOST_REMOTE_STATICPROPS,
  36. PSPOST_HOLYWALL_TUBE
  37. };
  38. struct PortalTransformAsAngledPosition_t //a matrix transformation from this portal to the linked portal, stored as vector and angle transforms
  39. {
  40. Vector ptOriginTransform;
  41. QAngle qAngleTransform;
  42. };
  43. inline bool LessFunc_Integer( const int &a, const int &b ) { return a < b; };
  44. class CPortalSimulatorEventCallbacks //sends out notifications of events to game specific code
  45. {
  46. public:
  47. virtual void PortalSimulator_TookOwnershipOfEntity( CBaseEntity *pEntity ) { };
  48. virtual void PortalSimulator_ReleasedOwnershipOfEntity( CBaseEntity *pEntity ) { };
  49. virtual void PortalSimulator_TookPhysicsOwnershipOfEntity( CBaseEntity *pEntity ) { };
  50. virtual void PortalSimulator_ReleasedPhysicsOwnershipOfEntity( CBaseEntity *pEntity ) { };
  51. };
  52. //====================================================================================
  53. // To any coder trying to understand the following nested structures....
  54. //
  55. // You may be wondering... why? wtf?
  56. //
  57. // The answer. The previous incarnation of server side portal simulation suffered
  58. // terribly from evolving variables with increasingly cryptic names with no clear
  59. // definition of what part of the system the variable was involved with.
  60. //
  61. // It's my hope that a nested structure with clear boundaries will eliminate that
  62. // horrible, awful, nasty, frustrating confusion. (It was really really bad). This
  63. // system has the added benefit of pseudo-forcing a naming structure.
  64. //
  65. // Lastly, if it all roots in one struct, we can const reference it out to allow
  66. // easy reads without writes
  67. //
  68. // It's broken out like this to solve a few problems....
  69. // 1. It cleans up intellisense when you don't actually define a structure
  70. // within a structure.
  71. // 2. Shorter typenames when you want to have a pointer/reference deep within
  72. // the nested structure.
  73. // 3. Needed at least one level removed from CPortalSimulator so
  74. // pointers/references could be made while the primary instance of the
  75. // data was private/protected.
  76. //
  77. // It may be slightly difficult to understand in it's broken out structure, but
  78. // intellisense brings all the data together in a very cohesive manner for
  79. // working with.
  80. //====================================================================================
  81. struct PS_PlacementData_t //stuff useful for geometric operations
  82. {
  83. Vector ptCenter;
  84. QAngle qAngles;
  85. Vector vForward;
  86. Vector vUp;
  87. Vector vRight;
  88. VPlane PortalPlane;
  89. VMatrix matThisToLinked;
  90. VMatrix matLinkedToThis;
  91. PortalTransformAsAngledPosition_t ptaap_ThisToLinked;
  92. PortalTransformAsAngledPosition_t ptaap_LinkedToThis;
  93. CPhysCollide *pHoleShapeCollideable; //used to test if a collideable is in the hole, should NOT be collided against in general
  94. PS_PlacementData_t( void )
  95. {
  96. memset( this, 0, sizeof( PS_PlacementData_t ) );
  97. }
  98. };
  99. struct PS_SD_Static_World_Brushes_t
  100. {
  101. CUtlVector<CPolyhedron *> Polyhedrons; //the building blocks of more complex collision
  102. CPhysCollide *pCollideable;
  103. #ifndef CLIENT_DLL
  104. IPhysicsObject *pPhysicsObject;
  105. PS_SD_Static_World_Brushes_t() : pCollideable(NULL), pPhysicsObject(NULL) {};
  106. #else
  107. PS_SD_Static_World_Brushes_t() : pCollideable(NULL) {};
  108. #endif
  109. };
  110. struct PS_SD_Static_World_StaticProps_ClippedProp_t
  111. {
  112. StaticPropPolyhedronGroups_t PolyhedronGroup;
  113. CPhysCollide * pCollide;
  114. #ifndef CLIENT_DLL
  115. IPhysicsObject * pPhysicsObject;
  116. #endif
  117. IHandleEntity * pSourceProp;
  118. int iTraceContents;
  119. short iTraceSurfaceProps;
  120. static CBaseEntity * pTraceEntity;
  121. static const char * szTraceSurfaceName; //same for all static props, here just for easy reference
  122. static const int iTraceSurfaceFlags; //same for all static props, here just for easy reference
  123. };
  124. struct PS_SD_Static_World_StaticProps_t
  125. {
  126. CUtlVector<CPolyhedron *> Polyhedrons; //the building blocks of more complex collision
  127. CUtlVector<PS_SD_Static_World_StaticProps_ClippedProp_t> ClippedRepresentations;
  128. bool bCollisionExists; //the shortcut to know if collideables exist for each prop
  129. bool bPhysicsExists; //the shortcut to know if physics obects exist for each prop
  130. PS_SD_Static_World_StaticProps_t( void ) : bCollisionExists( false ), bPhysicsExists( false ) { };
  131. };
  132. struct PS_SD_Static_World_t //stuff in front of the portal
  133. {
  134. PS_SD_Static_World_Brushes_t Brushes;
  135. PS_SD_Static_World_StaticProps_t StaticProps;
  136. };
  137. struct PS_SD_Static_Wall_Local_Tube_t //a minimal tube, an object must fit inside this to be eligible for portaling
  138. {
  139. CUtlVector<CPolyhedron *> Polyhedrons; //the building blocks of more complex collision
  140. CPhysCollide *pCollideable;
  141. #ifndef CLIENT_DLL
  142. IPhysicsObject *pPhysicsObject;
  143. PS_SD_Static_Wall_Local_Tube_t() : pCollideable(NULL), pPhysicsObject(NULL) {};
  144. #else
  145. PS_SD_Static_Wall_Local_Tube_t() : pCollideable(NULL) {};
  146. #endif
  147. };
  148. struct PS_SD_Static_Wall_Local_Brushes_t
  149. {
  150. CUtlVector<CPolyhedron *> Polyhedrons; //the building blocks of more complex collision
  151. CPhysCollide *pCollideable;
  152. #ifndef CLIENT_DLL
  153. IPhysicsObject *pPhysicsObject;
  154. PS_SD_Static_Wall_Local_Brushes_t() : pCollideable(NULL), pPhysicsObject(NULL) {};
  155. #else
  156. PS_SD_Static_Wall_Local_Brushes_t() : pCollideable(NULL) {};
  157. #endif
  158. };
  159. struct PS_SD_Static_Wall_Local_t //things in the wall that are completely independant of having a linked portal
  160. {
  161. PS_SD_Static_Wall_Local_Tube_t Tube;
  162. PS_SD_Static_Wall_Local_Brushes_t Brushes;
  163. };
  164. struct PS_SD_Static_Wall_RemoteTransformedToLocal_Brushes_t
  165. {
  166. IPhysicsObject *pPhysicsObject;
  167. PS_SD_Static_Wall_RemoteTransformedToLocal_Brushes_t() : pPhysicsObject(NULL) {};
  168. };
  169. struct PS_SD_Static_Wall_RemoteTransformedToLocal_StaticProps_t
  170. {
  171. CUtlVector<IPhysicsObject *> PhysicsObjects;
  172. };
  173. struct PS_SD_Static_Wall_RemoteTransformedToLocal_t //things taken from the linked portal's "World" collision and transformed into local space
  174. {
  175. PS_SD_Static_Wall_RemoteTransformedToLocal_Brushes_t Brushes;
  176. PS_SD_Static_Wall_RemoteTransformedToLocal_StaticProps_t StaticProps;
  177. };
  178. struct PS_SD_Static_Wall_t //stuff behind the portal
  179. {
  180. PS_SD_Static_Wall_Local_t Local;
  181. #ifndef CLIENT_DLL
  182. PS_SD_Static_Wall_RemoteTransformedToLocal_t RemoteTransformedToLocal;
  183. #endif
  184. };
  185. struct PS_SD_Static_SurfaceProperties_t //surface properties to pretend every collideable here is using
  186. {
  187. int contents;
  188. csurface_t surface;
  189. CBaseEntity *pEntity;
  190. };
  191. struct PS_SD_Static_t //stuff that doesn't move around
  192. {
  193. PS_SD_Static_World_t World;
  194. PS_SD_Static_Wall_t Wall;
  195. PS_SD_Static_SurfaceProperties_t SurfaceProperties;
  196. };
  197. class CPhysicsShadowClone;
  198. struct PS_SD_Dynamic_PhysicsShadowClones_t
  199. {
  200. CUtlVector<CBaseEntity *> ShouldCloneFromMain; //a list of entities that should be cloned from main if physics simulation is enabled
  201. //in single-environment mode, this helps us track who should collide with who
  202. CUtlVector<CPhysicsShadowClone *> FromLinkedPortal;
  203. };
  204. struct PS_SD_Dynamic_t //stuff that moves around
  205. {
  206. unsigned int EntFlags[MAX_EDICTS]; //flags maintained for every entity in the world based on its index
  207. PS_SD_Dynamic_PhysicsShadowClones_t ShadowClones;
  208. CUtlVector<CBaseEntity *> OwnedEntities;
  209. PS_SD_Dynamic_t()
  210. {
  211. memset( EntFlags, 0, sizeof( EntFlags ) );
  212. }
  213. };
  214. class CPSCollisionEntity;
  215. struct PS_SimulationData_t //compartmentalized data for coherent management
  216. {
  217. PS_SD_Static_t Static;
  218. #ifndef CLIENT_DLL
  219. PS_SD_Dynamic_t Dynamic;
  220. IPhysicsEnvironment *pPhysicsEnvironment;
  221. CPSCollisionEntity *pCollisionEntity; //the entity we'll be tying physics objects to for collision
  222. PS_SimulationData_t() : pPhysicsEnvironment(NULL), pCollisionEntity(NULL) {};
  223. #endif
  224. };
  225. struct PS_InternalData_t
  226. {
  227. PS_PlacementData_t Placement;
  228. PS_SimulationData_t Simulation;
  229. };
  230. class CPortalSimulator
  231. {
  232. public:
  233. CPortalSimulator( void );
  234. ~CPortalSimulator( void );
  235. void MoveTo( const Vector &ptCenter, const QAngle &angles );
  236. void ClearEverything( void );
  237. void AttachTo( CPortalSimulator *pLinkedPortalSimulator );
  238. void DetachFromLinked( void ); //detach portals to sever the connection, saves work when planning on moving both portals
  239. CPortalSimulator *GetLinkedPortalSimulator( void ) const;
  240. void SetPortalSimulatorCallbacks( CPortalSimulatorEventCallbacks *pCallbacks );
  241. bool IsReadyToSimulate( void ) const; //is active and linked to another portal
  242. void SetCollisionGenerationEnabled( bool bEnabled ); //enable/disable collision generation for the hole in the wall, needed for proper vphysics simulation
  243. bool IsCollisionGenerationEnabled( void ) const;
  244. void SetVPhysicsSimulationEnabled( bool bEnabled ); //enable/disable vphysics simulation. Will automatically update the linked portal to be the same
  245. bool IsSimulatingVPhysics( void ) const; //this portal is setup to handle any physically simulated object, false means the portal is handling player movement only
  246. bool EntityIsInPortalHole( CBaseEntity *pEntity ) const; //true if the entity is within the portal cutout bounds and crossing the plane. Not just *near* the portal
  247. bool EntityHitBoxExtentIsInPortalHole( CBaseAnimating *pBaseAnimating ) const; //true if the entity is within the portal cutout bounds and crossing the plane. Not just *near* the portal
  248. void RemoveEntityFromPortalHole( CBaseEntity *pEntity ); //if the entity is in the portal hole, this forcibly moves it out by any means possible
  249. bool RayIsInPortalHole( const Ray_t &ray ) const; //traces a ray against the same detector for EntityIsInPortalHole(), bias is towards false positives
  250. #ifndef CLIENT_DLL
  251. 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
  252. static CPortalSimulator *GetSimulatorThatOwnsEntity( const CBaseEntity *pEntity ); //fairly cheap to call
  253. static CPortalSimulator *GetSimulatorThatCreatedPhysicsObject( const IPhysicsObject *pObject, PS_PhysicsObjectSourceType_t *pOut_SourceType = NULL );
  254. static void Pre_UTIL_Remove( CBaseEntity *pEntity );
  255. static void Post_UTIL_Remove( CBaseEntity *pEntity );
  256. //these three really should be made internal and the public interface changed to a "watch this entity" setup
  257. void TakeOwnershipOfEntity( CBaseEntity *pEntity ); //general ownership, not necessarily physics ownership
  258. 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
  259. void ReleaseAllEntityOwnership( void ); //go back to not owning any entities
  260. //void TeleportEntityToLinkedPortal( CBaseEntity *pEntity );
  261. void StartCloningEntity( CBaseEntity *pEntity );
  262. void StopCloningEntity( CBaseEntity *pEntity );
  263. bool OwnsEntity( const CBaseEntity *pEntity ) const;
  264. bool OwnsPhysicsForEntity( const CBaseEntity *pEntity ) const;
  265. bool CreatedPhysicsObject( const IPhysicsObject *pObject, PS_PhysicsObjectSourceType_t *pOut_SourceType = NULL ) const; //true if the physics object was generated by this portal simulator
  266. static void PrePhysFrame( void );
  267. static void PostPhysFrame( void );
  268. #endif //#ifndef CLIENT_DLL
  269. #ifdef PORTAL_SIMULATORS_EMBED_GUID
  270. int GetPortalSimulatorGUID( void ) const { return m_iPortalSimulatorGUID; };
  271. #endif
  272. protected:
  273. bool m_bLocalDataIsReady; //this side of the portal is properly setup, no guarantees as to linkage to another portal
  274. bool m_bSimulateVPhysics;
  275. bool m_bGenerateCollision;
  276. 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.
  277. CPortalSimulator *m_pLinkedPortal;
  278. 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
  279. CPortalSimulatorEventCallbacks *m_pCallbacks;
  280. #ifdef PORTAL_SIMULATORS_EMBED_GUID
  281. int m_iPortalSimulatorGUID;
  282. #endif
  283. struct
  284. {
  285. bool bPolyhedronsGenerated;
  286. bool bLocalCollisionGenerated;
  287. bool bLinkedCollisionGenerated;
  288. bool bLocalPhysicsGenerated;
  289. bool bLinkedPhysicsGenerated;
  290. } m_CreationChecklist;
  291. friend class CPSCollisionEntity;
  292. #ifndef CLIENT_DLL //physics handled purely by server side
  293. void TakePhysicsOwnership( CBaseEntity *pEntity );
  294. void ReleasePhysicsOwnership( CBaseEntity *pEntity, bool bContinuePhysicsCloning = true, bool bMovingToLinkedSimulator = false );
  295. void CreateAllPhysics( void );
  296. void CreateMinimumPhysics( void ); //stuff needed by any part of physics simulations
  297. void CreateLocalPhysics( void );
  298. void CreateLinkedPhysics( void );
  299. void ClearAllPhysics( void );
  300. void ClearMinimumPhysics( void );
  301. void ClearLocalPhysics( void );
  302. void ClearLinkedPhysics( void );
  303. void ClearLinkedEntities( void ); //gets rid of transformed shadow clones
  304. #endif
  305. void CreateAllCollision( void );
  306. void CreateLocalCollision( void );
  307. void CreateLinkedCollision( void );
  308. void ClearAllCollision( void );
  309. void ClearLinkedCollision( void );
  310. void ClearLocalCollision( void );
  311. void CreatePolyhedrons( void ); //carves up the world around the portal's position into sets of polyhedrons
  312. void ClearPolyhedrons( void );
  313. void UpdateLinkMatrix( void );
  314. void MarkAsOwned( CBaseEntity *pEntity );
  315. void MarkAsReleased( CBaseEntity *pEntity );
  316. PS_InternalData_t m_InternalData;
  317. public:
  318. const PS_InternalData_t &m_DataAccess;
  319. friend class CPS_AutoGameSys_EntityListener;
  320. };
  321. extern CUtlVector<CPortalSimulator *> const &g_PortalSimulators;
  322. #ifndef CLIENT_DLL
  323. class CPSCollisionEntity : public CBaseEntity
  324. {
  325. DECLARE_CLASS( CPSCollisionEntity, CBaseEntity );
  326. private:
  327. CPortalSimulator *m_pOwningSimulator;
  328. public:
  329. CPSCollisionEntity( void );
  330. virtual ~CPSCollisionEntity( void );
  331. virtual void Spawn( void );
  332. virtual void Activate( void );
  333. virtual int ObjectCaps( void );
  334. virtual IPhysicsObject *VPhysicsGetObject( void );
  335. virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax );
  336. virtual void UpdateOnRemove( void );
  337. virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const;
  338. virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ) {}
  339. virtual void VPhysicsFriction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit ) {}
  340. static bool IsPortalSimulatorCollisionEntity( const CBaseEntity *pEntity );
  341. friend class CPortalSimulator;
  342. };
  343. #endif
  344. #ifndef CLIENT_DLL
  345. inline bool CPortalSimulator::OwnsEntity( const CBaseEntity *pEntity ) const
  346. {
  347. return ((m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_OWNS_ENTITY) != 0);
  348. }
  349. inline bool CPortalSimulator::OwnsPhysicsForEntity( const CBaseEntity *pEntity ) const
  350. {
  351. return ((m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_OWNS_PHYSICS) != 0);
  352. }
  353. #endif
  354. inline bool CPortalSimulator::IsReadyToSimulate( void ) const
  355. {
  356. return m_bLocalDataIsReady && m_pLinkedPortal && m_pLinkedPortal->m_bLocalDataIsReady;
  357. }
  358. inline bool CPortalSimulator::IsSimulatingVPhysics( void ) const
  359. {
  360. return m_bSimulateVPhysics;
  361. }
  362. inline bool CPortalSimulator::IsCollisionGenerationEnabled( void ) const
  363. {
  364. return m_bGenerateCollision;
  365. }
  366. inline CPortalSimulator *CPortalSimulator::GetLinkedPortalSimulator( void ) const
  367. {
  368. return m_pLinkedPortal;
  369. }
  370. #endif //#ifndef PORTALSIMULATION_H