Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimizations to system object loops #82

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Mammoth/Include/TSEDeviceClassesImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ class CWeaponTargetDefinition
static std::unique_ptr<CWeaponTargetDefinition> ReadFromStream (SLoadCtx& Ctx);
void WriteToStream (IWriteStream* pStream) const;
private:
const std::function<bool(const CSpaceObject*, const CSpaceObject*, const CVector, const int, const int)> fnExclude =
[](const CSpaceObject* pSource, const CSpaceObject* pObj, const CVector vCenter, const int iMinAngle, const int iMaxAngle) {
return pObj->IsIntangible();
};

Kernel::CString m_CriteriaString = "";
CSpaceObjectCriteria m_TargetCriteria;
bool m_bCheckLineOfFire = false; // Check line of fire for friendlies
Expand Down
100 changes: 100 additions & 0 deletions Mammoth/Include/TSESpaceObjectsEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

#pragma once

#include<functional>

// RANGE FILTERS --------------------------------------------------------------

// CNearestInRadiusRange
Expand Down Expand Up @@ -182,6 +184,7 @@ class CCriteriaObjSelector
bool Matches (CSpaceObject &Obj, Metric rDist2)
{
return (!Obj.IsUnreal())
&& Obj.MatchesCriteriaCategory(m_Ctx, m_Criteria)
&& Obj.MatchesCriteria(m_Ctx, m_Criteria);
}

Expand Down Expand Up @@ -683,6 +686,11 @@ class CSpaceObjectEnum
template <class RANGE, class SELECTOR>
static CSpaceObject *FindNearestTangibleObjInArc (const CSystem &System, const CSpaceObject *pSource, const CVector vCenter, const int iMinAngle, const int iMaxAngle, RANGE &Range, SELECTOR &Selector)
{
// TODO(heliogenesis): Create variants of this for other areas where we can optimize via grid.
// For AutoDefenseClass, we can use this as is but we also need to exclude pObj->GetDamageSource().IsAutomatedWeapon() == TRUE,
// and ((!pObj->GetDamageSource().IsEjecta() && !pObj->GetDamageSource().IsExplosion())) if the auto defense class only targets reactions.
// We may want to pass in a function pointer that accepts pObj, pSource, vCenter as arguments so we can avoid introducing an excessive number of functions like this.
// If we go this route, we should remove the `!pObj->IsIntangible()` function, and add that to the function pointer for intangibility.
const CSpaceObjectGrid &Grid = System.GetObjectGrid();

Range.ReduceRadius(Selector.GetMaxRange());
Expand Down Expand Up @@ -715,6 +723,98 @@ class CSpaceObjectEnum
return pBestObj;
}

template <class RANGE, class SELECTOR>
static CSpaceObject* FindNearestObjInArc(const CSystem& System, const CSpaceObject* pSource, const CVector vCenter, const int iMinAngle, const int iMaxAngle, RANGE& Range, SELECTOR& Selector)
{
const std::function<bool(const CSpaceObject*, const CSpaceObject*, const CVector, const int, const int)> fnExclude =
[](const CSpaceObject* pSource, const CSpaceObject* pObj, const CVector vCenter, const int iMinAngle, const int iMaxAngle) {
return true;
};
return FindNearestObjInArc(System, pSource, vCenter, iMinAngle, iMaxAngle, fnExclude, Range, Selector);
}

template <class RANGE, class SELECTOR>
static CSpaceObject *FindNearestObjInArc(const CSystem &System, const CSpaceObject *pSource, const CVector vCenter, const int iMinAngle, const int iMaxAngle,
const std::function<bool(const CSpaceObject*, const CSpaceObject*, const CVector, const int, const int)> fnExclude, RANGE &Range, SELECTOR &Selector)
{
const CSpaceObjectGrid &Grid = System.GetObjectGrid();

Range.ReduceRadius(Selector.GetMaxRange());

CSpaceObject *pBestObj = NULL;

SSpaceObjectGridEnumerator i;
Grid.EnumStart(i, Range.GetUR(), Range.GetLL(), gridNoBoxCheck);

bool bOmnidirectional = (iMinAngle == -1 && iMaxAngle == -1);

while (Grid.EnumHasMore(i))
{
CSpaceObject *pObj = Grid.EnumGetNextFast(i);

Metric rDist2;
if (Selector.MatchesCategory(*pObj)
&& Range.Matches(*pObj, &rDist2)
&& Selector.Matches(*pObj, rDist2)
&& pObj != pSource
&& !fnExclude(pSource, pObj, vCenter, iMinAngle, iMaxAngle)
&& (bOmnidirectional
|| AngleInArc(VectorToPolar((pObj->GetPos() - vCenter)), iMinAngle, iMaxAngle)))
{
Range.SetBestDist2(rDist2);
pBestObj = pObj;
}
}

return pBestObj;
}

