Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/components/CCmpObstruction.cpp
Show First 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | typedef struct { | ||||
entity_pos_t size0, size1; | entity_pos_t size0, size1; | ||||
flags_t flags; | flags_t flags; | ||||
} Shape; | } Shape; | ||||
std::vector<Shape> m_Shapes; | std::vector<Shape> m_Shapes; | ||||
// Dynamic state: | // Dynamic state: | ||||
/// Whether the obstruction is actively obstructing or just an inactive placeholder. | |||||
bool m_Active; | |||||
/// Whether the entity associated with this obstruction is currently moving. Only applicable for | /// Whether the entity associated with this obstruction is currently moving. Only applicable for | ||||
/// UNIT-type obstructions. | /// UNIT-type obstructions. | ||||
bool m_Moving; | bool m_Moving; | ||||
/// Whether an obstruction's control group should be kept consistent and | /// Whether an obstruction's control group should be kept consistent and | ||||
/// used to set control groups for entities that collide with it. | /// used to set control groups for entities that collide with it. | ||||
bool m_ControlPersist; | bool m_ControlPersist; | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | return | ||||
"<data type='decimal'>" | "<data type='decimal'>" | ||||
"<param name='minInclusive'>1.5</param>" | "<param name='minInclusive'>1.5</param>" | ||||
"</data>" | "</data>" | ||||
"</attribute>" | "</attribute>" | ||||
"</element>" | "</element>" | ||||
"</zeroOrMore>" | "</zeroOrMore>" | ||||
"</element>" | "</element>" | ||||
"</choice>" | "</choice>" | ||||
"<element name='Active' a:help='If false, this entity will be ignored in collision tests by other units but can still perform its own collision tests'>" | |||||
"<data type='boolean'/>" | |||||
"</element>" | |||||
"<element name='BlockMovement' a:help='Whether units should be allowed to walk through this entity'>" | "<element name='BlockMovement' a:help='Whether units should be allowed to walk through this entity'>" | ||||
"<data type='boolean'/>" | "<data type='boolean'/>" | ||||
"</element>" | "</element>" | ||||
"<element name='BlockPathfinding' a:help='Whether the long-distance pathfinder should avoid paths through this entity. This should only be set for large stationary obstructions'>" | "<element name='BlockPathfinding' a:help='Whether the long-distance pathfinder should avoid paths through this entity. This should only be set for large stationary obstructions'>" | ||||
"<data type='boolean'/>" | "<data type='boolean'/>" | ||||
"</element>" | "</element>" | ||||
"<element name='BlockFoundation' a:help='Whether players should be unable to place building foundations on top of this entity. If true, BlockConstruction should be true too'>" | "<element name='BlockFoundation' a:help='Whether players should be unable to place building foundations on top of this entity.'>" | ||||
"<data type='boolean'/>" | |||||
"</element>" | |||||
"<element name='BlockConstruction' a:help='Whether players should be unable to begin constructing buildings placed on top of this entity'>" | |||||
"<data type='boolean'/>" | "<data type='boolean'/>" | ||||
"</element>" | "</element>" | ||||
"<element name='DeleteUponConstruction' a:help='Whether this entity should be deleted when construction on a buildings placed on top of this entity is started.'>" | "<element name='DeleteUponConstruction' a:help='Whether this entity should be deleted when construction on a buildings placed on top of this entity is started.'>" | ||||
"<data type='boolean'/>" | "<data type='boolean'/>" | ||||
"</element>" | "</element>" | ||||
"<element name='DisableBlockMovement' a:help='If true, BlockMovement will be overridden and treated as false. (This is a special case to handle foundations)'>" | "<element name='DisableBlockMovement' a:help='If true, BlockMovement will be overridden and treated as false. (This is a special case to handle foundations)'>" | ||||
"<data type='boolean'/>" | "<data type='boolean'/>" | ||||
"</element>" | "</element>" | ||||
Show All 14 Lines | virtual void Init(const CParamNode& paramNode) | ||||
fixed minObstruction = (Pathfinding::NAVCELL_SIZE.Square() * 2).Sqrt(); | fixed minObstruction = (Pathfinding::NAVCELL_SIZE.Square() * 2).Sqrt(); | ||||
m_TemplateFlags = 0; | m_TemplateFlags = 0; | ||||
if (paramNode.GetChild("BlockMovement").ToBool()) | if (paramNode.GetChild("BlockMovement").ToBool()) | ||||
m_TemplateFlags |= ICmpObstructionManager::FLAG_BLOCK_MOVEMENT; | m_TemplateFlags |= ICmpObstructionManager::FLAG_BLOCK_MOVEMENT; | ||||
if (paramNode.GetChild("BlockPathfinding").ToBool()) | if (paramNode.GetChild("BlockPathfinding").ToBool()) | ||||
m_TemplateFlags |= ICmpObstructionManager::FLAG_BLOCK_PATHFINDING; | m_TemplateFlags |= ICmpObstructionManager::FLAG_BLOCK_PATHFINDING; | ||||
if (paramNode.GetChild("BlockFoundation").ToBool()) | if (paramNode.GetChild("BlockFoundation").ToBool()) | ||||
m_TemplateFlags |= ICmpObstructionManager::FLAG_BLOCK_FOUNDATION; | m_TemplateFlags |= ICmpObstructionManager::FLAG_BLOCK_FOUNDATION; | ||||
if (paramNode.GetChild("BlockConstruction").ToBool()) | |||||
m_TemplateFlags |= ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION; | |||||
if (paramNode.GetChild("DeleteUponConstruction").ToBool()) | if (paramNode.GetChild("DeleteUponConstruction").ToBool()) | ||||
m_TemplateFlags |= ICmpObstructionManager::FLAG_DELETE_UPON_CONSTRUCTION; | m_TemplateFlags |= ICmpObstructionManager::FLAG_DELETE_UPON_CONSTRUCTION; | ||||
m_Flags = m_TemplateFlags; | m_Flags = m_TemplateFlags; | ||||
if (paramNode.GetChild("DisableBlockMovement").ToBool()) | if (paramNode.GetChild("DisableBlockMovement").ToBool()) | ||||
m_Flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_MOVEMENT); | m_Flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_MOVEMENT); | ||||
if (paramNode.GetChild("DisableBlockPathfinding").ToBool()) | if (paramNode.GetChild("DisableBlockPathfinding").ToBool()) | ||||
m_Flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_PATHFINDING); | m_Flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_PATHFINDING); | ||||
Show All 36 Lines | else | ||||
max.Y = std::max(max.Y, b.dz + b.size1/2); | max.Y = std::max(max.Y, b.dz + b.size1/2); | ||||
min.X = std::min(min.X, b.dx - b.size0/2); | min.X = std::min(min.X, b.dx - b.size0/2); | ||||
min.Y = std::min(min.Y, b.dz - b.size1/2); | min.Y = std::min(min.Y, b.dz - b.size1/2); | ||||
} | } | ||||
m_Size0 = fixed::FromInt(2).Multiply(std::max(max.X, -min.X)); | m_Size0 = fixed::FromInt(2).Multiply(std::max(max.X, -min.X)); | ||||
m_Size1 = fixed::FromInt(2).Multiply(std::max(max.Y, -min.Y)); | m_Size1 = fixed::FromInt(2).Multiply(std::max(max.Y, -min.Y)); | ||||
} | } | ||||
m_Active = paramNode.GetChild("Active").ToBool(); | |||||
m_ControlPersist = paramNode.GetChild("ControlPersist").IsOk(); | m_ControlPersist = paramNode.GetChild("ControlPersist").IsOk(); | ||||
m_Tag = tag_t(); | m_Tag = tag_t(); | ||||
if (m_Type == CLUSTER) | if (m_Type == CLUSTER) | ||||
m_ClusterTags.clear(); | m_ClusterTags.clear(); | ||||
m_Moving = false; | m_Moving = false; | ||||
m_ControlGroup = GetEntityId(); | m_ControlGroup = GetEntityId(); | ||||
m_ControlGroup2 = INVALID_ENTITY; | m_ControlGroup2 = INVALID_ENTITY; | ||||
Show All 10 Lines | struct SerializeTag | ||||
{ | { | ||||
serialize.NumberU32_Unbounded("tag", value.n); | serialize.NumberU32_Unbounded("tag", value.n); | ||||
} | } | ||||
}; | }; | ||||
template<typename S> | template<typename S> | ||||
void SerializeCommon(S& serialize) | void SerializeCommon(S& serialize) | ||||
{ | { | ||||
serialize.Bool("active", m_Active); | |||||
serialize.Bool("moving", m_Moving); | serialize.Bool("moving", m_Moving); | ||||
serialize.NumberU32_Unbounded("control group", m_ControlGroup); | serialize.NumberU32_Unbounded("control group", m_ControlGroup); | ||||
serialize.NumberU32_Unbounded("control group 2", m_ControlGroup2); | serialize.NumberU32_Unbounded("control group 2", m_ControlGroup2); | ||||
serialize.NumberU32_Unbounded("tag", m_Tag.n); | serialize.NumberU32_Unbounded("tag", m_Tag.n); | ||||
serialize.NumberU8_Unbounded("flags", m_Flags); | serialize.NumberU8_Unbounded("flags", m_Flags); | ||||
if (m_Type == CLUSTER) | if (m_Type == CLUSTER) | ||||
SerializeVector<SerializeTag>()(serialize, "cluster tags", m_ClusterTags); | SerializeVector<SerializeTag>()(serialize, "cluster tags", m_ClusterTags); | ||||
if (m_Type == UNIT) | if (m_Type == UNIT) | ||||
Show All 13 Lines | public: | ||||
} | } | ||||
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) | virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) | ||||
{ | { | ||||
switch (msg.GetType()) | switch (msg.GetType()) | ||||
{ | { | ||||
case MT_PositionChanged: | case MT_PositionChanged: | ||||
{ | { | ||||
if (!m_Active) | |||||
break; | |||||
const CMessagePositionChanged& data = static_cast<const CMessagePositionChanged&> (msg); | const CMessagePositionChanged& data = static_cast<const CMessagePositionChanged&> (msg); | ||||
if (!data.inWorld && !m_Tag.valid()) | if (!data.inWorld && !m_Tag.valid()) | ||||
break; // nothing needs to change | break; // nothing needs to change | ||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity()); | CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity()); | ||||
if (!cmpObstructionManager) | if (!cmpObstructionManager) | ||||
break; // error | break; // error | ||||
Show All 38 Lines | virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) | ||||
{ | { | ||||
if (m_Tag.valid()) | if (m_Tag.valid()) | ||||
{ | { | ||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity()); | CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity()); | ||||
if (!cmpObstructionManager) | if (!cmpObstructionManager) | ||||
break; // error | break; // error | ||||
// Deactivate the obstruction in case PositionChanged messages are sent after this. | // Deactivate the obstruction in case PositionChanged messages are sent after this. | ||||
m_Active = false; | |||||
cmpObstructionManager->RemoveShape(m_Tag); | cmpObstructionManager->RemoveShape(m_Tag); | ||||
m_Tag = tag_t(); | m_Tag = tag_t(); | ||||
if(m_Type == CLUSTER) | if(m_Type == CLUSTER) | ||||
RemoveClusterShapes(); | RemoveClusterShapes(); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
virtual void SetActive(bool active) | void ResetShape() | ||||
{ | |||||
if (active && !m_Active) | |||||
{ | { | ||||
m_Active = true; | // Delete the obstruction shape | ||||
// TODO: code duplication from message handlers | |||||
// Construct the obstruction shape | |||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity()); | CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity()); | ||||
if (!cmpObstructionManager) | if (!cmpObstructionManager) | ||||
return; // error | return; // error | ||||
if (m_Tag.valid()) | |||||
{ | |||||
cmpObstructionManager->RemoveShape(m_Tag); | |||||
m_Tag = tag_t(); | |||||
if (m_Type == CLUSTER) | |||||
RemoveClusterShapes(); | |||||
} | |||||
// Construct the obstruction shape | |||||
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | ||||
if (!cmpPosition) | if (!cmpPosition) | ||||
return; // error | return; // | ||||
if (!cmpPosition->IsInWorld()) | if (!cmpPosition->IsInWorld()) | ||||
return; // don't need an obstruction | return; // don't need an obstruction | ||||
// TODO: code duplication from message handlers | |||||
CFixedVector2D pos = cmpPosition->GetPosition2D(); | CFixedVector2D pos = cmpPosition->GetPosition2D(); | ||||
if (m_Type == STATIC) | if (m_Type == STATIC) | ||||
m_Tag = cmpObstructionManager->AddStaticShape(GetEntityId(), | m_Tag = cmpObstructionManager->AddStaticShape(GetEntityId(), | ||||
pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, m_Flags, m_ControlGroup, m_ControlGroup2); | pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, m_Flags, m_ControlGroup, m_ControlGroup2); | ||||
else if (m_Type == UNIT) | else if (m_Type == UNIT) | ||||
m_Tag = cmpObstructionManager->AddUnitShape(GetEntityId(), | m_Tag = cmpObstructionManager->AddUnitShape(GetEntityId(), | ||||
pos.X, pos.Y, m_Clearance, (flags_t)(m_Flags | (m_Moving ? ICmpObstructionManager::FLAG_MOVING : 0)), m_ControlGroup); | pos.X, pos.Y, m_Clearance, (flags_t)(m_Flags | (m_Moving ? ICmpObstructionManager::FLAG_MOVING : 0)), m_ControlGroup); | ||||
else | else | ||||
AddClusterShapes(pos.X, pos.Y, cmpPosition->GetRotation().Y); | AddClusterShapes(pos.X, pos.Y, cmpPosition->GetRotation().Y); | ||||
} | } | ||||
else if (!active && m_Active) | |||||
{ | |||||
m_Active = false; | |||||
// Delete the obstruction shape | |||||
// TODO: code duplication from message handlers | |||||
if (m_Tag.valid()) | |||||
{ | |||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity()); | |||||
if (!cmpObstructionManager) | |||||
return; // error | |||||
cmpObstructionManager->RemoveShape(m_Tag); | |||||
m_Tag = tag_t(); | |||||
if (m_Type == CLUSTER) | |||||
RemoveClusterShapes(); | |||||
} | |||||
} | |||||
// else we didn't change the active status | |||||
} | |||||
virtual void SetDisableBlockMovementPathfinding(bool movementDisabled, bool pathfindingDisabled, int32_t shape) | virtual void SetDisableBlockMovementPathfinding(bool movementDisabled, bool pathfindingDisabled, int32_t shape) | ||||
{ | { | ||||
flags_t *flags = NULL; | flags_t *flags = NULL; | ||||
if (shape == -1) | if (shape == -1) | ||||
flags = &m_Flags; | flags = &m_Flags; | ||||
else if (m_Type == CLUSTER && shape < (int32_t)m_Shapes.size()) | else if (m_Type == CLUSTER && shape < (int32_t)m_Shapes.size()) | ||||
flags = &m_Shapes[shape].flags; | flags = &m_Shapes[shape].flags; | ||||
else | else | ||||
return; // error | return; // error | ||||
// Remove the blocking / pathfinding flags or | // Remove the blocking / pathfinding flags or | ||||
// Add the blocking / pathfinding flags if the template had enabled them | // Add the blocking / pathfinding flags if the template had enabled them | ||||
if (movementDisabled) | if (movementDisabled) | ||||
*flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_MOVEMENT); | *flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_MOVEMENT); | ||||
else | else | ||||
*flags |= (flags_t)(m_TemplateFlags & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT); | *flags |= (flags_t)(m_TemplateFlags & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT); | ||||
if (pathfindingDisabled) | if (pathfindingDisabled) | ||||
*flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_PATHFINDING); | *flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_PATHFINDING); | ||||
else | else | ||||
*flags |= (flags_t)(m_TemplateFlags & ICmpObstructionManager::FLAG_BLOCK_PATHFINDING); | *flags |= (flags_t)(m_TemplateFlags & ICmpObstructionManager::FLAG_BLOCK_PATHFINDING); | ||||
// Reset the shape with the new flags (kind of inefficiently - we | // Reset the shape with the new flags (kind of inefficiently - we | ||||
// should have a ICmpObstructionManager::SetFlags function or something) | // should have a ICmpObstructionManager::SetFlags function or something) | ||||
if (m_Active) | ResetShape(); | ||||
{ | |||||
SetActive(false); | |||||
SetActive(true); | |||||
} | |||||
} | } | ||||
virtual bool GetBlockMovementFlag() const | virtual bool GetBlockMovementFlag() const | ||||
{ | { | ||||
return (m_TemplateFlags & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT) != 0; | return (m_TemplateFlags & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT) != 0; | ||||
} | } | ||||
virtual EObstructionType GetObstructionType() const | virtual EObstructionType GetObstructionType() const | ||||
▲ Show 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | virtual bool CheckDuplicateFoundation() const | ||||
if (m_Type == UNIT) | if (m_Type == UNIT) | ||||
return !cmpObstructionManager->TestUnitShape(filter, pos.X, pos.Y, m_Clearance, NULL); | return !cmpObstructionManager->TestUnitShape(filter, pos.X, pos.Y, m_Clearance, NULL); | ||||
else | else | ||||
return !cmpObstructionManager->TestStaticShape(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, NULL ); | return !cmpObstructionManager->TestStaticShape(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, NULL ); | ||||
} | } | ||||
virtual std::vector<entity_id_t> GetEntitiesByFlags(flags_t flags) const | virtual std::vector<entity_id_t> GetEntitiesByFlags(flags_t flags) const | ||||
{ | { | ||||
return GetEntitiesByFlags(flags, true, true); | |||||
} | |||||
virtual std::vector<entity_id_t> GetEntitiesByFlags(flags_t flags, bool unitShapes, bool staticShapes) const | |||||
{ | |||||
std::vector<entity_id_t> ret; | std::vector<entity_id_t> ret; | ||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity()); | CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity()); | ||||
if (!cmpObstructionManager) | if (!cmpObstructionManager) | ||||
return ret; // error | return ret; // error | ||||
// Ignore collisions within the same control group, or with other shapes that don't match the filter. | // Ignore collisions within the same control group, or with other shapes that don't match the filter. | ||||
// Note that, since the control group for each entity defaults to the entity's ID, this is typically | // Note that, since the control group for each entity defaults to the entity's ID, this is typically | ||||
// equivalent to only ignoring the entity's own shape and other shapes that don't match the filter. | // equivalent to only ignoring the entity's own shape and other shapes that don't match the filter. | ||||
SkipControlGroupsRequireFlagObstructionFilter filter(false, m_ControlGroup, m_ControlGroup2, flags); | SkipControlGroupsRequireFlagObstructionFilter filter(false, m_ControlGroup, m_ControlGroup2, flags); | ||||
ICmpObstructionManager::ObstructionSquare square; | ICmpObstructionManager::ObstructionSquare square; | ||||
if (!GetObstructionSquare(square)) | if (!GetObstructionSquare(square)) | ||||
return ret; // error | return ret; // error | ||||
if (unitShapes) | |||||
cmpObstructionManager->GetUnitsOnObstruction(square, ret, filter, false); | cmpObstructionManager->GetUnitsOnObstruction(square, ret, filter, false); | ||||
if (staticShapes) | |||||
cmpObstructionManager->GetStaticObstructionsOnObstruction(square, ret, filter); | cmpObstructionManager->GetStaticObstructionsOnObstruction(square, ret, filter); | ||||
return ret; | return ret; | ||||
} | } | ||||
virtual std::vector<entity_id_t> GetEntitiesBlockingMovement() const | virtual std::vector<entity_id_t> GetUnitsBlockingMovement() const | ||||
{ | |||||
return GetEntitiesByFlags(ICmpObstructionManager::FLAG_BLOCK_MOVEMENT); | |||||
} | |||||
virtual std::vector<entity_id_t> GetEntitiesBlockingConstruction() const | |||||
{ | { | ||||
return GetEntitiesByFlags(ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION); | return GetEntitiesByFlags(ICmpObstructionManager::FLAG_BLOCK_MOVEMENT, true, false); | ||||
} | } | ||||
virtual std::vector<entity_id_t> GetEntitiesDeletedUponConstruction() const | virtual std::vector<entity_id_t> GetEntitiesDeletedUponConstruction() const | ||||
{ | { | ||||
return GetEntitiesByFlags(ICmpObstructionManager::FLAG_DELETE_UPON_CONSTRUCTION); | return GetEntitiesByFlags(ICmpObstructionManager::FLAG_DELETE_UPON_CONSTRUCTION); | ||||
} | } | ||||
virtual void SetMovingFlag(bool enabled) | virtual void SetMovingFlag(bool enabled) | ||||
▲ Show 20 Lines • Show All 175 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator