diff --git a/mathlib/mathlib_base.cpp b/mathlib/mathlib_base.cpp index 31443f16..24d084e6 100644 --- a/mathlib/mathlib_base.cpp +++ b/mathlib/mathlib_base.cpp @@ -42,6 +42,7 @@ void Sys_Error (char *error, ...); #endif const QAngle vec3_angle(0,0,0); +const Quaternion quat_identity(0,0,0,1); const Vector vec3_invalid( FLT_MAX, FLT_MAX, FLT_MAX ); const int nanmask = 255<<23; diff --git a/public/bspflags.h b/public/bspflags.h index a4de7f08..4b98d537 100644 --- a/public/bspflags.h +++ b/public/bspflags.h @@ -14,6 +14,8 @@ #pragma once #endif +#include "const.h" + // contents flags are seperate bits // a given brush can contribute multiple content bits // multiple brushes can be in a single leaf @@ -21,136 +23,80 @@ // these definitions also need to be in q_shared.h! // lower bits are stronger, and will eat weaker brushes completely -#define CONTENTS_EMPTY 0 // No contents +#define CONTENTS_EMPTY 0ull // No contents -#define CONTENTS_SOLID 0x1 // an eye is never valid in a solid -#define CONTENTS_WINDOW 0x2 // translucent, but not watery (glass) -#define CONTENTS_AUX 0x4 -#define CONTENTS_GRATE 0x8 // alpha-tested "grate" textures. Bullets/sight pass through, but solids don't -#define CONTENTS_SLIME 0x10 -#define CONTENTS_WATER 0x20 -#define CONTENTS_BLOCKLOS 0x40 // block AI line of sight -#define CONTENTS_OPAQUE 0x80 // things that cannot be seen through (may be non-solid though) -#define LAST_VISIBLE_CONTENTS CONTENTS_OPAQUE +#define CONTENTS_SOLID ( 1ull << LAYER_INDEX_CONTENTS_SOLID ) +#define CONTENTS_HITBOX ( 1ull << LAYER_INDEX_CONTENTS_HITBOX ) +#define CONTENTS_TRIGGER ( 1ull << LAYER_INDEX_CONTENTS_TRIGGER ) +#define CONTENTS_SKY ( 1ull << LAYER_INDEX_CONTENTS_SKY ) -#define ALL_VISIBLE_CONTENTS (LAST_VISIBLE_CONTENTS | (LAST_VISIBLE_CONTENTS-1)) +#define CONTENTS_PLAYER_CLIP ( 1ull << LAYER_INDEX_CONTENTS_PLAYER_CLIP ) +#define CONTENTS_NPC_CLIP ( 1ull << LAYER_INDEX_CONTENTS_NPC_CLIP ) +#define CONTENTS_BLOCK_LOS ( 1ull << LAYER_INDEX_CONTENTS_BLOCK_LOS ) +#define CONTENTS_BLOCK_LIGHT ( 1ull << LAYER_INDEX_CONTENTS_BLOCK_LIGHT ) +#define CONTENTS_LADDER ( 1ull << LAYER_INDEX_CONTENTS_LADDER ) +#define CONTENTS_PICKUP ( 1ull << LAYER_INDEX_CONTENTS_PICKUP ) +#define CONTENTS_BLOCK_SOUND ( 1ull << LAYER_INDEX_CONTENTS_BLOCK_SOUND ) +#define CONTENTS_NODRAW ( 1ull << LAYER_INDEX_CONTENTS_NODRAW ) +#define CONTENTS_WINDOW ( 1ull << LAYER_INDEX_CONTENTS_WINDOW ) +#define CONTENTS_PASS_BULLETS ( 1ull << LAYER_INDEX_CONTENTS_PASS_BULLETS ) +#define CONTENTS_WORLD_GEOMETRY ( 1ull << LAYER_INDEX_CONTENTS_WORLD_GEOMETRY ) +#define CONTENTS_WATER ( 1ull << LAYER_INDEX_CONTENTS_WATER ) +#define CONTENTS_SLIME ( 1ull << LAYER_INDEX_CONTENTS_SLIME ) +#define CONTENTS_TOUCH_ALL ( 1ull << LAYER_INDEX_CONTENTS_TOUCH_ALL ) +#define CONTENTS_PLAYER ( 1ull << LAYER_INDEX_CONTENTS_PLAYER ) +#define CONTENTS_NPC ( 1ull << LAYER_INDEX_CONTENTS_NPC ) +#define CONTENTS_DEBRIS ( 1ull << LAYER_INDEX_CONTENTS_DEBRIS ) +#define CONTENTS_PHYSICS_PROP ( 1ull << LAYER_INDEX_CONTENTS_PHYSICS_PROP ) +#define CONTENTS_NAV_IGNORE ( 1ull << LAYER_INDEX_CONTENTS_NAV_IGNORE ) +#define CONTENTS_NAV_LOCAL_IGNORE ( 1ull << LAYER_INDEX_CONTENTS_NAV_LOCAL_IGNORE ) +#define CONTENTS_POST_PROCESSING_VOLUME ( 1ull << LAYER_INDEX_CONTENTS_POST_PROCESSING_VOLUME ) +#define CONTENTS_UNUSED_LAYER3 ( 1ull << LAYER_INDEX_CONTENTS_UNUSED_LAYER3 ) +#define CONTENTS_CARRIED_OBJECT ( 1ull << LAYER_INDEX_CONTENTS_CARRIED_OBJECT ) +#define CONTENTS_PUSHAWAY ( 1ull << LAYER_INDEX_CONTENTS_PUSHAWAY ) +#define CONTENTS_SERVER_ENTITY_ON_CLIENT ( 1ull << LAYER_INDEX_CONTENTS_SERVER_ENTITY_ON_CLIENT ) +#define CONTENTS_CARRIED_WEAPON ( 1ull << LAYER_INDEX_CONTENTS_CARRIED_WEAPON ) +#define CONTENTS_STATIC_LEVEL ( 1ull << LAYER_INDEX_CONTENTS_STATIC_LEVEL ) -#define CONTENTS_TESTFOGVOLUME 0x100 -#define CONTENTS_UNUSED 0x200 - -// unused -// NOTE: If it's visible, grab from the top + update LAST_VISIBLE_CONTENTS -// if not visible, then grab from the bottom. -// CONTENTS_OPAQUE + SURF_NODRAW count as CONTENTS_OPAQUE (shadow-casting toolsblocklight textures) -#define CONTENTS_BLOCKLIGHT 0x400 - -#define CONTENTS_TEAM1 0x800 // per team contents used to differentiate collisions -#define CONTENTS_TEAM2 0x1000 // between players and objects on different teams - -// ignore CONTENTS_OPAQUE on surfaces that have SURF_NODRAW -#define CONTENTS_IGNORE_NODRAW_OPAQUE 0x2000 - -// hits entities which are MOVETYPE_PUSH (doors, plats, etc.) -#define CONTENTS_MOVEABLE 0x4000 - -// remaining contents are non-visible, and don't eat brushes -#define CONTENTS_AREAPORTAL 0x8000 - -#define CONTENTS_PLAYERCLIP 0x10000 -#define CONTENTS_MONSTERCLIP 0x20000 - -// currents can be added to any other contents, and may be mixed -#define CONTENTS_CURRENT_0 0x40000 -#define CONTENTS_CURRENT_90 0x80000 -#define CONTENTS_CURRENT_180 0x100000 -#define CONTENTS_CURRENT_270 0x200000 -#define CONTENTS_CURRENT_UP 0x400000 -#define CONTENTS_CURRENT_DOWN 0x800000 - -#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity - -#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game -#define CONTENTS_DEBRIS 0x4000000 -#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs -#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans -#define CONTENTS_LADDER 0x20000000 -#define CONTENTS_HITBOX 0x40000000 // use accurate hitboxes on trace - -// NOTE: These are stored in a short in the engine now. Don't use more than 16 bits -#define SURF_LIGHT 0x0001 // value will hold the light strength -#define SURF_SKY2D 0x0002 // don't draw, indicates we should skylight + draw 2d sky but not draw the 3D skybox -#define SURF_SKY 0x0004 // don't draw, but add to skybox -#define SURF_WARP 0x0008 // turbulent water warp -#define SURF_TRANS 0x0010 -#define SURF_NOPORTAL 0x0020 // the surface can not have a portal placed on it -#define SURF_TRIGGER 0x0040 // FIXME: This is an xbox hack to work around elimination of trigger surfaces, which breaks occluders -#define SURF_NODRAW 0x0080 // don't bother referencing the texture - -#define SURF_HINT 0x0100 // make a primary bsp splitter - -#define SURF_SKIP 0x0200 // completely ignore, allowing non-closed brushes -#define SURF_NOLIGHT 0x0400 // Don't calculate light -#define SURF_BUMPLIGHT 0x0800 // calculate three lightmaps for the surface for bumpmapping -#define SURF_NOSHADOWS 0x1000 // Don't receive shadows -#define SURF_NODECALS 0x2000 // Don't receive decals -#define SURF_NOPAINT SURF_NODECALS // the surface can not have paint placed on it -#define SURF_NOCHOP 0x4000 // Don't subdivide patches on this surface -#define SURF_HITBOX 0x8000 // surface is part of a hitbox +#define CONTENTS_CSGO_TEAM1 ( 1ull << LAYER_INDEX_CONTENTS_CSGO_TEAM1 ) +#define CONTENTS_CSGO_TEAM2 ( 1ull << LAYER_INDEX_CONTENTS_CSGO_TEAM2 ) +#define CONTENTS_CSGO_GRENADE_CLIP ( 1ull << LAYER_INDEX_CONTENTS_CSGO_GRENADE_CLIP ) +#define CONTENTS_CSGO_DRONE_CLIP ( 1ull << LAYER_INDEX_CONTENTS_CSGO_DRONE_CLIP ) +#define CONTENTS_CSGO_MOVEABLE ( 1ull << LAYER_INDEX_CONTENTS_CSGO_MOVEABLE ) +#define CONTENTS_CSGO_OPAQUE ( 1ull << LAYER_INDEX_CONTENTS_CSGO_OPAQUE ) +#define CONTENTS_CSGO_MONSTER ( 1ull << LAYER_INDEX_CONTENTS_CSGO_MONSTER ) +#define CONTENTS_CSGO_UNUSED_LAYER ( 1ull << LAYER_INDEX_CONTENTS_CSGO_UNUSED_LAYER ) +#define CONTENTS_CSGO_THROWN_GRENADE ( 1ull << LAYER_INDEX_CONTENTS_CSGO_THROWN_GRENADE ) // ----------------------------------------------------- // spatial content masks - used for spatial queries (traceline,etc.) // ----------------------------------------------------- -#define MASK_ALL (0xFFFFFFFF) +#define MASK_ALL (~0ull) // everything that is normally solid -#define MASK_SOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) +#define MASK_SOLID (CONTENTS_SOLID|CONTENTS_WINDOW|CONTENTS_PLAYER|CONTENTS_NPC|CONTENTS_PASS_BULLETS) // everything that blocks player movement -#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) +#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYER_CLIP|CONTENTS_WINDOW|CONTENTS_PLAYER|CONTENTS_NPC|CONTENTS_PASS_BULLETS) // blocks npc movement -#define MASK_NPCSOLID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER|CONTENTS_GRATE) +#define MASK_NPCSOLID (CONTENTS_SOLID|CONTENTS_NPC_CLIP|CONTENTS_WINDOW|CONTENTS_PLAYER|CONTENTS_NPC|CONTENTS_PASS_BULLETS) // blocks fluid movement -#define MASK_NPCFLUID (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER) +#define MASK_NPCFLUID (CONTENTS_SOLID|CONTENTS_NPC_CLIP|CONTENTS_WINDOW|CONTENTS_PLAYER|CONTENTS_NPC) // water physics in these contents -#define MASK_WATER (CONTENTS_WATER|CONTENTS_MOVEABLE|CONTENTS_SLIME) -// everything that blocks lighting -#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_OPAQUE) -// everything that blocks lighting, but with monsters added. -#define MASK_OPAQUE_AND_NPCS (MASK_OPAQUE|CONTENTS_MONSTER) -// everything that blocks line of sight for AI -#define MASK_BLOCKLOS (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_BLOCKLOS) -// everything that blocks line of sight for AI plus NPCs -#define MASK_BLOCKLOS_AND_NPCS (MASK_BLOCKLOS|CONTENTS_MONSTER) -// everything that blocks line of sight for players -#define MASK_VISIBLE (MASK_OPAQUE|CONTENTS_IGNORE_NODRAW_OPAQUE) -// everything that blocks line of sight for players, but with monsters added. -#define MASK_VISIBLE_AND_NPCS (MASK_OPAQUE_AND_NPCS|CONTENTS_IGNORE_NODRAW_OPAQUE) +#define MASK_WATER (CONTENTS_WATER|CONTENTS_SLIME) // bullets see these as solid -#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEBRIS|CONTENTS_HITBOX) +#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_PLAYER|CONTENTS_NPC|CONTENTS_WINDOW|CONTENTS_DEBRIS|CONTENTS_HITBOX) // bullets see these as solid, except monsters (world+brush only) -#define MASK_SHOT_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_DEBRIS) +#define MASK_SHOT_BRUSHONLY (CONTENTS_SOLID|CONTENTS_WINDOW|CONTENTS_DEBRIS) // non-raycasted weapons see this as solid (includes grates) -#define MASK_SHOT_HULL (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEBRIS|CONTENTS_GRATE) +#define MASK_SHOT_HULL (CONTENTS_SOLID|CONTENTS_PLAYER|CONTENTS_NPC|CONTENTS_WINDOW|CONTENTS_DEBRIS|CONTENTS_PASS_BULLETS) // hits solids (not grates) and passes through everything else -#define MASK_SHOT_PORTAL (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTER) +#define MASK_SHOT_PORTAL (CONTENTS_SOLID|CONTENTS_WINDOW|CONTENTS_PLAYER|CONTENTS_NPC) // everything normally solid, except monsters (world+brush only) -#define MASK_SOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_GRATE) +#define MASK_SOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_WINDOW|CONTENTS_PASS_BULLETS) // everything normally solid for player movement, except monsters (world+brush only) -#define MASK_PLAYERSOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_PLAYERCLIP|CONTENTS_GRATE) +#define MASK_PLAYERSOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_WINDOW|CONTENTS_PLAYER_CLIP|CONTENTS_PASS_BULLETS) // everything normally solid for npc movement, except monsters (world+brush only) -#define MASK_NPCSOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_WINDOW|CONTENTS_MONSTERCLIP|CONTENTS_GRATE) -// just the world, used for route rebuilding -#define MASK_NPCWORLDSTATIC (CONTENTS_SOLID|CONTENTS_WINDOW|CONTENTS_MONSTERCLIP|CONTENTS_GRATE) -// just the world, used for route rebuilding -#define MASK_NPCWORLDSTATIC_FLUID (CONTENTS_SOLID|CONTENTS_WINDOW|CONTENTS_MONSTERCLIP) -// These are things that can split areaportals -#define MASK_SPLITAREAPORTAL (CONTENTS_WATER|CONTENTS_SLIME) - -// UNDONE: This is untested, any moving water -#define MASK_CURRENT (CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN) - -// everything that blocks corpse movement -// UNDONE: Not used yet / may be deleted -#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_GRATE) +#define MASK_NPCSOLID_BRUSHONLY (CONTENTS_SOLID|CONTENTS_WINDOW|CONTENTS_NPC_CLIP|CONTENTS_PASS_BULLETS) #endif // BSPFLAGS_H diff --git a/public/cmodel.h b/public/cmodel.h index 400dcefd..37e1d655 100644 --- a/public/cmodel.h +++ b/public/cmodel.h @@ -38,6 +38,15 @@ COLLISION DETECTION #include "vcollide.h" +enum RayType_t : uint8 +{ + RAY_TYPE_LINE = 0, + RAY_TYPE_SPHERE, + RAY_TYPE_HULL, + RAY_TYPE_CAPSULE, + RAY_TYPE_MESH, +}; + struct cmodel_t { Vector mins, maxs; @@ -59,70 +68,121 @@ struct csurface_t //----------------------------------------------------------------------------- struct Ray_t { - VectorAligned m_Start; // starting point, centered within the extents - VectorAligned m_Delta; // direction + length of the ray - VectorAligned m_StartOffset; // Add this to m_Start to get the actual ray start - VectorAligned m_Extents; // Describes an axis aligned box extruded along a ray - const matrix3x4_t *m_pWorldAxisTransform; - bool m_IsRay; // are the extents zero? - bool m_IsSwept; // is delta != 0? - - Ray_t() : m_pWorldAxisTransform( NULL ) {} - - void Init( Vector const& start, Vector const& end ) + Ray_t() { Init( Vector( 0.0f, 0.0f, 0.0f ) ); } + Ray_t( const Vector& vStartOffset ) { Init( vStartOffset ); } + Ray_t( const Vector& vCenter, float flRadius ) { Init( vCenter, flRadius ); } + Ray_t( const Vector& vMins, const Vector& vMaxs ) { Init( vMins, vMaxs ); } + Ray_t( const Vector& vCenterA, const Vector& vCenterB, float flRadius ) { Init( vCenterA, vCenterB, flRadius ); } + Ray_t( const Vector& vMins, const Vector& vMaxs, const Vector* pVertices, int nNumVertices ) { Init( vMins, vMaxs, pVertices, nNumVertices ); } + + void Init( const Vector& vStartOffset ) { - Assert( &end ); - VectorSubtract( end, start, m_Delta ); - - m_IsSwept = (m_Delta.LengthSqr() != 0); - - VectorClear( m_Extents ); - m_pWorldAxisTransform = NULL; - m_IsRay = true; - - // Offset m_Start to be in the center of the box... - VectorClear( m_StartOffset ); - VectorCopy( start, m_Start ); + m_Line.m_vStartOffset = vStartOffset; + m_Line.m_flRadius = 0.0f; + m_eType = RAY_TYPE_LINE; } - - void Init( Vector const& start, Vector const& end, Vector const& mins, Vector const& maxs ) + + void Init( const Vector& vCenter, float flRadius ) { - Assert( &end ); - VectorSubtract( end, start, m_Delta ); - - m_pWorldAxisTransform = NULL; - m_IsSwept = (m_Delta.LengthSqr() != 0); - - VectorSubtract( maxs, mins, m_Extents ); - m_Extents *= 0.5f; - m_IsRay = (m_Extents.LengthSqr() < 1e-6); - - // Offset m_Start to be in the center of the box... - VectorAdd( mins, maxs, m_StartOffset ); - m_StartOffset *= 0.5f; - VectorAdd( start, m_StartOffset, m_Start ); - m_StartOffset *= -1.0f; - } - - // compute inverse delta - Vector InvDelta() const - { - Vector vecInvDelta; - for ( int iAxis = 0; iAxis < 3; ++iAxis ) + if ( flRadius > 0.0f ) { - if ( m_Delta[iAxis] != 0.0f ) + m_Sphere.m_vCenter = vCenter; + m_Sphere.m_flRadius = flRadius; + m_eType = RAY_TYPE_SPHERE; + } + else + { + Init( vCenter ); + } + } + + void Init( const Vector& vMins, const Vector& vMaxs ) + { + if ( vMins != vMaxs ) + { + m_Hull.m_vMins = vMins; + m_Hull.m_vMaxs = vMaxs; + m_eType = RAY_TYPE_HULL; + } + else + { + Init( vMins ); + } + } + + void Init( const Vector& vCenterA, const Vector& vCenterB, float flRadius ) + { + if ( vCenterA != vCenterB ) + { + if ( flRadius > 0.0f ) { - vecInvDelta[iAxis] = 1.0f / m_Delta[iAxis]; + m_Capsule.m_vCenter[0] = vCenterA; + m_Capsule.m_vCenter[1] = vCenterB; + m_Capsule.m_flRadius = flRadius; + m_eType = RAY_TYPE_CAPSULE; } else { - vecInvDelta[iAxis] = FLT_MAX; + Init( vCenterA, vCenterB ); } } - return vecInvDelta; + else + { + Init( vCenterA, flRadius ); + } } - -private: + + void Init( const Vector& vMins, const Vector& vMaxs, const Vector* pVertices, int nNumVertices ) + { + m_Mesh.m_vMins = vMins; + m_Mesh.m_vMaxs = vMaxs; + m_Mesh.m_pVertices = pVertices; + m_Mesh.m_nNumVertices = nNumVertices; + m_eType = RAY_TYPE_MESH; + } + + struct Line_t + { + Vector m_vStartOffset; + float m_flRadius; + }; + + struct Sphere_t + { + Vector m_vCenter; + float m_flRadius; + }; + + struct Hull_t + { + Vector m_vMins; + Vector m_vMaxs; + }; + + struct Capsule_t + { + Vector m_vCenter[2]; + float m_flRadius; + }; + + struct Mesh_t + { + Vector m_vMins; + Vector m_vMaxs; + const Vector* m_pVertices; + int m_nNumVertices; + }; + + union + { + Line_t m_Line; + Sphere_t m_Sphere; + Hull_t m_Hull; + Capsule_t m_Capsule; + Mesh_t m_Mesh; + }; + + RayType_t m_eType; }; diff --git a/public/const.h b/public/const.h index 8fdbf348..e2fe1927 100644 --- a/public/const.h +++ b/public/const.h @@ -352,13 +352,81 @@ enum RenderFx_t : unsigned char kRenderFxMax }; -enum Collision_Group_t +enum BuiltInInteractionLayer_t { - COLLISION_GROUP_ALWAYS = 0, - COLLISION_GROUP_NEVER, - COLLISION_GROUP_TRIGGER, - COLLISION_GROUP_CONDITIONALLY_SOLID, - COLLISION_GROUP_DEFAULT, + LAYER_INDEX_CONTENTS_SOLID = 0, + LAYER_INDEX_CONTENTS_HITBOX, + LAYER_INDEX_CONTENTS_TRIGGER, + LAYER_INDEX_CONTENTS_SKY, + LAYER_INDEX_FIRST_USER, + LAYER_INDEX_NOT_FOUND = -1, + LAYER_INDEX_MAX_ALLOWED = 64, +}; + +enum StandardInteractionLayers_t +{ + LAYER_INDEX_CONTENTS_PLAYER_CLIP = LAYER_INDEX_FIRST_USER, + LAYER_INDEX_CONTENTS_NPC_CLIP, + LAYER_INDEX_CONTENTS_BLOCK_LOS, + LAYER_INDEX_CONTENTS_BLOCK_LIGHT, + LAYER_INDEX_CONTENTS_LADDER, + LAYER_INDEX_CONTENTS_PICKUP, + LAYER_INDEX_CONTENTS_BLOCK_SOUND, + LAYER_INDEX_CONTENTS_NODRAW, + LAYER_INDEX_CONTENTS_WINDOW, + LAYER_INDEX_CONTENTS_PASS_BULLETS, + LAYER_INDEX_CONTENTS_WORLD_GEOMETRY, + LAYER_INDEX_CONTENTS_WATER, + LAYER_INDEX_CONTENTS_SLIME, + LAYER_INDEX_CONTENTS_TOUCH_ALL, + LAYER_INDEX_CONTENTS_PLAYER, + LAYER_INDEX_CONTENTS_NPC, + LAYER_INDEX_CONTENTS_DEBRIS, + LAYER_INDEX_CONTENTS_PHYSICS_PROP, + LAYER_INDEX_CONTENTS_NAV_IGNORE, + LAYER_INDEX_CONTENTS_NAV_LOCAL_IGNORE, + LAYER_INDEX_CONTENTS_POST_PROCESSING_VOLUME, + LAYER_INDEX_CONTENTS_UNUSED_LAYER3, + LAYER_INDEX_CONTENTS_CARRIED_OBJECT, + LAYER_INDEX_CONTENTS_PUSHAWAY, + LAYER_INDEX_CONTENTS_SERVER_ENTITY_ON_CLIENT, + LAYER_INDEX_CONTENTS_CARRIED_WEAPON, + LAYER_INDEX_CONTENTS_STATIC_LEVEL, + LAYER_INDEX_FIRST_MOD_SPECIFIC, +}; + +enum ModSpecificInteractionLayers_t +{ + LAYER_INDEX_CONTENTS_CSGO_TEAM1 = LAYER_INDEX_FIRST_MOD_SPECIFIC, + LAYER_INDEX_CONTENTS_CSGO_TEAM2, + LAYER_INDEX_CONTENTS_CSGO_GRENADE_CLIP, + LAYER_INDEX_CONTENTS_CSGO_DRONE_CLIP, + LAYER_INDEX_CONTENTS_CSGO_MOVEABLE, + LAYER_INDEX_CONTENTS_CSGO_OPAQUE, + LAYER_INDEX_CONTENTS_CSGO_MONSTER, + LAYER_INDEX_CONTENTS_CSGO_UNUSED_LAYER, + LAYER_INDEX_CONTENTS_CSGO_THROWN_GRENADE, +}; + +enum BuiltInCollisionGroup_t +{ + // Default layer, always collides with everything. + COLLISION_GROUP_ALWAYS = 0, // "always" + // This is how you turn off all collisions for an object - move it to this group + COLLISION_GROUP_NONPHYSICAL, // "never" + // Trigger layer, never collides with anything, only triggers/interacts. Use when querying for interaction layers. + COLLISION_GROUP_TRIGGER, // "trigger" + // Conditionally solid means that the collision response will be zero or as defined in the table when there are matching interactions + COLLISION_GROUP_CONDITIONALLY_SOLID, // needs interactions + // First unreserved collision layer index. + COLLISION_GROUP_FIRST_USER, + // Hard limit of 254 due to memory layout, and these are never visible to scene queries. + COLLISION_GROUPS_MAX_ALLOWED = 64, +}; + +enum StandardCollisionGroups_t +{ + COLLISION_GROUP_DEFAULT = COLLISION_GROUP_FIRST_USER, COLLISION_GROUP_DEBRIS, // Collides with nothing but world, static stuff and triggers COLLISION_GROUP_INTERACTIVE_DEBRIS, // Collides with everything except other interactive debris or debris COLLISION_GROUP_INTERACTIVE, // Collides with everything except interactive debris or debris @@ -378,14 +446,11 @@ enum Collision_Group_t COLLISION_GROUP_PUSHAWAY, // Nonsolid on client and server, pushaway in player code COLLISION_GROUP_NPC_ACTOR, // Used so NPCs in scripts ignore the player. - COLLISION_GROUP_NPC_SCRIPTED, // USed for NPCs in scripts that should not collide with each other + COLLISION_GROUP_NPC_SCRIPTED, // Used for NPCs in scripts that should not collide with each other COLLISION_GROUP_PZ_CLIP, - - - COLLISION_GROUP_PROPS, - LAST_SHARED_COLLISION_GROUP + LAST_SHARED_COLLISION_GROUP, }; #include "basetypes.h" diff --git a/public/engine/IEngineTrace.h b/public/engine/IEngineTrace.h deleted file mode 100644 index fc7ae7e5..00000000 --- a/public/engine/IEngineTrace.h +++ /dev/null @@ -1,233 +0,0 @@ -//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// - -#ifndef ENGINE_IENGINETRACE_H -#define ENGINE_IENGINETRACE_H -#ifdef _WIN32 -#pragma once -#endif - -#include "entityhandle.h" -#include "utlvector.h" //need CUtlVector for IEngineTrace::GetBrushesIn*() -#include "mathlib/vector4d.h" -#include "bspflags.h" - -class Vector; -class CEntityInstance; -struct Ray_t; -class CGameTrace; -typedef CGameTrace trace_t; -class ICollideable; -class QAngle; -class ITraceListData; -class CPhysCollide; -struct cplane_t; -struct virtualmeshlist_t; - -//----------------------------------------------------------------------------- -// The standard trace filter... NOTE: Most normal traces inherit from CTraceFilter!!! -//----------------------------------------------------------------------------- -enum TraceType_t -{ - TRACE_EVERYTHING = 0, - TRACE_WORLD_ONLY, // NOTE: This does *not* test static props!!! - TRACE_ENTITIES_ONLY, // NOTE: This version will *not* test static props - TRACE_EVERYTHING_FILTER_PROPS, // NOTE: This version will pass the IHandleEntity for props through the filter, unlike all other filters -}; - -abstract_class ITraceFilter -{ -public: - virtual bool ShouldHitEntity( CEntityInstance *pEntity, int contentsMask ) = 0; - virtual TraceType_t GetTraceType() const = 0; -}; - - -//----------------------------------------------------------------------------- -// Classes are expected to inherit these + implement the ShouldHitEntity method -//----------------------------------------------------------------------------- - -// This is the one most normal traces will inherit from -class CTraceFilter : public ITraceFilter -{ -public: - virtual TraceType_t GetTraceType() const - { - return TRACE_EVERYTHING; - } -}; - -class CTraceFilterEntitiesOnly : public ITraceFilter -{ -public: - virtual TraceType_t GetTraceType() const - { - return TRACE_ENTITIES_ONLY; - } -}; - - -//----------------------------------------------------------------------------- -// Classes need not inherit from these -//----------------------------------------------------------------------------- -class CTraceFilterWorldOnly : public ITraceFilter -{ -public: - bool ShouldHitEntity( CEntityInstance *pServerEntity, int contentsMask ) - { - return false; - } - virtual TraceType_t GetTraceType() const - { - return TRACE_WORLD_ONLY; - } -}; - -class CTraceFilterWorldAndPropsOnly : public ITraceFilter -{ -public: - bool ShouldHitEntity( CEntityInstance *pServerEntity, int contentsMask ) - { - return false; - } - virtual TraceType_t GetTraceType() const - { - return TRACE_EVERYTHING; - } -}; - -class CTraceFilterHitAll : public CTraceFilter -{ -public: - virtual bool ShouldHitEntity( CEntityInstance *pServerEntity, int contentsMask ) - { - return true; - } -}; - - -enum DebugTraceCounterBehavior_t -{ - kTRACE_COUNTER_SET = 0, - kTRACE_COUNTER_INC, -}; - -//----------------------------------------------------------------------------- -// Enumeration interface for EnumerateLinkEntities -//----------------------------------------------------------------------------- -abstract_class IEntityEnumerator -{ -public: - // This gets called with each handle - virtual bool EnumEntity( CEntityInstance *pHandleEntity ) = 0; -}; - - -struct BrushSideInfo_t -{ - Vector4D plane; // The plane of the brush side - unsigned short bevel; // Bevel plane? - unsigned short thin; // Thin? -}; - -//----------------------------------------------------------------------------- -// Interface the engine exposes to the game DLL -//----------------------------------------------------------------------------- -#define INTERFACEVERSION_ENGINETRACE_SERVER "EngineTraceServer004" -#define INTERFACEVERSION_ENGINETRACE_CLIENT "EngineTraceClient004" -abstract_class IEngineTrace -{ -public: - // Returns the contents mask + entity at a particular world-space position - virtual int GetPointContents( const Vector &vecAbsPosition, int contentsMask = MASK_ALL, CEntityInstance** ppEntity = NULL ) = 0; - - // Returns the contents mask of the world only @ the world-space position (static props are ignored) - virtual int GetPointContents_WorldOnly( const Vector &vecAbsPosition, int contentsMask = MASK_ALL ) = 0; - - // Get the point contents, but only test the specific entity. This works - // on static props and brush models. - // - // If the entity isn't a static prop or a brush model, it returns CONTENTS_EMPTY and sets - // bFailed to true if bFailed is non-null. - virtual int GetPointContents_Collideable( ICollideable *pCollide, const Vector &vecAbsPosition ) = 0; - - // Traces a ray against a particular entity - virtual void ClipRayToEntity( const Ray_t &ray, unsigned int fMask, CEntityInstance *pEnt, trace_t *pTrace ) = 0; - - // Traces a ray against a particular entity - virtual void ClipRayToCollideable( const Ray_t &ray, unsigned int fMask, ICollideable *pCollide, trace_t *pTrace ) = 0; - - // A version that simply accepts a ray (can work as a traceline or tracehull) - virtual void TraceRay( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace ) = 0; - - // A version that sets up the leaf and entity lists and allows you to pass those in for collision. - virtual void SetupLeafAndEntityListRay( const Ray_t &ray, ITraceListData *pTraceData ) = 0; - virtual void SetupLeafAndEntityListBox( const Vector &vecBoxMin, const Vector &vecBoxMax, ITraceListData *pTraceData ) = 0; - virtual void TraceRayAgainstLeafAndEntityList( const Ray_t &ray, ITraceListData *pTraceData, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace ) = 0; - - // A version that sweeps a collideable through the world - // abs start + abs end represents the collision origins you want to sweep the collideable through - // vecAngles represents the collision angles of the collideable during the sweep - virtual void SweepCollideable( ICollideable *pCollide, const Vector &vecAbsStart, const Vector &vecAbsEnd, - const QAngle &vecAngles, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace ) = 0; - - // Enumerates over all entities along a ray - // If triggers == true, it enumerates all triggers along a ray - virtual void EnumerateEntities( const Ray_t &ray, bool triggers, IEntityEnumerator *pEnumerator ) = 0; - - // Same thing, but enumerate entitys within a box - virtual void EnumerateEntities( const Vector &vecAbsMins, const Vector &vecAbsMaxs, IEntityEnumerator *pEnumerator ) = 0; - - // Convert a handle entity to a collideable. Useful inside enumer - virtual ICollideable *GetCollideable( CEntityInstance *pEntity ) = 0; - - // HACKHACK: Temp for performance measurments - virtual int GetStatByIndex( int index, bool bClear ) = 0; - - - //finds brushes in an AABB, prone to some false positives - virtual void GetBrushesInAABB( const Vector &vMins, const Vector &vMaxs, CUtlVector *pOutput, int iContentsMask = 0xFFFFFFFF ) = 0; - - //Creates a CPhysCollide out of all displacements wholly or partially contained in the specified AABB - virtual CPhysCollide* GetCollidableFromDisplacementsInAABB( const Vector& vMins, const Vector& vMaxs ) = 0; - - // gets the number of displacements in the world - virtual int GetNumDisplacements( ) = 0; - - // gets a specific diplacement mesh - virtual void GetDisplacementMesh( int nIndex, virtualmeshlist_t *pMeshTriList ) = 0; - - //retrieve brush planes and contents, returns true if data is being returned in the output pointers, false if the brush doesn't exist - virtual bool GetBrushInfo( int iBrush, CUtlVector *pBrushSideInfoOut, int *pContentsOut ) = 0; - - virtual bool PointOutsideWorld( const Vector &ptTest ) = 0; //Tests a point to see if it's outside any playable area - - // Walks bsp to find the leaf containing the specified point - virtual int GetLeafContainingPoint( const Vector &ptTest ) = 0; - - virtual ITraceListData *AllocTraceListData() = 0; - virtual void FreeTraceListData(ITraceListData *) = 0; - - /// Used only in debugging: get/set/clear/increment the trace debug counter. See comment below for details. - virtual int GetSetDebugTraceCounter( int value, DebugTraceCounterBehavior_t behavior ) = 0; -}; - -/// IEngineTrace::GetSetDebugTraceCounter -/// SET to a negative number to disable. SET to a positive number to reset the counter; it'll tick down by -/// one for each trace, and break into the debugger on hitting zero. INC lets you add or subtract from the -/// counter. In each case it will return the value of the counter BEFORE you set or incremented it. INC 0 -/// to query. This end-around approach is necessary for security: because only the engine knows when we -/// are in a trace, and only the server knows when we are in a think, data must somehow be shared between -/// them. Simply returning a pointer to an address inside the engine in a retail build is unacceptable, -/// and in the PC there is no way to distinguish between retail and non-retail builds at compile time -/// (there is no #define for it). -/// This may seem redundant with the VPROF_INCREMENT_COUNTER( "TraceRay" ), but it's not, because while -/// that's readable across DLLs, there's no way to trap on its exceeding a certain value, nor can we reset -/// it for each think. - -#endif // ENGINE_IENGINETRACE_H diff --git a/public/gametrace.h b/public/gametrace.h index 2a6f6406..81501562 100644 --- a/public/gametrace.h +++ b/public/gametrace.h @@ -12,84 +12,488 @@ #include "cmodel.h" +#include "Color.h" +#include "entity2/entityinstance.h" +#include "mathlib/transform.h" +#include "tier1/generichash.h" #include "tier1/utlvector.h" +#include "tier1/utlstring.h" #include "ispatialpartition.h" -#if defined( CLIENT_DLL ) - class C_BaseEntity; -#else - class CBaseEntity; -#endif +class IPhysicsBody; +class IPhysicsShape; +typedef IPhysicsBody* HPhysicsBody; +typedef IPhysicsShape* HPhysicsShape; -//----------------------------------------------------------------------------- -// Purpose: A trace is returned when a box is swept through the world -// NOTE: eventually more of this class should be moved up into the base class!! -//----------------------------------------------------------------------------- -class CGameTrace : public CBaseTrace +enum CollisionFunctionMask_t +{ + FCOLLISION_FUNC_ENABLE_SOLID_CONTACT = (1<<0), + FCOLLISION_FUNC_ENABLE_TRACE_QUERY = (1<<1), + FCOLLISION_FUNC_ENABLE_TOUCH_EVENT = (1<<2), + FCOLLISION_FUNC_ENABLE_SELF_COLLISIONS = (1<<3), + FCOLLISION_FUNC_IGNORE_FOR_HITBOX_TEST = (1<<4), + FCOLLISION_FUNC_ENABLE_TOUCH_PERSISTS = (1<<5), +}; + +// these are on by default +#define FCOLLISION_FUNC_DEFAULT (FCOLLISION_FUNC_ENABLE_SOLID_CONTACT | FCOLLISION_FUNC_ENABLE_TRACE_QUERY | FCOLLISION_FUNC_ENABLE_TOUCH_EVENT) + +enum RnQueryObjectSet +{ + RNQUERY_OBJECTS_STATIC = (1<<0), + RNQUERY_OBJECTS_DYNAMIC = (1<<1), + RNQUERY_OBJECTS_NON_COLLIDEABLE = (1<<2), + RNQUERY_OBJECTS_KEYFRAMED_ONLY = (1<<3) | (1<<8), + RNQUERY_OBJECTS_DYNAMIC_ONLY = (1<<4) | (1<<8), + + RNQUERY_OBJECTS_ALL_GAME_ENTITIES = RNQUERY_OBJECTS_DYNAMIC | RNQUERY_OBJECTS_NON_COLLIDEABLE, + RNQUERY_OBJECTS_ALL = RNQUERY_OBJECTS_STATIC | RNQUERY_OBJECTS_ALL_GAME_ENTITIES, +}; + +enum HitGroup_t +{ + HITGROUP_INVALID = -1, + HITGROUP_GENERIC = 0, + HITGROUP_HEAD, + HITGROUP_CHEST, + HITGROUP_STOMACH, + HITGROUP_LEFTARM, + HITGROUP_RIGHTARM, + HITGROUP_LEFTLEG, + HITGROUP_RIGHTLEG, + HITGROUP_NECK, + HITGROUP_UNUSED, + HITGROUP_GEAR, + HITGROUP_SPECIAL, + HITGROUP_COUNT, +}; + +enum HitboxShapeType_t +{ + HITBOX_SHAPE_HULL = 0, + HITBOX_SHAPE_SPHERE, + HITBOX_SHAPE_CAPSULE, +}; + +class CPhysSurfacePropertiesPhysics { public: - - // Returns true if hEnt points at the world entity. - // If this returns true, then you can't use GetHitBoxIndex(). - bool DidHitWorld() const; + CPhysSurfacePropertiesPhysics() + { + m_friction = 0.0f; + m_elasticity = 0.0f; + m_density = 0.0f; + m_thickness = 0.1f; + m_softContactFrequency = 0.0f; + m_softContactDampingRatio = 0.0f; + m_wheelDrag = 0.0f; + } - // Returns true if we hit something and it wasn't the world. - bool DidHitNonWorldEntity() const; - - // Gets the entity's network index if the trace has hit an entity. - // If not, returns -1. - int GetEntityIndex() const; - - // Returns true if there was any kind of impact at all - bool DidHit() const; - - // The engine doesn't know what a CBaseEntity is, so it has a backdoor to - // let it get at the edict. -#if defined( ENGINE_DLL ) - void SetEdict( edict_t *pEdict ); - edict_t* GetEdict() const; -#endif - - public: + float m_friction; + float m_elasticity; + float m_density; + float m_thickness; + float m_softContactFrequency; + float m_softContactDampingRatio; + float m_wheelDrag; +}; - float fractionleftsolid; // time we left a solid, only valid if we started in solid - csurface_t surface; // surface hit (impact surface) +class CPhysSurfacePropertiesSoundNames +{ +public: + CPhysSurfacePropertiesSoundNames() + { + m_meleeImpact = ""; + m_pushOff = ""; + m_skidStop = ""; + } + +public: + CUtlString m_impactSoft; + CUtlString m_impactHard; + CUtlString m_scrapeSmooth; + CUtlString m_scrapeRough; + CUtlString m_bulletImpact; + CUtlString m_rolling; + CUtlString m_break; + CUtlString m_strain; + CUtlString m_meleeImpact; + CUtlString m_pushOff; + CUtlString m_skidStop; +}; - int hitgroup; // 0 == generic, non-zero is specific body part +class CPhysSurfacePropertiesAudio +{ +public: + CPhysSurfacePropertiesAudio() + { + m_reflectivity = 0.0f; + m_hardnessFactor = 0.0f; + m_roughnessFactor = 0.0f; + m_roughThreshold = 0.0f; + m_hardThreshold = 0.0f; + m_hardVelocityThreshold = 0.0f; + m_flStaticImpactVolume = 0.0f; + m_flOcclusionFactor = 0.0f; + } + +public: + float m_reflectivity; + float m_hardnessFactor; + float m_roughnessFactor; + float m_roughThreshold; + float m_hardThreshold; + float m_hardVelocityThreshold; + float m_flStaticImpactVolume; + float m_flOcclusionFactor; +}; - short physicsbone; // physics bone hit by trace in studio - unsigned short worldSurfaceIndex; // Index of the msurface2_t, if applicable +class CPhysSurfaceProperties +{ +public: + CPhysSurfaceProperties() + { + m_bHidden = false; + } + +public: + CUtlString m_name; + uint32 m_nameHash; + uint32 m_baseNameHash; + int32 m_nListIndex; + int32 m_nBaseListIndex; + bool m_bHidden; + CUtlString m_description; + CPhysSurfacePropertiesPhysics m_physics; + CPhysSurfacePropertiesSoundNames m_audioSounds; + CPhysSurfacePropertiesAudio m_audioParams; +}; -#if defined( CLIENT_DLL ) - C_BaseEntity *m_pEnt; -#else - CBaseEntity *m_pEnt; +class CHitBox +{ +public: + CHitBox() + { + m_vMinBounds.Init(); + m_vMaxBounds.Init(); + m_nBoneNameHash = 0; + m_nGroupId = HITGROUP_GENERIC; + m_nShapeType = HITBOX_SHAPE_HULL; + m_bTranslationOnly = false; + m_CRC = 0; + m_cRenderColor.SetColor( 255, 255, 255, 255 ); + m_nHitBoxIndex = 0; + m_bForcedTransform = false; + m_forcedTransform.SetToIdentity(); + } + +public: + CUtlString m_name; + CUtlString m_sSurfaceProperty; + CUtlString m_sBoneName; + Vector m_vMinBounds; + Vector m_vMaxBounds; + float m_flShapeRadius; + uint32 m_nBoneNameHash; + int32 m_nGroupId; + uint8 m_nShapeType; + bool m_bTranslationOnly; + uint32 m_CRC; + Color m_cRenderColor; + uint16 m_nHitBoxIndex; + bool m_bForcedTransform; + CTransform m_forcedTransform; +}; + +class CDefaultHitbox : public CHitBox +{ +public: + CDefaultHitbox() + { + V_strncpy( m_tempName, "invalid_hitbox", sizeof( m_tempName ) ); + V_strncpy( m_tempBoneName, "invalid_bone", sizeof( m_tempBoneName ) ); + V_strncpy( m_tempSurfaceProp, "default", sizeof( m_tempSurfaceProp ) ); + + m_name = m_tempName; + m_sSurfaceProperty = m_tempSurfaceProp; + m_sBoneName = m_tempBoneName; + + m_nBoneNameHash = MurmurHash2LowerCase(m_tempBoneName, 0x31415926); + +#if 0 + if (g_bUpdateStringTokenDatabase) + { + RegisterStringToken(m_nBoneNameHash, m_tempBoneName, 0, true); + } #endif - // NOTE: this member is overloaded. - // If hEnt points at the world entity, then this is the static prop index. - // Otherwise, this is the hitbox index. - int hitbox; // box hit by trace in studio + m_cRenderColor.SetColor( 0, 0, 0, 0 ); + } + +public: + char m_tempName[16]; + char m_tempBoneName[16]; + char m_tempSurfaceProp[16]; +}; - CGameTrace() {} +struct RnQueryShapeAttr_t +{ +public: + RnQueryShapeAttr_t() + { + m_nInteractsWith = 0; + m_nInteractsExclude = 0; + m_nInteractsAs = 0; + + m_nEntityIdsToIgnore[0] = -1; + m_nEntityIdsToIgnore[1] = -1; + + m_nOwnerIdsToIgnore[0] = -1; + m_nOwnerIdsToIgnore[1] = -1; + + m_nHierarchyIds[0] = 0; + m_nHierarchyIds[1] = 0; + + m_nObjectSetMask = RNQUERY_OBJECTS_ALL; + m_nCollisionGroup = COLLISION_GROUP_ALWAYS; + + m_bHitSolid = true; + m_bHitSolidRequiresGenerateContacts = false; + m_bHitTrigger = false; + m_bShouldIgnoreDisabledPairs = true; + m_bIgnoreIfBothInteractWithHitboxes = false; + m_bForceHitEverything = false; + m_bUnknown = true; + } + + bool HasInteractsAsLayer( int nLayerIndex ) const { return ( m_nInteractsAs & ( 1ull << nLayerIndex ) ) != 0; } + bool HasInteractsWithLayer( int nLayerIndex ) const { return ( m_nInteractsWith & ( 1ull << nLayerIndex ) ) != 0; } + bool HasInteractsExcludeLayer( int nLayerIndex ) const { return ( m_nInteractsExclude & ( 1ull << nLayerIndex ) ) != 0; } + void EnableInteractsAsLayer( int nLayer ) { m_nInteractsAs |= ( 1ull << nLayer ); } + void EnableInteractsWithLayer( int nLayer ) { m_nInteractsWith |= ( 1ull << nLayer ); } + void EnableInteractsExcludeLayer( int nLayer ) { m_nInteractsExclude |= ( 1ull << nLayer ); } + void DisableInteractsAsLayer( int nLayer ) { m_nInteractsAs &= ~( 1ull << nLayer ); } + void DisableInteractsWithLayer( int nLayer ) { m_nInteractsWith &= ~( 1ull << nLayer ); } + void DisableInteractsExcludeLayer( int nLayer ) { m_nInteractsExclude &= ~( 1ull << nLayer ); } + +public: + // Which interaction layers do I interact or collide with? (e.g. I collide with LAYER_INDEX_CONTENTS_PASS_BULLETS because I am not a bullet) + // NOTE: This is analogous to the "solid mask" or "trace mask" in source 1 (bit mask of CONTENTS_* or 1<GetRefEHandle().ToInt() : -1; } + void SetPassEntity2( CEntityInstance* pEntity ) { m_nEntityIdsToIgnore[1] = pEntity ? pEntity->GetRefEHandle().ToInt() : -1; } + + void SetPassEntityOwner1( CEntityInstance* pOwner ) { m_nOwnerIdsToIgnore[0] = pOwner ? pOwner->GetRefEHandle().ToInt() : -1; } + void SetPassEntityOwner2( CEntityInstance* pOwner ) { m_nOwnerIdsToIgnore[1] = pOwner ? pOwner->GetRefEHandle().ToInt() : -1; } + + virtual ~CTraceFilter() {} + virtual bool ShouldHitEntity( CEntityInstance* pEntity ) { return true; } + +public: + bool m_bIterateEntities; // if true then calls ShouldHitEntity for each hit entity +}; + +struct RnCollisionAttr_t +{ +public: + RnCollisionAttr_t() + { + m_nInteractsAs = 0; + m_nInteractsWith = 0; + m_nInteractsExclude = 0; + m_nEntityId = 0; + m_nOwnerId = -1; + m_nHierarchyId = 0; + m_nCollisionGroup = COLLISION_GROUP_ALWAYS; + m_nCollisionFunctionMask = FCOLLISION_FUNC_DEFAULT; + } + + bool IsSolidContactEnabled() const { return ( m_nCollisionFunctionMask & FCOLLISION_FUNC_ENABLE_SOLID_CONTACT ) != 0; } + bool IsTraceAndQueryEnabled() const { return ( m_nCollisionFunctionMask & FCOLLISION_FUNC_ENABLE_TRACE_QUERY ) != 0; } + bool IsTouchEventEnabled() const { return ( m_nCollisionFunctionMask & FCOLLISION_FUNC_ENABLE_TOUCH_EVENT ) != 0; } + bool IsSelfCollisionsEnabled() const { return ( m_nCollisionFunctionMask & FCOLLISION_FUNC_ENABLE_SELF_COLLISIONS ) != 0; } + bool ShouldIgnoreForHitboxTest() const { return ( m_nCollisionFunctionMask & FCOLLISION_FUNC_IGNORE_FOR_HITBOX_TEST ) != 0; } + bool IsTouchPersistsEnabled() const { return ( m_nCollisionFunctionMask & FCOLLISION_FUNC_ENABLE_TOUCH_PERSISTS ) != 0; } + + bool HasInteractsAsLayer( int nLayerIndex ) const { return ( m_nInteractsAs & ( 1ull << nLayerIndex ) ) != 0; } + bool HasInteractsWithLayer( int nLayerIndex ) const { return ( m_nInteractsWith & ( 1ull << nLayerIndex ) ) != 0; } + bool HasInteractsExcludeLayer( int nLayerIndex ) const { return ( m_nInteractsExclude & ( 1ull << nLayerIndex ) ) != 0; } + void EnableInteractsAsLayer( int nLayer ) { m_nInteractsAs |= ( 1ull << nLayer ); } + void EnableInteractsWithLayer( int nLayer ) { m_nInteractsWith |= ( 1ull << nLayer ); } + void EnableInteractsExcludeLayer( int nLayer ) { m_nInteractsExclude |= ( 1ull << nLayer ); } + void DisableInteractsAsLayer( int nLayer ) { m_nInteractsAs &= ~( 1ull << nLayer ); } + void DisableInteractsWithLayer( int nLayer ) { m_nInteractsWith &= ~( 1ull << nLayer ); } + void DisableInteractsExcludeLayer( int nLayer ) { m_nInteractsExclude &= ~( 1ull << nLayer ); } + +public: + // Which interaction layers do I represent? (e.g. I am a LAYER_INDEX_CONTENTS_PLAYER_CLIP volume) + // NOTE: This is analogous to "contents" in source 1 (bit mask of CONTENTS_* or 1<