BVB Source Codes

CRYENGINE Show WorldQuery.cpp Source code

Return Download CRYENGINE: download WorldQuery.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include "GameObjects/GameObject.h"
  5. #include "WorldQuery.h"
  6. #include "CryAction.h"
  7. #include "IActorSystem.h"
  8. #include "IViewSystem.h"
  9. #include "IMovementController.h"
  10.  
  11. static const float AROUND_X = 2.0f;
  12. static const float AROUND_Y = 2.0f;
  13. static const float AROUND_Z = 2.0f;
  14.  
  15. #define PIERCE_GLASS                     (13)
  16. #define ENTITY_GRID_PROXIMITY_MULTIPLIER 2
  17.  
  18. CWorldQuery::UpdateQueryFunction CWorldQuery::m_updateQueryFunctions[] =
  19. {
  20.         &CWorldQuery::UpdateRaycastQuery,
  21.         &CWorldQuery::UpdateProximityQuery,
  22.         &CWorldQuery::UpdateInFrontOfQuery,
  23.         &CWorldQuery::UpdateBackRaycastQuery,
  24.         &CWorldQuery::UpdateEntitiesAround,
  25.         &CWorldQuery::UpdatePhysicalEntitiesAround,
  26.         &CWorldQuery::UpdatePhysicalEntityInFrontOf,
  27. };
  28.  
  29. namespace
  30. {
  31. class CCompareEntitiesByDistanceFromPoint
  32. {
  33. public:
  34.         CCompareEntitiesByDistanceFromPoint(const Vec3& point) : m_point(point), m_pEntitySystem(gEnv->pEntitySystem) {}
  35.  
  36.         bool operator()(IEntity* pEnt0, IEntity* pEnt1) const
  37.         {
  38.                 float distSq0 = (pEnt0->GetPos() - m_point).GetLengthSquared();
  39.                 float distSq1 = (pEnt1->GetPos() - m_point).GetLengthSquared();
  40.                 return distSq0 < distSq1;
  41.         }
  42.  
  43. private:
  44.         Vec3           m_point;
  45.         IEntitySystem* m_pEntitySystem;
  46. };
  47.  
  48. }
  49.  
  50. CWorldQuery::CWorldQuery()
  51.         : m_physicalEntityInFrontOf(-100)
  52. {
  53.         m_worldPosition = Vec3(ZERO);
  54.         m_dir = Vec3(0, 1, 0);
  55.         m_pActor = NULL;
  56.         m_lookAtEntityId = 0;
  57.         m_validQueries = 0;
  58.         m_proximityRadius = 5.0f;
  59.         m_pEntitySystem = gEnv->pEntitySystem;
  60.         m_pPhysWorld = gEnv->pPhysicalWorld;
  61.         m_pViewSystem = CCryAction::GetCryAction()->GetIViewSystem();
  62.         m_rayHitAny = false;
  63.         m_backRayHitAny = false;
  64.         m_renderFrameId = -1;
  65.         m_rayHitPierceable.dist = -1.0f;
  66.  
  67. #if WORLDQUERY_USE_DEFERRED_LINETESTS
  68.         m_timeLastDeferredResult = 0.0f;
  69.         m_requestCounter = 0;
  70. #endif
  71. }
  72.  
  73. CWorldQuery::~CWorldQuery()
  74. {
  75. #if WORLDQUERY_USE_DEFERRED_LINETESTS
  76.         for (int i = 0; i < kMaxQueuedRays; ++i)
  77.         {
  78.                 m_queuedRays[i].Reset();
  79.         }
  80. #endif
  81. }
  82.  
  83. bool CWorldQuery::Init(IGameObject* pGameObject)
  84. {
  85.         SetGameObject(pGameObject);
  86.         m_pActor = CCryAction::GetCryAction()->GetIActorSystem()->GetActor(GetEntityId());
  87.         if (!m_pActor)
  88.         {
  89.                 GameWarning("WorldQuery extension only available for actors");
  90.                 return false;
  91.         }
  92.         return true;
  93. }
  94.  
  95. void CWorldQuery::PostInit(IGameObject* pGameObject)
  96. {
  97.         pGameObject->EnableUpdateSlot(this, 0);
  98. }
  99.  
  100. bool CWorldQuery::ReloadExtension(IGameObject* pGameObject, const SEntitySpawnParams& params)
  101. {
  102.         ResetGameObject();
  103.  
  104.         CRY_ASSERT_MESSAGE(false, "CWorldQuery::ReloadExtension not implemented");
  105.  
  106.         return false;
  107. }
  108.  
  109. void CWorldQuery::Release()
  110. {
  111.         delete this;
  112. }
  113.  
  114. void CWorldQuery::FullSerialize(TSerialize ser)
  115. {
  116.         if (ser.GetSerializationTarget() == eST_Network)
  117.                 return;
  118.  
  119.         ser.Value("proximityRadius", m_proximityRadius);
  120.         m_validQueries = 0;
  121.  
  122.         if (GetISystem()->IsSerializingFile() == 1)
  123.         {
  124.                 m_pActor = CCryAction::GetCryAction()->GetIActorSystem()->GetActor(GetEntityId());
  125.                 CRY_ASSERT(m_pActor);
  126.         }
  127. }
  128.  
  129. void CWorldQuery::Update(SEntityUpdateContext& ctx, int slot)
  130. {
  131.         //m_validQueries = 0;
  132.         //m_renderFrameId = gEnv->pRenderer->GetFrameID();
  133.  
  134.         if (!m_pActor)
  135.                 return;
  136.  
  137.         IMovementController* pMC = (m_pActor != NULL) ? m_pActor->GetMovementController() : NULL;
  138.         if (pMC)
  139.         {
  140.                 SMovementState s;
  141.                 pMC->GetMovementState(s);
  142.                 m_worldPosition = s.eyePosition;
  143.                 m_dir = s.eyeDirection;
  144.         }
  145. }
  146.  
  147. void CWorldQuery::UpdateRaycastQuery()
  148. {
  149.         if (!m_pActor || m_pActor->GetEntity()->IsHidden())
  150.                 return;
  151.  
  152.         IEntity* pEntity = m_pActor->GetEntity();
  153.         IPhysicalEntity* pPhysEnt = pEntity ? pEntity->GetPhysics() : NULL;
  154.  
  155.         static const int obj_types = ent_all; // ent_terrain|ent_static|ent_rigid|ent_sleeping_rigid|ent_living;
  156.         static const unsigned int flags = rwi_pierceability(PIERCE_GLASS) | rwi_colltype_any;
  157.  
  158. #if WORLDQUERY_USE_DEFERRED_LINETESTS
  159.         IPhysicalEntity* skipEntities[1];
  160.         skipEntities[0] = pPhysEnt;
  161.  
  162.         int raySlot = GetRaySlot();
  163.         CRY_ASSERT(raySlot != -1);
  164.  
  165.         m_queuedRays[raySlot].rayId = CCryAction::GetCryAction()->GetPhysicQueues().GetRayCaster().Queue(
  166.           RayCastRequest::HighPriority,
  167.           RayCastRequest(m_worldPosition, 300.0f * m_dir,
  168.                          obj_types,
  169.                          flags,
  170.                          skipEntities,
  171.                          pPhysEnt ? 1 : 0, 2),
  172.           functor(*this, &CWorldQuery::OnRayCastDataReceived));
  173.  
  174.         m_queuedRays[raySlot].counter = ++m_requestCounter;
  175.  
  176.         static const float k_maxTimeRaycastStaysValid = 0.1f;
  177.  
  178.         const float frameStartTime = gEnv->pTimer->GetCurrTime();
  179.         const float timeSinceLastDeferred = (frameStartTime - m_timeLastDeferredResult);
  180.         if (timeSinceLastDeferred > k_maxTimeRaycastStaysValid)
  181.         {
  182.                 // it's been too long since the last deferred raycast result assume hit nothing
  183.                 m_rayHitAny = false;
  184.                 m_lookAtEntityId = 0;
  185.                 //CryLogAlways("CWorldQuery::UpdateRaycastQuery() - frameStartTime=%f; it's been too long (%f) since the last deferred raycast result, assuming hit nothing\n", frameStartTime, timeSinceLastDeferred);
  186.         }
  187. #else // WORLDQUERY_USE_DEFERRED_LINETESTS
  188.         m_rayHitAny = 0 != m_pPhysWorld->RayWorldIntersection(m_worldPosition, 300.0f * m_dir, obj_types, flags, &m_rayHit, 1, pPhysEnt);
  189.         if (m_rayHitAny)
  190.         {
  191.                 IEntity* pLookAt = m_pEntitySystem->GetEntityFromPhysics(m_rayHit.pCollider);
  192.                 if (pLookAt)
  193.                 {
  194.                         m_lookAtEntityId = pLookAt->GetId();
  195.                         //m_rayHit.pCollider=0; // -- commented until a better solution is thought of.
  196.                 }
  197.                 else
  198.                         m_lookAtEntityId = 0;
  199.         }
  200.         else
  201.                 m_lookAtEntityId = 0;
  202.  
  203.         //      if (m_rayHitAny)
  204.         //              CryLogAlways( "HIT: terrain:%i distance:%f (%f,%f,%f)", m_rayHit.bTerrain, m_rayHit.dist, m_rayHit.pt.x, m_rayHit.pt.y, m_rayHit.pt.z );
  205. #endif // WORLDQUERY_USE_DEFERRED_LINETESTS
  206. }
  207.  
  208. void CWorldQuery::UpdateBackRaycastQuery()
  209. {
  210.         if (!m_pActor)
  211.                 return;
  212.         IEntity* pEntity = m_pEntitySystem->GetEntity(m_pActor->GetEntityId());
  213.         IPhysicalEntity* pPhysEnt = pEntity ? pEntity->GetPhysics() : NULL;
  214.  
  215.         static const int obj_types = ent_all; // ent_terrain|ent_static|ent_rigid|ent_sleeping_rigid|ent_living;
  216.         static const unsigned int flags = rwi_stop_at_pierceable | rwi_colltype_any;
  217.         m_backRayHitAny = 0 != m_pPhysWorld->RayWorldIntersection(m_worldPosition, -100.0f * m_dir, obj_types, flags, &m_backRayHit, 1, pPhysEnt);
  218. }
  219.  
  220. void CWorldQuery::UpdateProximityQuery()
  221. {
  222.         EntityId ownerActorId = m_pActor ? m_pActor->GetEntityId() : 0;
  223.  
  224.         m_proximity.resize(0);
  225.  
  226.         SEntityProximityQuery qry;
  227.         const float entityGridProxRadius = m_proximityRadius * ENTITY_GRID_PROXIMITY_MULTIPLIER;
  228.         qry.box = AABB(Vec3(m_worldPosition.x - entityGridProxRadius, m_worldPosition.y - entityGridProxRadius, m_worldPosition.z - entityGridProxRadius),
  229.                        Vec3(m_worldPosition.x + entityGridProxRadius, m_worldPosition.y + entityGridProxRadius, m_worldPosition.z + entityGridProxRadius));
  230.  
  231.         m_pEntitySystem->QueryProximity(qry);
  232.         m_proximity.reserve(qry.nCount);
  233.         for (int i = 0; i < qry.nCount; i++)
  234.         {
  235.                 IEntity* pEntity = qry.pEntities[i];
  236.                 EntityId entityId = pEntity ? pEntity->GetId() : 0;
  237.  
  238.                 //skip the user
  239.                 if (!entityId || (entityId == ownerActorId))
  240.                         continue;
  241.  
  242.                 const Vec3 entityWorldPos = pEntity->GetWorldPos();
  243.  
  244.                 //Check height, entity grid is 2D
  245.                 const float heightThreshold = m_proximityRadius * 1.2f;
  246.                 if (fabs_tpl(entityWorldPos.z - m_worldPosition.z) > heightThreshold)
  247.                         continue;
  248.  
  249.                 //Check flat (2D) distance
  250.                 AABB aabb;
  251.                 pEntity->GetWorldBounds(aabb);
  252.                 aabb.min.z = aabb.max.z = m_worldPosition.z;
  253.  
  254.                 const float flatDistanceSqr = (m_proximityRadius * m_proximityRadius);
  255.                 if (aabb.GetDistanceSqr(m_worldPosition) > flatDistanceSqr)
  256.                         continue;
  257.  
  258.                 m_proximity.push_back(entityId);
  259.         }
  260. }
  261.  
  262. void CWorldQuery::UpdateInFrontOfQuery()
  263. {
  264.         EntityId ownerActorId = m_pActor ? m_pActor->GetEntityId() : 0;
  265.  
  266.         m_inFrontOf.resize(0);
  267.         Lineseg lineseg(m_worldPosition, m_worldPosition + m_proximityRadius * m_dir);
  268.  
  269.         SEntityProximityQuery qry;
  270.         //qry.pEntityClass=0;
  271.         qry.box = AABB(Vec3(m_worldPosition.x - m_proximityRadius, m_worldPosition.y - m_proximityRadius, m_worldPosition.z - m_proximityRadius),
  272.                        Vec3(m_worldPosition.x + m_proximityRadius, m_worldPosition.y + m_proximityRadius, m_worldPosition.z + m_proximityRadius));
  273.         m_pEntitySystem->QueryProximity(qry);
  274.         int n = qry.nCount;
  275.         m_inFrontOf.reserve(n);
  276.  
  277.         IEntity* pEntity;
  278.  
  279.         for (int i = 0; i < n; ++i)
  280.         {
  281.                 pEntity = qry.pEntities[i];
  282.  
  283.                 //skip the user
  284.                 if (!pEntity || (pEntity->GetId() == ownerActorId))
  285.                         continue;
  286.  
  287.                 AABB bbox;
  288.                 pEntity->GetLocalBounds(bbox);
  289.                 if (!bbox.IsEmpty())
  290.                 {
  291.                         OBB obb(OBB::CreateOBBfromAABB(Matrix33(pEntity->GetWorldTM()), bbox));
  292.                         if (Overlap::Lineseg_OBB(lineseg, pEntity->GetWorldPos(), obb))
  293.                                 m_inFrontOf.push_back(pEntity->GetId());
  294.                 }
  295.         }
  296. }
  297.  
  298. void CWorldQuery::HandleEvent(const SGameObjectEvent&)
  299. {
  300. }
  301.  
  302. void CWorldQuery::GetMemoryUsage(ICrySizer* pSizer) const
  303. {
  304.         pSizer->AddObject(this, sizeof(*this));
  305.         //pSizer->AddObject(m_PhysEntAroundOf);
  306.         pSizer->AddObject(m_proximity);
  307.         pSizer->AddObject(m_inFrontOf);
  308.         pSizer->AddObject(m_EntAroundOf);
  309. }
  310.  
  311. void CWorldQuery::UpdatePhysicalEntitiesAround()
  312. {
  313.         if (!m_pActor)
  314.         {
  315.                 m_PhysEntAroundOf.resize(0);
  316.                 return;
  317.         }
  318.         Vec3 checkOffset(AROUND_X, AROUND_Y, AROUND_Z);
  319.         //
  320.         IPhysicalEntity** ppList = NULL;
  321.         int numEntities = gEnv->pPhysicalWorld->GetEntitiesInBox(m_worldPosition - checkOffset, m_worldPosition + checkOffset, ppList, ent_static | ent_sleeping_rigid | ent_rigid | ent_living);
  322.         m_PhysEntAroundOf.resize(numEntities);
  323.         for (int i = 0; i < numEntities; ++i)
  324.         {
  325.                 m_PhysEntAroundOf[i] = ppList[i];
  326.         }
  327. }
  328.  
  329. void CWorldQuery::UpdatePhysicalEntityInFrontOf()
  330. {
  331.         const int objectTypes = ent_static | ent_sleeping_rigid | ent_rigid | ent_living;
  332.         const unsigned int flags = ent_all;
  333.  
  334.         ray_hit rayHitResult;
  335.         const int numberOfHits = gEnv->pPhysicalWorld->RayWorldIntersection(m_worldPosition, m_proximityRadius * m_dir, objectTypes, flags, &rayHitResult, 1, (IPhysicalEntity*)0);
  336.  
  337.         m_physicalEntityInFrontOf = -100; // Anton said it's a safe value to initialise my var with
  338.  
  339.         if (numberOfHits > 0)
  340.         {
  341.                 m_physicalEntityInFrontOf = gEnv->pPhysicalWorld->GetPhysicalEntityId(rayHitResult.pCollider);
  342.         }
  343. }
  344.  
  345. void CWorldQuery::UpdateEntitiesAround()
  346. {
  347.         if (!m_pActor)
  348.         {
  349.                 m_EntAroundOf.resize(0);
  350.                 return;
  351.         }
  352.         //
  353.         Vec3 checkOffset(AROUND_X, AROUND_Y, AROUND_Z);
  354.         //
  355.         SEntityProximityQuery qry;
  356.         qry.box.min = m_worldPosition - checkOffset;
  357.         qry.box.max = m_worldPosition + checkOffset;
  358.         qry.nEntityFlags = ~0;
  359.         gEnv->pEntitySystem->QueryProximity(qry);
  360.         m_EntAroundOf.resize(qry.nCount);
  361.         for (int i = 0; i < qry.nCount; i++)
  362.         {
  363.                 m_EntAroundOf[i] = qry.pEntities[i]->GetId();
  364.         }
  365.         // add to ent list if available in phys list
  366.         int physEntListSize = 0;
  367.         IPhysicalEntity* const* physEntList = this->GetPhysicalEntitiesAround(physEntListSize);
  368.         for (size_t n = 0; n < physEntListSize; n++)
  369.         {
  370.                 IEntity* ent = gEnv->pEntitySystem->GetEntityFromPhysics(physEntList[n]);
  371.                 if (ent)
  372.                 {
  373.                         if (std::find(m_EntAroundOf.begin(), m_EntAroundOf.end(), ent->GetId()) == m_EntAroundOf.end())
  374.                         {
  375.                                 m_EntAroundOf.push_back(ent->GetId());
  376.                         }
  377.                 }
  378.         }
  379. }
  380.  
  381. #if WORLDQUERY_USE_DEFERRED_LINETESTS
  382. //async raycasts results callback
  383. void CWorldQuery::OnRayCastDataReceived(const QueuedRayID& rayID, const RayCastResult& result)
  384. {
  385.         int raySlot = GetSlotForRay(rayID);
  386.         CRY_ASSERT(raySlot != -1);
  387.  
  388.         if (raySlot != -1)
  389.         {
  390.                 m_queuedRays[raySlot].rayId = 0;
  391.                 m_queuedRays[raySlot].counter = 0;
  392.         }
  393.  
  394.         // these need setting
  395.         // m_rayHitAny
  396.         // m_lookAtEntityId
  397.         const bool rayHitSucced = (result.hitCount > 0);
  398.         EntityId entityIdHit = 0;
  399.  
  400.         m_rayHitPierceable.dist = -1.f;
  401.  
  402.         if (rayHitSucced)
  403.         {
  404.                 // only because the raycast is being done with  rwi_stop_at_pierceable can we rely on there being only 1
  405.                 // hit. Otherwise hit[0] is always the solid hit (and thus the last), hit[1-n] are then first to last-1 in order of distance
  406.                 IEntity* pEntity = gEnv->pEntitySystem->GetEntityFromPhysics(result.hits[0].pCollider);
  407.  
  408.                 //Check if it's the child or not
  409.                 int partId = result.hits[0].partid;
  410.                 if (partId && pEntity)
  411.                 {
  412.                         pEntity = pEntity->UnmapAttachedChild(partId);
  413.                 }
  414.  
  415.                 if (pEntity)
  416.                 {
  417.                         entityIdHit = pEntity->GetId();
  418.                 }
  419.  
  420.                 m_rayHitSolid = result.hits[0];
  421.  
  422.                 //It is not safe to access this, since the result can be kept multiple frames
  423.                 //Yet other data of the hit can be useful, and the entity Id is also remembered.
  424.                 m_rayHitSolid.pCollider = NULL;
  425.                 m_rayHitSolid.next = NULL;
  426.  
  427.                 if (result.hitCount > 1)
  428.                 {
  429.                         m_rayHitPierceable = result.hits[1];
  430.                         m_rayHitPierceable.pCollider = NULL;
  431.                         m_rayHitPierceable.next = NULL;
  432.                 }
  433.         }
  434.  
  435.         m_timeLastDeferredResult = gEnv->pTimer->GetCurrTime();
  436.  
  437.         m_rayHitAny = rayHitSucced;
  438.         m_lookAtEntityId = entityIdHit;
  439. }
  440.  
  441. int CWorldQuery::GetRaySlot()
  442. {
  443.         for (int i = 0; i < kMaxQueuedRays; ++i)
  444.         {
  445.                 if (m_queuedRays[i].rayId == 0)
  446.                 {
  447.                         return i;
  448.                 }
  449.         }
  450.  
  451.         //Find out oldest request and remove it
  452.         uint32 oldestCounter = m_requestCounter + 1;
  453.         int oldestSlot = 0;
  454.         for (int i = 0; i < kMaxQueuedRays; ++i)
  455.         {
  456.                 if (m_queuedRays[i].counter < oldestCounter)
  457.                 {
  458.                         oldestCounter = m_queuedRays[i].counter;
  459.                         oldestSlot = i;
  460.                 }
  461.         }
  462.  
  463.         m_queuedRays[oldestSlot].Reset();
  464.  
  465.         return oldestSlot;
  466. }
  467.  
  468. int CWorldQuery::GetSlotForRay(const QueuedRayID& rayId) const
  469. {
  470.         for (int i = 0; i < kMaxQueuedRays; ++i)
  471.         {
  472.                 if (m_queuedRays[i].rayId == rayId)
  473.                 {
  474.                         return i;
  475.                 }
  476.         }
  477.  
  478.         return -1;
  479. }
  480.  
  481. #endif
  482.  
downloadWorldQuery.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top