//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Pulling CCollisionEvent's definition out of physics.cpp so it can be // abstracted upon (for the portal mod) // // // $Workfile: $ // $Date: $ // $NoKeywords: $ //=============================================================================// #ifndef PHYSICS_COLLISIONEVENT_H #define PHYSICS_COLLISIONEVENT_H #ifdef _WIN32 #pragma once #endif #include "physics.h" #include "tier1/callqueue.h" extern CCallQueue g_PostSimulationQueue; struct damageevent_t { CBaseEntity *pEntity; IPhysicsObject *pInflictorPhysics; CTakeDamageInfo info; bool bRestoreVelocity; }; struct inflictorstate_t { Vector savedVelocity; AngularImpulse savedAngularVelocity; IPhysicsObject *pInflictorPhysics; float otherMassMax; short nextIndex; short restored; }; enum { COLLSTATE_ENABLED = 0, COLLSTATE_TRYDISABLE = 1, COLLSTATE_TRYNPCSOLVER = 2, COLLSTATE_TRYENTITYSOLVER = 3, COLLSTATE_DISABLED = 4 }; struct penetrateevent_t { EHANDLE hEntity0; EHANDLE hEntity1; float startTime; float timeStamp; int collisionState; }; class CCollisionEvent : public IPhysicsCollisionEvent, public IPhysicsCollisionSolver, public IPhysicsObjectEvent { public: CCollisionEvent(); friction_t *FindFriction(CBaseEntity *pObject); void ShutdownFriction(friction_t &friction); void FrameUpdate(); void LevelShutdown(void); // IPhysicsCollisionEvent void PreCollision(vcollisionevent_t *pEvent); void PostCollision(vcollisionevent_t *pEvent); void Friction(IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit, IPhysicsCollisionData *pData); void StartTouch(IPhysicsObject *pObject1, IPhysicsObject *pObject2, IPhysicsCollisionData *pTouchData); void EndTouch(IPhysicsObject *pObject1, IPhysicsObject *pObject2, IPhysicsCollisionData *pTouchData); void FluidStartTouch(IPhysicsObject *pObject, IPhysicsFluidController *pFluid); void FluidEndTouch(IPhysicsObject *pObject, IPhysicsFluidController *pFluid); void PostSimulationFrame(); void ObjectEnterTrigger(IPhysicsObject *pTrigger, IPhysicsObject *pObject); void ObjectLeaveTrigger(IPhysicsObject *pTrigger, IPhysicsObject *pObject); bool GetTriggerEvent(triggerevent_t *pEvent, CBaseEntity *pTriggerEntity); void BufferTouchEvents(bool enable) { m_bBufferTouchEvents = enable; } virtual void AddDamageEvent(CBaseEntity *pEntity, const CTakeDamageInfo &info, IPhysicsObject *pInflictorPhysics, bool bRestoreVelocity, const Vector &savedVel, const AngularImpulse &savedAngVel); void AddImpulseEvent(IPhysicsObject *pPhysicsObject, const Vector &vecCenterForce, const AngularImpulse &vecCenterTorque); void AddSetVelocityEvent(IPhysicsObject *pPhysicsObject, const Vector &vecVelocity); void AddRemoveObject(IServerNetworkable *pRemove); void FlushQueuedOperations(); // IPhysicsCollisionSolver int ShouldCollide(IPhysicsObject *pObj0, IPhysicsObject *pObj1, void *pGameData0, void *pGameData1); int ShouldSolvePenetration(IPhysicsObject *pObj0, IPhysicsObject *pObj1, void *pGameData0, void *pGameData1, float dt); bool ShouldFreezeObject(IPhysicsObject *pObject); static const char *ModuleName() { return CBaseEntity::IsServer() ? "SERVER" : "CLIENT"; } int AdditionalCollisionChecksThisTick(int currentChecksDone) { // CallbackContext check(this); if (currentChecksDone < 1200) { DevMsg(1, "%s: VPhysics Collision detection getting expensive, check " "for too many convex pieces!\n", ModuleName()); return 1200 - currentChecksDone; } DevMsg(1, "%s: VPhysics exceeded collision check limit " "(%d)!!!\nInterpenetration may result!\n", ModuleName(), currentChecksDone); return 0; } bool ShouldFreezeContacts(IPhysicsObject **pObjectList, int objectCount); // IPhysicsObjectEvent // these can be used to optimize out queries on sleeping objects // Called when an object is woken after sleeping virtual void ObjectWake(IPhysicsObject *pObject); // called when an object goes to sleep (no longer simulating) virtual void ObjectSleep(IPhysicsObject *pObject); // locals bool GetInflictorVelocity(IPhysicsObject *pInflictor, Vector &velocity, AngularImpulse &angVelocity); void GetListOfPenetratingEntities(CBaseEntity *pSearch, CUtlVector &list); bool IsInCallback() { return m_inCallback > 0 ? true : false; } private: #if _DEBUG int ShouldCollide_2(IPhysicsObject *pObj0, IPhysicsObject *pObj1, void *pGameData0, void *pGameData1); #endif void UpdateFrictionSounds(); void UpdateTouchEvents(); void UpdateDamageEvents(); void UpdatePenetrateEvents(void); void UpdateFluidEvents(); void UpdateRemoveObjects(); void AddTouchEvent(CBaseEntity *pEntity0, CBaseEntity *pEntity1, int touchType, const Vector &point, const Vector &normal); penetrateevent_t &FindOrAddPenetrateEvent(CBaseEntity *pEntity0, CBaseEntity *pEntity1); float DeltaTimeSinceLastFluid(CBaseEntity *pEntity); void RestoreDamageInflictorState(IPhysicsObject *pInflictor); void RestoreDamageInflictorState(int inflictorStateIndex, float velocityBlend); int AddDamageInflictor(IPhysicsObject *pInflictorPhysics, float otherMass, const Vector &savedVel, const AngularImpulse &savedAngVel, bool addList); int FindDamageInflictor(IPhysicsObject *pInflictorPhysics); // make the call into the entity system void DispatchStartTouch(CBaseEntity *pEntity0, CBaseEntity *pEntity1, const Vector &point, const Vector &normal); void DispatchEndTouch(CBaseEntity *pEntity0, CBaseEntity *pEntity1); class CallbackContext { public: CallbackContext(CCollisionEvent *pOuter) { m_pOuter = pOuter; m_pOuter->m_inCallback++; } ~CallbackContext() { m_pOuter->m_inCallback--; } private: CCollisionEvent *m_pOuter; }; friend class CallbackContext; friction_t m_current[4]; gamevcollisionevent_t m_gameEvent; CUtlVector m_triggerEvents; triggerevent_t m_currentTriggerEvent; CUtlVector m_touchEvents; CUtlVector m_damageEvents; CUtlVector m_damageInflictors; CUtlVector m_penetrateEvents; CUtlVector m_fluidEvents; CUtlVector m_removeObjects; int m_inCallback; int m_lastTickFrictionError; // counter to control printing of the dev // warning for large contact systems bool m_bBufferTouchEvents; }; #endif //#ifndef PHYSICS_COLLISIONEVENT_H