template <class RANGE, class SELECTOR>
static TArray<CSpaceObject*> FindNearbyObjsInArc(const CSystem& System, const CSpaceObject* pSource, const CVector vCenter, const int iMinAngle, const int iMaxAngle, RANGE& Range, SELECTOR& Selector)
{
const std::function<bool(const CSpaceObject*, const CSpaceObject*, const CVector, const int, const int)> fnExclude =
[](const CSpaceObject* pSource, const CSpaceObject* pObj, const CVector vCenter, const int iMinAngle, const int iMaxAngle) {
return true;
};
return FindNearbyObjsInArc(System, pSource, vCenter, iMinAngle, iMaxAngle, fnExclude, Range, Selector);
}

template <class RANGE, class SELECTOR>
static TArray<CSpaceObject*> FindNearbyObjsInArc(const CSystem &System, const CSpaceObject *pSource, const CVector vCenter, const int iMinAngle, const int iMaxAngle,
const std::function<bool(const CSpaceObject*, const CSpaceObject*, const CVector, const int, const int)> fnExclude, RANGE &Range, SELECTOR &Selector)
{
const CSpaceObjectGrid &Grid = System.GetObjectGrid();

Range.ReduceRadius(Selector.GetMaxRange());

CSpaceObject *pBestObj = NULL;

SSpaceObjectGridEnumerator i;
Grid.EnumStart(i, Range.GetUR(), Range.GetLL(), gridNoBoxCheck);

bool bOmnidirectional = (iMinAngle == -1 && iMaxAngle == -1);

TArray<CSpaceObject*> Objects;
while (Grid.EnumHasMore(i))
{
CSpaceObject *pObj = Grid.EnumGetNextFast(i);

Metric rDist2;
if (Selector.MatchesCategory(*pObj)
&& Range.Matches(*pObj, &rDist2)
&& Selector.Matches(*pObj, rDist2)
&& pObj != pSource
&& !fnExclude(pSource, pObj, vCenter, iMinAngle, iMaxAngle)
&& (bOmnidirectional
|| AngleInArc(VectorToPolar((pObj->GetPos() - vCenter)), iMinAngle, iMaxAngle)))
{
Objects.Insert(pObj);
}
}

return Objects;
}

