WARNING THIS CODE IS VERY SLOW!!! (Profiling(in microseconds): provided function ~= 0.044809, UTIL_TraceLine() ~= 0.001445)
Code:
class ITraceFilter
{
public:
virtual inline const bool ShouldHitEntity (edict_t *const edict) = 0;
//
// Group: Private operators.
//
private:
inline ITraceFilter &operator = (const ITraceFilter &/*right*/); // Avoid "warning C4512: 'ITraceFilter' : assignment operator could not be generated".
};
//-----------------------------------------------------------------------------
// Classes need not inherit from these
//-----------------------------------------------------------------------------
class TraceFilter_HitWorldOnly : public ITraceFilter
{
public:
inline const bool ShouldHitEntity (edict_t *const edict)
{
return ENTINDEX (edict) == 0u;
}
};
class TraceFilter_HitAll : public ITraceFilter
{
public:
virtual inline const bool ShouldHitEntity (edict_t *const edict)
{
return true;
}
};
class TraceFilter_PassEntity : public ITraceFilter
{
private:
const edict_t *m_passEdict;
public:
inline TraceFilter_PassEntity (const edict_t *const passEdict) :
m_passEdict (passEdict)
{ /* VOID */ }
public:
inline const bool ShouldHitEntity (edict_t *const edict)
{
return m_passEdict != edict;
}
};
//-----------------------------------------------------------------------------
// Trace filter that can take a list of entities to ignore
//-----------------------------------------------------------------------------
class TraceFilter_SimpleList : public ITraceFilter
{
protected:
vector <edict_t *> m_passEntities;
public:
inline TraceFilter_SimpleList (void) { /* VOID */ }
public:
virtual inline const bool ShouldHitEntity (edict_t *const edict)
{
for (unsigned int index (0u); index < m_passEntities.size (); ++index)
if (edict == m_passEntities[index])
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Add an entity to my list of entities to ignore in the trace
//-----------------------------------------------------------------------------
inline void AddEntityToIgnore (edict_t *const edict)
{
m_passEntities.push_back (edict);
}
};
//-----------------------------------------------------------------------------
// Trace filter that can take a classname to ignore
//-----------------------------------------------------------------------------
class TraceFilter_SkipClassName : public ITraceFilter
{
private:
const char *const m_className;
public:
inline TraceFilter_SkipClassName (const char *const className) :
m_className (className)
{ /* VOID */ }
public:
virtual inline const bool ShouldHitEntity (SDK::Classes::Edict *const edict)
{
return !FClassnameIs (edict, m_className);
}
};
//-----------------------------------------------------------------------------
// Trace filter that can take a list of entities to ignore
//-----------------------------------------------------------------------------
class TraceFilter_SimpleClassNameList : public ITraceFilter
{
private:
vector <const char *> m_passClassNames;
public:
virtual inline const bool ShouldHitEntity (SDK::Classes::Edict *const edict)
{
for (unsigned int index (0u); index < m_passClassNames.size (); ++index)
if (FClassnameIs (edict, m_passClassNames[index]))
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Add an entity to my list of entities to ignore in the trace
//-----------------------------------------------------------------------------
inline void AddClassnameToIgnore (const char *const className)
{
m_passClassNames.push_back (className);
}
};
class TraceFilter_Chain : public ITraceFilter
{
private:
ITraceFilter &m_traceFilter1;
ITraceFilter &m_traceFilter2;
public:
inline TraceFilter_Chain (ITraceFilter &traceFilter1, ITraceFilter &traceFilter2) :
m_traceFilter1 (traceFilter1),
m_traceFilter2 (traceFilter2)
{ /* VOID */ }
public:
virtual inline const bool ShouldHitEntity (edict_t *const edict)
{
return m_traceFilter1.ShouldHitEntity (edict) && m_traceFilter2.ShouldHitEntity (edict);
}
};
void TraceHull (const Vector &source, const Vector &destination, const int hullNumber, ITraceFilter &traceFilter, TraceResult &traceResult)
{
TraceResult tempTraceResult;
edict_t *entity (INDEXENT (0u)); // worldspawn
if (traceFilter.ShouldHitEntity (entity))
g_engfuncs.pfnTraceModel (source, destination, hullNumber, entity, &traceResult);
else
{
// Fill in a default trace result
memset (&traceResult, 0, sizeof (traceResult));
traceResult.flFraction = 1.0f;
traceResult.fAllSolid = true;
traceResult.vecEndPos = destination;
}
// For each entity....
for (unsigned short index (1u/* Skip worldspawn entity.... */); index < gpGlobals->maxEntities; ++index)
{
++entity;
if (FNullEnt (entity) || entity->v.mins == vec3_origin || entity->v.maxs == vec3_origin)
continue;
// Reliability check.
assert (entity->v.classname > 0); // MAY HAPPEN?!?!?!?!?!?
if (!traceFilter.ShouldHitEntity (entity))
continue;
g_engfuncs.pfnTraceModel (source, destination, hullNumber, entity, &tempTraceResult);
if (tempTraceResult.flFraction < traceResult.flFraction)
traceResult = tempTraceResult;
}
}