Fix units spawning on top of each other.
Add type-safety to prevent that kind of bug happening again. This was SVN commit r7691.
This commit is contained in:
parent
e8b264835a
commit
dff694f0f0
@ -170,6 +170,7 @@ TrainingQueue.prototype.SpawnUnits = function(templateName, count)
|
||||
// What should we do here?
|
||||
// For now, just move the unit into the middle of the building where it'll probably get stuck
|
||||
pos = cmpPosition.GetPosition();
|
||||
warn("Can't find free space to spawn trained unit");
|
||||
}
|
||||
|
||||
var cmpNewPosition = Engine.QueryInterface(ent, IID_Position);
|
||||
|
@ -135,11 +135,15 @@ public:
|
||||
return error;
|
||||
|
||||
entity_pos_t spawnedRadius;
|
||||
ICmpObstructionManager::tag_t spawnedTag;
|
||||
|
||||
CmpPtr<ICmpObstruction> cmpSpawnedObstruction(GetSimContext(), spawned);
|
||||
if (!cmpSpawnedObstruction.null())
|
||||
{
|
||||
spawnedRadius = cmpSpawnedObstruction->GetUnitRadius();
|
||||
// else zero
|
||||
spawnedTag = cmpSpawnedObstruction->GetObstruction();
|
||||
}
|
||||
// else use zero radius
|
||||
|
||||
// The spawn point should be far enough from this footprint to fit the unit, plus a little gap
|
||||
entity_pos_t clearance = spawnedRadius + entity_pos_t::FromInt(2);
|
||||
@ -162,7 +166,7 @@ public:
|
||||
|
||||
CFixedVector3D pos (initialPos.X + s.Multiply(radius), fixed::Zero(), initialPos.Z + c.Multiply(radius));
|
||||
|
||||
SkipTagObstructionFilter filter(spawned); // ignore collisions with the spawned entity
|
||||
SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity
|
||||
if (!cmpObstructionManager->TestUnitShape(filter, pos.X, pos.Z, spawnedRadius))
|
||||
return pos; // this position is okay, so return it
|
||||
}
|
||||
@ -212,7 +216,7 @@ public:
|
||||
{
|
||||
CFixedVector2D pos (center + dir*i);
|
||||
|
||||
SkipTagObstructionFilter filter(spawned); // ignore collisions with the spawned entity
|
||||
SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity
|
||||
if (!cmpObstructionManager->TestUnitShape(filter, pos.X, pos.Y, spawnedRadius))
|
||||
return CFixedVector3D(pos.X, fixed::Zero(), pos.Y); // this position is okay, so return it
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ public:
|
||||
else
|
||||
m_Active = true;
|
||||
|
||||
m_Tag = 0;
|
||||
m_Tag = ICmpObstructionManager::tag_t();
|
||||
m_Moving = false;
|
||||
}
|
||||
|
||||
@ -133,18 +133,18 @@ public:
|
||||
|
||||
const CMessagePositionChanged& data = static_cast<const CMessagePositionChanged&> (msg);
|
||||
|
||||
if (!data.inWorld && !m_Tag)
|
||||
if (!data.inWorld && !m_Tag.valid())
|
||||
break; // nothing needs to change
|
||||
|
||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(context, SYSTEM_ENTITY);
|
||||
if (cmpObstructionManager.null())
|
||||
break;
|
||||
|
||||
if (data.inWorld && m_Tag)
|
||||
if (data.inWorld && m_Tag.valid())
|
||||
{
|
||||
cmpObstructionManager->MoveShape(m_Tag, data.x, data.z, data.a);
|
||||
}
|
||||
else if (data.inWorld && !m_Tag)
|
||||
else if (data.inWorld && !m_Tag.valid())
|
||||
{
|
||||
// Need to create a new pathfinder shape:
|
||||
if (m_Type == STATIC)
|
||||
@ -152,10 +152,10 @@ public:
|
||||
else
|
||||
m_Tag = cmpObstructionManager->AddUnitShape(data.x, data.z, m_Size0, m_Moving);
|
||||
}
|
||||
else if (!data.inWorld && m_Tag)
|
||||
else if (!data.inWorld && m_Tag.valid())
|
||||
{
|
||||
cmpObstructionManager->RemoveShape(m_Tag);
|
||||
m_Tag = 0;
|
||||
m_Tag = ICmpObstructionManager::tag_t();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -164,7 +164,7 @@ public:
|
||||
const CMessageMotionChanged& data = static_cast<const CMessageMotionChanged&> (msg);
|
||||
m_Moving = !data.speed.IsZero();
|
||||
|
||||
if (m_Tag && m_Type == UNIT)
|
||||
if (m_Tag.valid() && m_Type == UNIT)
|
||||
{
|
||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(context, SYSTEM_ENTITY);
|
||||
if (cmpObstructionManager.null())
|
||||
@ -175,14 +175,14 @@ public:
|
||||
}
|
||||
case MT_Destroy:
|
||||
{
|
||||
if (m_Tag)
|
||||
if (m_Tag.valid())
|
||||
{
|
||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(context, SYSTEM_ENTITY);
|
||||
if (cmpObstructionManager.null())
|
||||
break;
|
||||
|
||||
cmpObstructionManager->RemoveShape(m_Tag);
|
||||
m_Tag = 0;
|
||||
m_Tag = ICmpObstructionManager::tag_t();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -34,11 +34,12 @@
|
||||
// Externally, tags are opaque non-zero positive integers.
|
||||
// Internally, they are tagged (by shape) indexes into shape lists.
|
||||
// idx must be non-zero.
|
||||
#define TAG_IS_UNIT(tag) (((tag) & 1) == 0)
|
||||
#define TAG_IS_STATIC(tag) (((tag) & 1) == 1)
|
||||
#define UNIT_INDEX_TO_TAG(idx) (((idx) << 1) | 0)
|
||||
#define STATIC_INDEX_TO_TAG(idx) (((idx) << 1) | 1)
|
||||
#define TAG_TO_INDEX(tag) ((tag) >> 1)
|
||||
#define TAG_IS_VALID(tag) ((tag).valid())
|
||||
#define TAG_IS_UNIT(tag) (((tag).n & 1) == 0)
|
||||
#define TAG_IS_STATIC(tag) (((tag).n & 1) == 1)
|
||||
#define UNIT_INDEX_TO_TAG(idx) tag_t(((idx) << 1) | 0)
|
||||
#define STATIC_INDEX_TO_TAG(idx) tag_t(((idx) << 1) | 1)
|
||||
#define TAG_TO_INDEX(tag) ((tag).n >> 1)
|
||||
|
||||
/**
|
||||
* Internal representation of axis-aligned sometimes-square sometimes-circle shapes for moving units
|
||||
@ -152,7 +153,7 @@ public:
|
||||
|
||||
virtual void MoveShape(tag_t tag, entity_pos_t x, entity_pos_t z, entity_angle_t a)
|
||||
{
|
||||
debug_assert(tag);
|
||||
debug_assert(TAG_IS_VALID(tag));
|
||||
|
||||
if (TAG_IS_UNIT(tag))
|
||||
{
|
||||
@ -179,7 +180,7 @@ public:
|
||||
|
||||
virtual void SetUnitMovingFlag(tag_t tag, bool moving)
|
||||
{
|
||||
debug_assert(tag && TAG_IS_UNIT(tag));
|
||||
debug_assert(TAG_IS_VALID(tag) && TAG_IS_UNIT(tag));
|
||||
|
||||
if (TAG_IS_UNIT(tag))
|
||||
{
|
||||
@ -190,7 +191,7 @@ public:
|
||||
|
||||
virtual void RemoveShape(tag_t tag)
|
||||
{
|
||||
debug_assert(tag);
|
||||
debug_assert(TAG_IS_VALID(tag));
|
||||
|
||||
if (TAG_IS_UNIT(tag))
|
||||
m_UnitShapes.erase(TAG_TO_INDEX(tag));
|
||||
@ -202,7 +203,7 @@ public:
|
||||
|
||||
virtual ObstructionSquare GetObstruction(tag_t tag)
|
||||
{
|
||||
debug_assert(tag);
|
||||
debug_assert(TAG_IS_VALID(tag));
|
||||
|
||||
if (TAG_IS_UNIT(tag))
|
||||
{
|
||||
|
@ -557,7 +557,7 @@ bool CCmpUnitMotion::MoveToAttackRange(entity_id_t target, entity_pos_t minRange
|
||||
if (cmpObstructionManager.null())
|
||||
return false;
|
||||
|
||||
ICmpObstructionManager::tag_t tag = 0;
|
||||
ICmpObstructionManager::tag_t tag;
|
||||
|
||||
CmpPtr<ICmpObstruction> cmpObstruction(GetSimContext(), target);
|
||||
if (!cmpObstruction.null())
|
||||
@ -590,7 +590,7 @@ bool CCmpUnitMotion::MoveToAttackRange(entity_id_t target, entity_pos_t minRange
|
||||
|
||||
const entity_pos_t goalDelta = entity_pos_t::FromInt(CELL_SIZE)/4; // for extending the goal outwards/inwards a little bit
|
||||
|
||||
if (tag)
|
||||
if (tag.valid())
|
||||
{
|
||||
ICmpObstructionManager::ObstructionSquare obstruction = cmpObstructionManager->GetObstruction(tag);
|
||||
|
||||
@ -723,7 +723,7 @@ bool CCmpUnitMotion::IsInAttackRange(entity_id_t target, entity_pos_t minRange,
|
||||
if (cmpObstructionManager.null())
|
||||
return false;
|
||||
|
||||
ICmpObstructionManager::tag_t tag = 0;
|
||||
ICmpObstructionManager::tag_t tag;
|
||||
|
||||
CmpPtr<ICmpObstruction> cmpObstruction(GetSimContext(), target);
|
||||
if (!cmpObstruction.null())
|
||||
@ -731,7 +731,7 @@ bool CCmpUnitMotion::IsInAttackRange(entity_id_t target, entity_pos_t minRange,
|
||||
|
||||
entity_pos_t distance;
|
||||
|
||||
if (tag)
|
||||
if (tag.valid())
|
||||
{
|
||||
ICmpObstructionManager::ObstructionSquare obstruction = cmpObstructionManager->GetObstruction(tag);
|
||||
|
||||
|
@ -55,9 +55,17 @@ class ICmpObstructionManager : public IComponent
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* External identifiers for shapes. Valid tags are guaranteed to be non-zero.
|
||||
* External identifiers for shapes.
|
||||
* (This is a struct rather than a raw u32 for type-safety.)
|
||||
*/
|
||||
typedef u32 tag_t;
|
||||
struct tag_t
|
||||
{
|
||||
tag_t() : n(0) {}
|
||||
explicit tag_t(u32 n) : n(n) {}
|
||||
bool valid() { return n != 0; }
|
||||
|
||||
u32 n;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a static shape.
|
||||
@ -233,7 +241,7 @@ class SkipTagObstructionFilter : public IObstructionTestFilter
|
||||
ICmpObstructionManager::tag_t m_Tag;
|
||||
public:
|
||||
SkipTagObstructionFilter(ICmpObstructionManager::tag_t tag) : m_Tag(tag) {}
|
||||
virtual bool Allowed(ICmpObstructionManager::tag_t tag, bool UNUSED(moving)) const { return tag != m_Tag; }
|
||||
virtual bool Allowed(ICmpObstructionManager::tag_t tag, bool UNUSED(moving)) const { return tag.n != m_Tag.n; }
|
||||
};
|
||||
|
||||
#endif // INCLUDED_ICMPOBSTRUCTIONMANAGER
|
||||
|
Loading…
Reference in New Issue
Block a user