template <class RANGE, class SELECTOR>
static CSpaceObject *FindObjInRange (const CSystem &System, RANGE &Range, SELECTOR &Selector)
{
Expand Down
4 changes: 3 additions & 1 deletion Mammoth/Include/TSESystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,9 @@ class CSystem
CSpaceObject *EnumObjectsInBoxPointGetNext (SSpaceObjectGridEnumerator &i) const { return m_ObjGrid.EnumGetNextInBoxPoint(i); }
CSpaceObject *FindObject (DWORD dwID) const;
CSpaceObject *FindNearestObject (CSpaceObject* pSource, const CVector &vCenter, Metric rRange, const CSpaceObjectCriteria &Criteria = CSpaceObjectCriteria()) const;
CSpaceObject *FindNearestTangibleObjectInArc (CSpaceObject* pSource, const CVector &vCenter, Metric rRange, const CSpaceObjectCriteria &Criteria = CSpaceObjectCriteria(), int iMinAngle = -1, int iMaxAngle = -1) const;
CSpaceObject *FindNearestObjectInArc (CSpaceObject* pSource, const CVector &vCenter, Metric rRange,
const std::function<bool(const CSpaceObject*, const CSpaceObject*, const CVector, const int, const int)> fnExclude,
const CSpaceObjectCriteria &Criteria = CSpaceObjectCriteria(), int iMinAngle = -1, int iMaxAngle = -1) const;
CSpaceObject *FindObjectInRange (CSpaceObject *pSource, const CVector &vCenter, Metric rRange, const CSpaceObjectCriteria &Criteria = CSpaceObjectCriteria()) const;
CSpaceObject *FindObjectWithOrbit (const COrbit &Orbit) const;
bool FindObjectName (const CSpaceObject *pObj, CString *retsName = NULL);
Expand Down
1 change: 1 addition & 0 deletions Mammoth/TSE/AIManeuvers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ bool CAIBehaviorCtx::CalcFlockingFormationCloud (CShip *pShip, CSpaceObject *pLe
Metric rFlockCount = 0.0;
Metric rAvoidCount = 0.0;

// TODO(heliogenesis): Use grid functions to optimize this code.
for (i = 0; i < pShip->GetSystem()->GetObjectCount(); i++)
{
CSpaceObject *pObj = pShip->GetSystem()->GetObject(i);
Expand Down
1 change: 1 addition & 0 deletions Mammoth/TSE/CAIBehaviorCtx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,7 @@ bool CAIBehaviorCtx::CalcNavPath (CShip *pShip, CSpaceObject *pTo)

CSpaceObject *pBestObj = NULL;
Metric rBestDist2 = MAX_NAV_START_DIST2;
// TODO(heliogenesis): Use grid optimizations for this code
for (i = 0; i < pSystem->GetObjectCount(); i++)
{
CSpaceObject *pObj = pSystem->GetObject(i);
Expand Down
92 changes: 23 additions & 69 deletions Mammoth/TSE/CAutoDefenseClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,51 +85,18 @@ CSpaceObject *CAutoDefenseClass::FindTarget (CInstalledDevice *pDevice, CSpaceOb
{
Metric rBestDist2 = m_rInterceptRange * m_rInterceptRange;

for (int i = 0; i < pSystem->GetObjectCount(); i++)
{
CSpaceObject *pObj = pSystem->GetObject(i);

// See if this is a valid target. If not, skip

if (pObj == NULL
|| pObj->GetCategory() != CSpaceObject::catMissile
|| pObj->GetDamageSource().IsEqual(pSource)
|| pObj->IsIntangible()
|| pObj->GetDamageSource().IsAutomatedWeapon()
|| !pSource->IsAngryAt(pObj->GetDamageSource())
|| (!isOmniDirectional
&& !AngleInArc(VectorToPolar((pObj->GetPos() - vSourcePos)), iMinFireArc, iMaxFireArc)))
continue;

if (!m_bTargetReactions
&& (pObj->GetDamageSource().IsEjecta() || pObj->GetDamageSource().IsExplosion()))
continue;

// Is this closer than our previous best. If not, skip.

CVector vRange = pObj->GetPos() - vSourcePos;
Metric rDistance2 = vRange.Dot(vRange);

if (rDistance2 >= rBestDist2)
continue;

// If we have restrictions on the source distance, then check
// here. Skip if we don't match.

if (m_rMinSourceRange2 > 0.0)
{
CSpaceObject *pMissileSource = pObj->GetDamageSource().GetObj();
if (pMissileSource && pSource->GetDistance2(pMissileSource) < m_rMinSourceRange2)
continue;
}

// If we get this far, then this is the best target so far.

pBestTarget = pObj;
rBestDist2 = rDistance2;
}

return pBestTarget;
const std::function<bool(const CSpaceObject*, const CSpaceObject*, const CVector, const int, const int)> fnExclude =
[this](const CSpaceObject* pSource, const CSpaceObject* pObj, const CVector vCenter, const int iMinAngle, const int iMaxAngle) {
// Exclude objects that are intangible, or ejecta/explosions if we are not targeting reactions
CSpaceObject* pMissileSource = this->m_rMinSourceRange2 > 0.0 ? pObj->GetDamageSource().GetObj() : nullptr;
return pObj->IsIntangible() || (!m_bTargetReactions && (pObj->GetDamageSource().IsEjecta() || pObj->GetDamageSource().IsExplosion())) ||
pObj->GetCategory() != CSpaceObject::catMissile || pObj->GetDamageSource().IsEqual(*pSource)
|| pObj->GetDamageSource().IsAutomatedWeapon() || !pSource->IsAngryAt(pObj->GetDamageSource()) ||
(pMissileSource && pSource->GetDistance2(pMissileSource) < this->m_rMinSourceRange2);
};

CSpaceObjectCriteria EmptyCriteria;
return pSystem->FindNearestObjectInArc(pSource, vSourcePos, m_rInterceptRange, fnExclude, EmptyCriteria, iMinFireArc, iMaxFireArc);
}

// Look for an object by criteria
Expand All @@ -138,36 +105,23 @@ CSpaceObject *CAutoDefenseClass::FindTarget (CInstalledDevice *pDevice, CSpaceOb
{
// Compute the range

Metric rBestDist2;
Metric rBestDist;
if (m_TargetCriteria.MatchesMaxRadius() < g_InfiniteDistance)
rBestDist2 = (m_TargetCriteria.MatchesMaxRadius() * m_TargetCriteria.MatchesMaxRadius());
rBestDist = m_TargetCriteria.MatchesMaxRadius();
else
rBestDist2 = m_rInterceptRange * m_rInterceptRange;
rBestDist = m_rInterceptRange;

// Now look for the nearest object

const std::function<bool(const CSpaceObject*, const CSpaceObject*, const CVector, const int, const int)> fnExclude =
[this](const CSpaceObject* pSource, const CSpaceObject* pObj, const CVector vCenter, const int iMinAngle, const int iMaxAngle) {
// Exclude objects that are intangible, or ejecta/explosions if we are not targeting reactions
return pObj->IsIntangible() || (!this->m_bTargetReactions && (pObj->GetDamageSource().IsEjecta() || pObj->GetDamageSource().IsExplosion()))
|| pObj->GetDamageSource().IsAutomatedWeapon();
};

CSpaceObjectCriteria::SCtx Ctx(pSource, m_TargetCriteria);
for (int i = 0; i < pSystem->GetObjectCount(); i++)
{
CSpaceObject *pObj = pSystem->GetObject(i);
Metric rDistance2;
if (pObj
&& pObj->MatchesCriteriaCategory(Ctx, m_TargetCriteria)
&& ((rDistance2 = (pObj->GetPos() - vSourcePos).Length2()) < rBestDist2)
&& pObj->MatchesCriteria(Ctx, m_TargetCriteria)
&& !pObj->IsIntangible()
&& pObj != pSource
&& !pObj->GetDamageSource().IsAutomatedWeapon()
&& (m_bTargetReactions || (!pObj->GetDamageSource().IsEjecta() && !pObj->GetDamageSource().IsExplosion()))
&& (isOmniDirectional
|| AngleInArc(VectorToPolar((pObj->GetPos() - vSourcePos)), iMinFireArc, iMaxFireArc)))
{
pBestTarget = pObj;
rBestDist2 = rDistance2;
}
}

return pBestTarget;
return pSystem->FindNearestObjectInArc(pSource, vSourcePos, rBestDist, fnExclude, m_TargetCriteria, iMinFireArc, iMaxFireArc);
}

default:
Expand Down
8 changes: 5 additions & 3 deletions Mammoth/TSE/CSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1830,7 +1830,9 @@ CSpaceObject *CSystem::FindNearestObject (CSpaceObject *pSource, const CVector &
}
}

CSpaceObject *CSystem::FindNearestTangibleObjectInArc (CSpaceObject *pSource, const CVector &vCenter, Metric rRange, const CSpaceObjectCriteria &Criteria, int iMinAngle, int iMaxAngle) const
CSpaceObject *CSystem::FindNearestObjectInArc (CSpaceObject *pSource, const CVector &vCenter, Metric rRange,
const std::function<bool(const CSpaceObject*, const CSpaceObject*, const CVector, const int, const int)> fnExclude,
const CSpaceObjectCriteria &Criteria, int iMinAngle, int iMaxAngle) const

// FindNearestObject
//
Expand All @@ -1845,7 +1847,7 @@ CSpaceObject *CSystem::FindNearestTangibleObjectInArc (CSpaceObject *pSource, co
CCriteriaObjSelector Selector(pSource, Criteria);
CNearestInRadiusRange Range(vCenter, rRange);

return CSpaceObjectEnum::FindNearestTangibleObjInArc(*this, pSource, vCenter, iMinAngle, iMaxAngle, Range, Selector);
return CSpaceObjectEnum::FindNearestObjInArc(*this, pSource, vCenter, iMinAngle, iMaxAngle, fnExclude, Range, Selector);
}

// If we don't have a criteria, then we can do this faster.
Expand All @@ -1855,7 +1857,7 @@ CSpaceObject *CSystem::FindNearestTangibleObjectInArc (CSpaceObject *pSource, co
CAnyObjSelector Selector;
CNearestInRadiusRange Range(vCenter, rRange);

return CSpaceObjectEnum::FindNearestTangibleObjInArc(*this, pSource, vCenter, iMinAngle, iMaxAngle, Range, Selector);
return CSpaceObjectEnum::FindNearestObjInArc(*this, pSource, vCenter, iMinAngle, iMaxAngle, fnExclude, Range, Selector);
}
}

Expand Down
2 changes: 1 addition & 1 deletion Mammoth/TSE/CWeaponTargetDefinition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ CSpaceObject* CWeaponTargetDefinition::FindTarget (CWeaponClass* pWeapon, CInsta

// Now look for the nearest object

return pSystem->FindNearestTangibleObjectInArc(pSource, vSourcePos, rBestDist, m_TargetCriteria, iMinFireArc, iMaxFireArc);
return pSystem->FindNearestObjectInArc(pSource, vSourcePos, rBestDist, fnExclude, m_TargetCriteria, iMinFireArc, iMaxFireArc);
}

bool CWeaponTargetDefinition::AimAndFire(CWeaponClass* pWeapon, CInstalledDevice* pDevice, CSpaceObject* pSource, CDeviceClass::SDeviceUpdateCtx& Ctx) const
Expand Down