1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 /********************************************************************
4 ---------------------------------------------------------------------
8 Description: Manager per-actor signals to other actors by range
9 ---------------------------------------------------------------------
11 - 09:04:2007 : Created by Ricardo Pillosu
13 *********************************************************************/
15 #include "PersonalRangeSignaling.h"
16 #include "RangeSignaling.h"
18 #include "AngleAlert.h"
22 #include <CryAISystem/IAIObject.h>
30 CPersonalRangeSignaling::CPersonalRangeSignaling(CRangeSignaling
* pParent
) : m_bInit(false), m_bEnabled(false), m_pParent(pParent
), m_EntityId(0)
32 CRY_ASSERT(pParent
!= NULL
);
34 m_pDefaultFont
= gEnv
->pCryFont
->GetFont("default");
35 CRY_ASSERT(m_pDefaultFont
);
44 CPersonalRangeSignaling::~CPersonalRangeSignaling()
48 for (int i
= 0; i
< m_vecRanges
.size(); ++i
)
50 SAFE_DELETE(m_vecRanges
[i
]);
55 MapTargetRanges::iterator itTargetRange
= m_mapTargetRanges
.begin();
56 MapTargetRanges::iterator itTargetRangeEnd
= m_mapTargetRanges
.end();
57 for (; itTargetRange
!= itTargetRangeEnd
; ++itTargetRange
)
59 for (int i
= 0; i
< itTargetRange
->second
.size(); ++i
)
61 SAFE_DELETE(itTargetRange
->second
[i
]);
65 m_mapTargetRanges
.clear();
67 for (int i
= 0; i
< m_vecAngles
.size(); ++i
)
69 SAFE_DELETE(m_vecAngles
[i
]);
83 bool CPersonalRangeSignaling::Init(EntityId Id
)
85 CRY_ASSERT(m_bInit
== false);
90 // Enabled state starts off matching proxy's state
91 IAIActorProxy
* pAIProxy
= GetEntityAIProxy(m_EntityId
);
92 SetEnabled(pAIProxy
&& pAIProxy
->IsEnabled());
94 if (GetActor() == NULL
)
106 // Description: std::less functor template specialization, so to make comparison of two CRange pointers
109 // Arguments: two pointers to CRange instances
111 // Return: comparison result
119 bool operator()(const CRange
* pRange1
, const CRange
* pRange2
) const
121 CRY_ASSERT(pRange1
!= NULL
);
122 CRY_ASSERT(pRange2
!= NULL
);
124 return((*pRange1
) < (*pRange2
));
130 bool CompareRange(CRange
* pRange1
, CRange
* pRange2
)
132 CRY_ASSERT(pRange1
!= NULL
);
133 CRY_ASSERT(pRange2
!= NULL
);
135 return((*pRange1
) < (*pRange2
));
138 bool CompareAngle(CAngleAlert
* pAngle1
, CAngleAlert
* pAngle2
)
140 CRY_ASSERT(pAngle1
!= NULL
);
141 CRY_ASSERT(pAngle2
!= NULL
);
143 return((*pAngle1
) < (*pAngle2
));
152 bool CPersonalRangeSignaling::AddRangeSignal(float fRadius
, float fBoundary
, const char* sSignal
, IAISignalExtraData
* pData
/*=NULL*/)
154 CRY_ASSERT(m_bInit
== true);
155 CRY_ASSERT(sSignal
!= NULL
);
156 CRY_ASSERT(fRadius
> 0.5f
);
157 CRY_ASSERT(fBoundary
>= 0.0f
);
160 CRange
* pRange
= SearchRange(sSignal
, m_vecRanges
);
164 pRange
= new CRange(this);
165 m_vecRanges
.push_back(pRange
);
168 pRange
->Init(fRadius
, fBoundary
, sSignal
, pData
);
169 std::sort(m_vecRanges
.begin(), m_vecRanges
.end(), &CompareRange
); // std::less is properly overridden
180 bool CPersonalRangeSignaling::AddTargetRangeSignal(EntityId IdTarget
, float fRadius
, float fBoundary
, const char* sSignal
, IAISignalExtraData
* pData
/*= NULL*/)
182 CRY_ASSERT(m_bInit
== true);
183 CRY_ASSERT(GetActor());
184 CRY_ASSERT(IdTarget
> 0);
185 CRY_ASSERT(sSignal
!= NULL
);
186 CRY_ASSERT(fRadius
> 0.5f
);
187 CRY_ASSERT(fBoundary
>= 0.0f
);
190 CRange
* pRange
= SearchRange(sSignal
, m_mapTargetRanges
[IdTarget
]);
194 pRange
= new CRange(this);
195 m_mapTargetRanges
[IdTarget
].push_back(pRange
);
198 pRange
->Init(fRadius
, fBoundary
, sSignal
, pData
);
199 std::sort(m_mapTargetRanges
[IdTarget
].begin(), m_mapTargetRanges
[IdTarget
].end(), &CompareRange
); // std::less is properly overridden
210 bool CPersonalRangeSignaling::AddAngleSignal(float fAngle
, float fBoundary
, const char* sSignal
, IAISignalExtraData
* pData
/*=NULL*/)
212 CRY_ASSERT(m_bInit
== true);
213 CRY_ASSERT(sSignal
!= NULL
);
214 CRY_ASSERT(fAngle
> 0.5f
);
215 CRY_ASSERT(fBoundary
>= 0.0f
);
218 CAngleAlert
* pAngle
= SearchAngle(sSignal
);
222 pAngle
= new CAngleAlert(this);
223 m_vecAngles
.push_back(pAngle
);
226 pAngle
->Init(fAngle
, fBoundary
, sSignal
, pData
);
227 std::sort(m_vecAngles
.begin(), m_vecAngles
.end(), &CompareAngle
);
238 bool CPersonalRangeSignaling::Update(float fElapsedTime
, uint32 uDebugOrder
)
240 CRY_ASSERT(m_bInit
== true);
248 DebugDraw(uDebugOrder
);
251 // Iterate all actors and check range to them
252 IActorIteratorPtr pActorIt
= CCryAction::GetCryAction()->GetIActorSystem()->CreateActorIterator();
253 while (IActor
* pActor
= pActorIt
->Next())
255 EntityId entityId
= pActor
->GetEntityId();
256 if (entityId
!= GetEntityId())
258 // Skip over if not enabled
259 IAIObject
const* pAIObject
= GetEntityAI(entityId
);
260 if (!pAIObject
|| pAIObject
->IsEnabled())
262 CheckActorRanges(pActor
);
263 CheckActorAngles(pActor
);
265 // Do check on target ranges
266 MapTargetRanges::iterator itTargetRanges
= m_mapTargetRanges
.find(entityId
);
267 if (itTargetRanges
!= m_mapTargetRanges
.end())
269 CheckActorTargetRanges(pActor
);
287 void CPersonalRangeSignaling::CheckActorRanges(IActor
* pActor
)
289 CRY_ASSERT(pActor
!= NULL
);
291 MapRangeSignals::iterator it
= m_mapRangeSignalsSent
.find(pActor
->GetEntityId());
292 CRange
const* pRange
= GetRangeTo(pActor
->GetEntity()->GetPos(), m_vecRanges
);
293 CRange
const* pOldRange
= ((it
!= m_mapRangeSignalsSent
.end()) ? it
->second
: NULL
);
295 if (pRange
!= pOldRange
)
300 if (GetRangeTo(pActor
->GetEntity()->GetPos(), m_vecRanges
, true) != pOldRange
)
302 if (pOldRange
== NULL
)
304 m_mapRangeSignalsSent
.insert(std::pair
<EntityId
, CRange
const*>(pActor
->GetEntityId(), pRange
));
311 SendSignal(pActor
, pRange
->GetSignal(), pRange
->GetSignalData());
316 m_mapRangeSignalsSent
.erase(it
);
327 void CPersonalRangeSignaling::CheckActorTargetRanges(IActor
* pActor
)
329 CRY_ASSERT(pActor
!= NULL
);
331 MapTargetRanges::iterator itTargetRanges
= m_mapTargetRanges
.find(pActor
->GetEntityId());
332 CRY_ASSERT(itTargetRanges
!= m_mapTargetRanges
.end());
334 MapRangeSignals::iterator it
= m_mapTargetRangeSignalsSent
.find(pActor
->GetEntityId());
335 CRange
const* pRange
= GetRangeTo(pActor
->GetEntity()->GetPos(), itTargetRanges
->second
);
336 CRange
const* pOldRange
= ((it
!= m_mapTargetRangeSignalsSent
.end()) ? it
->second
: NULL
);
338 if (pRange
!= pOldRange
)
343 if (GetRangeTo(pActor
->GetEntity()->GetPos(), itTargetRanges
->second
, true) != pOldRange
)
345 if (pOldRange
== NULL
)
347 m_mapTargetRangeSignalsSent
.insert(std::pair
<EntityId
, CRange
const*>(pActor
->GetEntityId(), pRange
));
354 IActor
* pMe
= GetActor();
355 CRY_ASSERT_MESSAGE(pMe
, "An actor has been removed without cleaning up its range signals.");
358 SendSignal(pMe
, pRange
->GetSignal(), pRange
->GetSignalData());
364 m_mapTargetRangeSignalsSent
.erase(it
);
375 void CPersonalRangeSignaling::CheckActorAngles(IActor
* pActor
)
377 CRY_ASSERT(pActor
!= NULL
);
379 MapAngleSignals::iterator it
= m_mapAngleSignalsSent
.find(pActor
->GetEntityId());
380 CAngleAlert
const* pAngle
= GetAngleTo(pActor
->GetEntity()->GetPos());
381 CAngleAlert
const* pOldAngle
= ((it
!= m_mapAngleSignalsSent
.end()) ? it
->second
: NULL
);
383 if (pAngle
!= pOldAngle
)
388 if (GetAngleTo(pActor
->GetEntity()->GetPos(), true) != pOldAngle
)
390 if (pOldAngle
== NULL
)
392 m_mapAngleSignalsSent
.insert(std::pair
<EntityId
, CAngleAlert
const*>(pActor
->GetEntityId(), pAngle
));
399 SendSignal(pActor
, pAngle
->GetSignal(), pAngle
->GetSignalData());
404 m_mapAngleSignalsSent
.erase(it
);
415 void CPersonalRangeSignaling::Reset()
417 m_mapRangeSignalsSent
.clear();
418 m_mapTargetRangeSignalsSent
.clear();
419 m_mapAngleSignalsSent
.clear();
420 m_mapTargetRanges
.clear();
429 void CPersonalRangeSignaling::OnProxyReset()
441 void CPersonalRangeSignaling::SetEnabled(bool bEnable
)
443 CRY_ASSERT(m_bInit
== true);
445 m_bEnabled
= bEnable
;
454 EntityId
CPersonalRangeSignaling::GetEntityId() const
456 CRY_ASSERT(m_bInit
== true);
467 IEntity
* CPersonalRangeSignaling::GetEntity()
469 CRY_ASSERT(m_bInit
== true);
471 return(gEnv
->pEntitySystem
->GetEntity(m_EntityId
));
480 IEntity
const* CPersonalRangeSignaling::GetEntity() const
482 CRY_ASSERT(m_bInit
== true);
484 return(gEnv
->pEntitySystem
->GetEntity(m_EntityId
));
493 IActor
* CPersonalRangeSignaling::GetActor()
495 CRY_ASSERT(m_bInit
== true);
497 return(CCryAction::GetCryAction()->GetIActorSystem()->GetActor(m_EntityId
));
506 void CPersonalRangeSignaling::SendSignal(IActor
* pActor
, const string
& sSignal
, IAISignalExtraData
* pData
/*= NULL*/) const
508 CRY_ASSERT(m_bInit
== true);
509 CRY_ASSERT(pActor
!= NULL
);
510 CRY_ASSERT(sSignal
.length() > 0);
512 IAIObject
* pAI
= pActor
->GetEntity()->GetAI();
513 //CRY_ASSERT(pAI); Not every actor has an ai, and nor do they need it
514 if (pAI
&& gEnv
->pAISystem
)
516 gEnv
->pAISystem
->SendSignal(SIGNALFILTER_SENDER
, 1, sSignal
, pAI
, PrepareSignalData(pData
));
526 IAISignalExtraData
* CPersonalRangeSignaling::PrepareSignalData(IAISignalExtraData
* pRequestedData
) const
528 IAISignalExtraData
* pSendData
= gEnv
->pAISystem
->CreateSignalExtraData();
531 // Clone requested data and send it over
532 *pSendData
= *pRequestedData
;
537 pSendData
->nID
= GetEntityId();
538 pSendData
->point
= (GetEntity() ? GetEntity()->GetWorldPos() : Vec3Constants
<float>::fVec3_Zero
);
550 CRange
const* CPersonalRangeSignaling::GetRangeTo(const Vec3
& vPos
, const VecRanges
& vecRangeList
, bool bUseBoundary
) const
552 IEntity
const* pEntity
= GetEntity();
556 CRange
const* pRange
= NULL
;
557 Vec3 vOrigin
= pEntity
->GetPos();
558 float fSquaredDist
= (vPos
- vOrigin
).GetLengthSquared();
560 for (int i
= 0; i
< vecRangeList
.size(); ++i
)
562 bool bInRange
= false;
564 if (bUseBoundary
== true)
566 bInRange
= (vecRangeList
[i
]->IsInRangePlusBoundary(fSquaredDist
) == true);
570 bInRange
= (vecRangeList
[i
]->IsInRange(fSquaredDist
) == true);
573 if (bInRange
== true)
575 pRange
= vecRangeList
[i
];
589 CAngleAlert
const* CPersonalRangeSignaling::GetAngleTo(const Vec3
& vPos
, bool bUseBoundary
) const
591 CAngleAlert
const* pAngle
= NULL
;
592 float fAngleDiff
= -1.0f
;
594 for (int i
= 0; i
< m_vecAngles
.size(); ++i
)
596 bool bInAngle
= false;
598 if (fAngleDiff
< 0.0f
)
600 fAngleDiff
= m_vecAngles
[i
]->GetAngleTo(vPos
);
603 if (bUseBoundary
== true)
605 bInAngle
= (m_vecAngles
[i
]->CheckPlusBoundary(fAngleDiff
) == true);
609 bInAngle
= (m_vecAngles
[i
]->Check(fAngleDiff
) == true);
612 if (bInAngle
== true)
614 pAngle
= m_vecAngles
[i
];
628 CRange
* CPersonalRangeSignaling::SearchRange(const char* sSignal
, const VecRanges
& vecRangeList
) const
630 CRange
* pRange
= NULL
;
632 for (int i
= 0; i
< vecRangeList
.size(); ++i
)
634 if (vecRangeList
[i
]->GetSignal().compareNoCase(sSignal
) == 0)
636 pRange
= vecRangeList
[i
];
650 CAngleAlert
* CPersonalRangeSignaling::SearchAngle(const char* sSignal
) const
652 CAngleAlert
* pAngle
= NULL
;
654 for (int i
= 0; i
< m_vecAngles
.size(); ++i
)
656 if (m_vecAngles
[i
]->GetSignal().compareNoCase(sSignal
) == 0)
658 pAngle
= m_vecAngles
[i
];
672 void CPersonalRangeSignaling::DebugDraw(uint32 uOrder
) const
674 CRY_ASSERT(m_bInit
== true);
677 float y
= 100.0f
+ (float(uOrder
) * 10.0f
);
682 char txt
[512] = "\0";
684 //cry_sprintf( txt, "%s > %s: %0.1f / %0.1f", GetActor()->GetEntity()->GetName(), m_sSignal.c_str(), m_fTimer, m_fRateMax );
685 //IRenderAuxText::Draw2dLabel( x,y, 13.0f, ColorF(r,g,b), false, "%s", txt);
694 IAIObject
const* CPersonalRangeSignaling::GetEntityAI(EntityId entityId
) const
696 IAIObject
const* pAIObject
= NULL
;
698 IEntity
* pEntity
= gEnv
->pEntitySystem
->GetEntity(entityId
);
701 pAIObject
= pEntity
->GetAI();
713 IAIActorProxy
* CPersonalRangeSignaling::GetEntityAIProxy(EntityId entityId
) const
715 IAIActorProxy
* pAIProxy
= NULL
;
717 IAIObject
const* pAIObject
= GetEntityAI(m_EntityId
);
720 pAIProxy
= pAIObject
->GetProxy();
732 void CPersonalRangeSignaling::SetListener(bool bAdd
)
734 CAIProxy
* pAIProxy
= static_cast<CAIProxy
*>(GetEntityAIProxy(m_EntityId
));
738 pAIProxy
->AddListener(this);
740 pAIProxy
->RemoveListener(this);
750 void CPersonalRangeSignaling::OnAIProxyEnabled(bool bEnabled
)