Index: ps/trunk/binaries/data/mods/public/maps/scenarios/unit_pushing_test.js
===================================================================
--- ps/trunk/binaries/data/mods/public/maps/scenarios/unit_pushing_test.js
+++ ps/trunk/binaries/data/mods/public/maps/scenarios/unit_pushing_test.js
@@ -131,7 +131,7 @@
let cmpModifiersManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager);
// Make that tree essentially infinite.
cmpModifiersManager.AddModifiers("inf_tree", {
- "ResourceSupply/Max": [{ "affects": ["Tree"], "replace": 50000 }],
+ "ResourceSupply/Max": [{ "replace": 50000 }],
}, target);
let cmpSupply = Engine.QueryInterface(target, IID_ResourceSupply);
cmpSupply.SetAmount(50000);
Index: ps/trunk/binaries/data/mods/public/simulation/data/pathfinder.rng
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/data/pathfinder.rng
+++ ps/trunk/binaries/data/mods/public/simulation/data/pathfinder.rng
@@ -4,6 +4,9 @@
+
+
+
Index: ps/trunk/binaries/data/mods/public/simulation/data/pathfinder.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/data/pathfinder.xml
+++ ps/trunk/binaries/data/mods/public/simulation/data/pathfinder.xml
@@ -4,6 +4,12 @@
64
+
+
+
+
+ 1.6
+
Index: ps/trunk/source/simulation2/components/CCmpUnitMotion.h
===================================================================
--- ps/trunk/source/simulation2/components/CCmpUnitMotion.h
+++ ps/trunk/source/simulation2/components/CCmpUnitMotion.h
@@ -159,7 +159,11 @@
bool m_FacePointAfterMove;
// Whether the unit participates in pushing.
- bool m_Pushing = true;
+ bool m_Pushing = false;
+
+ // Whether the unit blocks movement (& is blocked by movement blockers)
+ // Cached from ICmpObstruction.
+ bool m_BlockMovement = false;
// Internal counter used when recovering from obstructed movement.
// Most notably, increases the search range of the vertex pathfinder.
@@ -239,7 +243,12 @@
""
""
""
- "";
+ ""
+ ""
+ ""
+ ""
+ ""
+ "";
}
virtual void Init(const CParamNode& paramNode)
@@ -267,11 +276,12 @@
if (cmpObstruction)
{
cmpObstruction->SetUnitClearance(m_Clearance);
- if (!cmpObstruction->GetBlockMovementFlag(true))
- m_Pushing = false;
+ m_BlockMovement = cmpObstruction->GetBlockMovementFlag(true);
}
}
+ SetParticipateInPushing(!paramNode.GetChild("DisablePushing").IsOk() || !paramNode.GetChild("DisablePushing").ToBool());
+
m_DebugOverlayEnabled = false;
}
@@ -322,6 +332,10 @@
CmpPtr cmpPathfinder(GetSystemEntity());
if (cmpPathfinder)
m_PassClass = cmpPathfinder->GetPassabilityClass(m_PassClassName);
+
+ CmpPtr cmpObstruction(GetEntityHandle());
+ if (cmpObstruction)
+ m_BlockMovement = cmpObstruction->GetBlockMovementFlag(false);
}
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global))
@@ -357,7 +371,7 @@
{
CmpPtr cmpObstruction(GetEntityHandle());
if (cmpObstruction)
- m_Pushing = cmpObstruction->GetBlockMovementFlag(false);
+ m_BlockMovement = cmpObstruction->GetBlockMovementFlag(false);
break;
}
case MT_ValueModification:
@@ -543,6 +557,12 @@
return IsFormationMember() ? m_MoveRequest.m_Entity : GetEntityId();
}
+ void SetParticipateInPushing(bool pushing)
+ {
+ CmpPtr cmpUnitMotionManager(GetSystemEntity());
+ m_Pushing = pushing && cmpUnitMotionManager->IsPushingActivated();
+ }
+
/**
* Warns other components that our current movement will likely fail (e.g. we won't be able to reach our target)
* This should only be called before the actual movement in a given turn, or units might both move and try to do things
@@ -731,18 +751,30 @@
void FaceTowardsPointFromPos(const CFixedVector2D& pos, entity_pos_t x, entity_pos_t z);
/**
+ * Units in 'pushing' mode are marked as 'moving' in the obstruction manager.
+ * Units in 'pushing' mode should skip them in checkMovement (to enable pushing).
+ * However, units for which pushing is deactivated should collide against everyone.
+ * Units that don't block movement never participate in pushing, but they also
+ * shouldn't collide with pushing units.
+ */
+ bool ShouldCollideWithMovingUnits() const
+ {
+ return !m_Pushing && m_BlockMovement;
+ }
+
+ /**
* Returns an appropriate obstruction filter for use with path requests.
*/
ControlGroupMovementObstructionFilter GetObstructionFilter() const
{
- return ControlGroupMovementObstructionFilter(false, GetGroup());
+ return ControlGroupMovementObstructionFilter(ShouldCollideWithMovingUnits(), GetGroup());
}
/**
* Filter a specific tag on top of the existing control groups.
*/
SkipTagAndControlGroupObstructionFilter GetObstructionFilter(const ICmpObstructionManager::tag_t& tag) const
{
- return SkipTagAndControlGroupObstructionFilter(tag, false, GetGroup());
+ return SkipTagAndControlGroupObstructionFilter(tag, ShouldCollideWithMovingUnits(), GetGroup());
}
/**
@@ -931,20 +963,20 @@
void CCmpUnitMotion::PreMove(CCmpUnitMotionManager::MotionState& state)
{
- state.ignore = !m_Pushing;
+ state.ignore = !m_Pushing || !m_BlockMovement;
// If we were idle and will still be, no need for an update.
state.needUpdate = state.cmpPosition->IsInWorld() &&
(m_CurSpeed != fixed::Zero() || m_MoveRequest.m_Type != MoveRequest::NONE);
- if (state.ignore)
+ if (!m_BlockMovement)
return;
state.controlGroup = IsFormationMember() ? m_MoveRequest.m_Entity : INVALID_ENTITY;
// Update moving flag, this is an internal construct used for pushing,
// so it does not really reflect whether the unit is actually moving or not.
- state.isMoving = m_MoveRequest.m_Type != MoveRequest::NONE;
+ state.isMoving = m_Pushing && m_MoveRequest.m_Type != MoveRequest::NONE;
CmpPtr cmpObstruction(GetEntityHandle());
if (cmpObstruction)
cmpObstruction->SetMovingFlag(state.isMoving);
Index: ps/trunk/source/simulation2/components/CCmpUnitMotionManager.h
===================================================================
--- ps/trunk/source/simulation2/components/CCmpUnitMotionManager.h
+++ ps/trunk/source/simulation2/components/CCmpUnitMotionManager.h
@@ -81,12 +81,18 @@
bool isMoving = false;
};
+ // Multiplier for the pushing radius. Pre-multiplied by the circle-square correction factor.
+ // "Template" state, not serialized (cannot be changed mid-game).
+ entity_pos_t m_PushingRadius;
+
+ // These vectors are reconstructed on deserialization.
+
EntityMap m_Units;
EntityMap m_FormationControllers;
- // The vectors are cleared each frame.
- Grid::iterator>> m_MovingUnits;
+ // Turn-local state below, not serialised.
+ Grid::iterator>> m_MovingUnits;
bool m_ComputingMotion;
static std::string GetSchema()
@@ -94,9 +100,7 @@
return "";
}
- virtual void Init(const CParamNode& UNUSED(paramNode))
- {
- }
+ virtual void Init(const CParamNode& UNUSED(paramNode));
virtual void Deinit()
{
@@ -155,6 +159,11 @@
return m_ComputingMotion;
}
+ virtual bool IsPushingActivated() const
+ {
+ return m_PushingRadius != entity_pos_t::Zero();
+ }
+
private:
void ResetSubdivisions();
void OnTurnStart();
Index: ps/trunk/source/simulation2/components/CCmpUnitMotion_System.cpp
===================================================================
--- ps/trunk/source/simulation2/components/CCmpUnitMotion_System.cpp
+++ ps/trunk/source/simulation2/components/CCmpUnitMotion_System.cpp
@@ -51,12 +51,6 @@
static const entity_pos_t PUSHING_CORRECTION = entity_pos_t::FromInt(5) / 7;
/**
- * The maximum distance at which units exert a pushing influence on each other, as a multiple of clearance.
- * (This is multiplied by PUSHING_CORRECTION for convenience).
- */
- static const entity_pos_t PUSHING_RADIUS = (entity_pos_t::FromInt(8) / 5).Multiply(PUSHING_CORRECTION);
-
- /**
* When moving, units exert a pushing influence at a greater distance.
*/
static const entity_pos_t PUSHING_MOVING_INFLUENCE_EXTENSION = entity_pos_t::FromInt(1);
@@ -72,6 +66,29 @@
{
}
+void CCmpUnitMotionManager::Init(const CParamNode&)
+{
+ // Load some data - see CCmpPathfinder.xml.
+ // This assumes the pathfinder component is initialised first and registers the validator.
+ // TODO: there seems to be no real reason why we could not register a 'system' entity somewhere instead.
+ CParamNode externalParamNode;
+ CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml", "pathfinder");
+ const CParamNode radius = externalParamNode.GetChild("Pathfinder").GetChild("PushingRadius");
+ if (radius.IsOk())
+ {
+ m_PushingRadius = radius.ToFixed();
+ if (m_PushingRadius < entity_pos_t::Zero())
+ {
+ LOGWARNING("Pushing radius cannot be below 0. De-activating pushing but 'pathfinder.xml' should be updated.");
+ m_PushingRadius = entity_pos_t::Zero();
+ }
+ // No upper value, but things won't behave sanely if values are too high.
+ }
+ else
+ m_PushingRadius = entity_pos_t::FromInt(8) / 5;
+ m_PushingRadius = m_PushingRadius.Multiply(PUSHING_CORRECTION);
+}
+
void CCmpUnitMotionManager::Register(CCmpUnitMotion* component, entity_id_t ent, bool formationController)
{
MotionState state(CmpPtr(GetSimContext(), ent), component);
@@ -145,7 +162,8 @@
if (it->second.needUpdate)
it->second.cmpUnitMotion->Move(it->second, dt);
- if (&ents == &m_Units)
+ // Skip pushing entirely if the radius is 0
+ if (&ents == &m_Units && m_PushingRadius != entity_pos_t::Zero())
{
PROFILE2("MotionMgr_Pushing");
for (std::vector::iterator>* vec : assigned)
@@ -166,6 +184,7 @@
}
}
+ if (m_PushingRadius != entity_pos_t::Zero())
{
PROFILE2("MotionMgr_PushAdjust");
CmpPtr cmpPathfinder(GetSystemEntity());
@@ -242,7 +261,7 @@
if (movingPush == 1)
return;
- entity_pos_t combinedClearance = (a.second.cmpUnitMotion->m_Clearance + b.second.cmpUnitMotion->m_Clearance).Multiply(PUSHING_RADIUS);
+ entity_pos_t combinedClearance = (a.second.cmpUnitMotion->m_Clearance + b.second.cmpUnitMotion->m_Clearance).Multiply(m_PushingRadius);
entity_pos_t maxDist = combinedClearance;
if (movingPush)
maxDist += PUSHING_MOVING_INFLUENCE_EXTENSION;
Index: ps/trunk/source/simulation2/components/ICmpUnitMotionManager.h
===================================================================
--- ps/trunk/source/simulation2/components/ICmpUnitMotionManager.h
+++ ps/trunk/source/simulation2/components/ICmpUnitMotionManager.h
@@ -46,6 +46,11 @@
*/
virtual bool ComputingMotion() const = 0;
+ /**
+ * @return whether pushing is currently enabled or not.
+ */
+ virtual bool IsPushingActivated() const = 0;
+
};
#endif // INCLUDED_ICMPUNITMOTIONMANAGER