1
0
forked from 0ad/0ad

Revert the logic change in 9da482ead4. This commit removed the checks in UnitMotion against structures, which should have been fine except the short-range pathfinder and the long-range pathfinder are not entirely compatible (check out #3532 for details). This behavior was probably slightly optimized, but it was too clever for its own good in the current state of the pathfinder, might be reintroduced later.

This resulted in ALL "units inside obstructions" issues.

Thanks to elexis for the testing.

Fixes #3532, #3450.
Refs #3538 (still OOSes), #3410 (unitmotion remains buggy for
formations, but this is only aesthethic.)
Probably affects #3471 and #3505, but those are not fixed.

This was SVN commit r17152.
This commit is contained in:
wraitii 2015-10-31 08:43:31 +00:00
parent e895b044e7
commit 8494e36aa8
6 changed files with 22 additions and 98 deletions

View File

@ -538,17 +538,4 @@ public:
}
};
/**
* Sent when the pathfinder's passability map is modified on update
*/
class CMessagePassabilityMapChanged : public CMessage
{
public:
DEFAULT_MESSAGE_IMPL(PassabilityMapChanged)
CMessagePassabilityMapChanged()
{
}
};
#endif // INCLUDED_MESSAGETYPES

View File

@ -57,7 +57,6 @@ MESSAGE(ValueModification)
MESSAGE(TemplateModification)
MESSAGE(VisionRangeChanged)
MESSAGE(MinimapPing)
MESSAGE(PassabilityMapChanged)
// TemplateManager must come before all other (non-test) components,
// so that it is the first to be (de)serialized

View File

@ -522,16 +522,7 @@ void CCmpPathfinder::UpdateGrid()
}
else
m_LongPathfinder.Update(m_Grid, m_ObstructionsDirty.dirtinessGrid);
// Notify the units that their current paths can be invalid now.
// The passability map will be globally dirty after init, or rejoining, loading a saved game, etc.
// In those situations the paths can't be invalid.
if (!m_ObstructionsDirty.globallyDirty)
{
CMessagePassabilityMapChanged msg;
GetSimContext().GetComponentManager().BroadcastMessage(msg);
}
}
void CCmpPathfinder::MinimalTerrainUpdate()
{
@ -727,7 +718,7 @@ void CCmpPathfinder::ProcessShortRequests(const std::vector<AsyncShortPathReques
{
const AsyncShortPathRequest& req = shortRequests[i];
WaypointPath path;
ControlGroupMovementObstructionFilter filter(true, req.avoidMovingUnits, req.group);
ControlGroupMovementObstructionFilter filter(req.avoidMovingUnits, req.group);
ComputeShortPath(filter, req.x0, req.z0, req.clearance, req.range, req.goal, req.passClass, path);
CMessagePathResult msg(req.ticket, path);
GetSimContext().GetComponentManager().PostMessage(req.notify, msg);

View File

@ -135,7 +135,6 @@ public:
componentManager.SubscribeToMessageType(MT_PathResult);
componentManager.SubscribeToMessageType(MT_ValueModification);
componentManager.SubscribeToMessageType(MT_Deserialized);
componentManager.SubscribeToMessageType(MT_PassabilityMapChanged);
}
DEFAULT_COMPONENT_ALLOCATOR(UnitMotion)
@ -255,10 +254,6 @@ public:
WaypointPath m_LongPath;
WaypointPath m_ShortPath;
// When the passability map has changed, we cannot fully trust the path computed by the
// pathfinder before that change.
bool m_PassabilityMapChangedRecently;
// Motion planning
SUnitMotionPlanning m_Planning;
@ -331,8 +326,6 @@ public:
m_ExpectedPathTicket = 0;
m_PassabilityMapChangedRecently = false;
m_TargetEntity = INVALID_ENTITY;
m_FinalGoal.type = PathGoal::POINT;
@ -369,7 +362,6 @@ public:
SerializeVector<SerializeWaypoint>()(serialize, "long path", m_LongPath.m_Waypoints);
SerializeVector<SerializeWaypoint>()(serialize, "short path", m_ShortPath.m_Waypoints);
serialize.Bool("passability map changed recently", m_PassabilityMapChangedRecently);
SerializeUnitMotionPlanning()(serialize, "planning", m_Planning);
@ -453,9 +445,6 @@ public:
m_RunSpeed = newRunSpeed;
break;
}
case MT_PassabilityMapChanged:
m_PassabilityMapChangedRecently = true;
break;
}
}
@ -668,14 +657,7 @@ private:
/**
* Returns an appropriate obstruction filter for use with path requests.
*/
ControlGroupMovementObstructionFilter GetObstructionFilter(bool avoidPathfindingShapes) const;
/**
* Checks our movement towards the next path waypoint.
* Pathfinding-blocking shapes are assumed to be taken into account during the path computation
* and this will only be used to avoid moving units.
*/
bool CheckMovement(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1) const;
ControlGroupMovementObstructionFilter GetObstructionFilter(bool forceAvoidMovingUnits = false) const;
/**
* Start moving to the given goal, from our current position 'from'.
@ -735,8 +717,6 @@ void CCmpUnitMotion::PathResult(u32 ticket, const WaypointPath& path)
if (m_PathState == PATHSTATE_WAITING_REQUESTING_LONG || m_PathState == PATHSTATE_FOLLOWING_REQUESTING_LONG)
{
m_PassabilityMapChangedRecently = false;
m_LongPath = path;
// If we are following a path, leave the old m_ShortPath so we can carry on following it
@ -852,6 +832,10 @@ void CCmpUnitMotion::Move(fixed dt)
// Maybe we should split the updates into multiple phases to minimise
// that problem.
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
if (!cmpPathfinder)
return;
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
if (!cmpPosition || !cmpPosition->IsInWorld())
return;
@ -911,7 +895,7 @@ void CCmpUnitMotion::Move(fixed dt)
fixed offsetLength = offset.Length();
if (offsetLength <= maxdist)
{
if (CheckMovement(pos.X, pos.Y, target.X, target.Y))
if (cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, target.X, target.Y, m_Clearance, m_PassClass))
{
pos = target;
@ -941,7 +925,7 @@ void CCmpUnitMotion::Move(fixed dt)
offset.Normalize(maxdist);
target = pos + offset;
if (CheckMovement(pos.X, pos.Y, target.X, target.Y))
if (cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, target.X, target.Y, m_Clearance, m_PassClass))
{
pos = target;
break;
@ -970,14 +954,14 @@ void CCmpUnitMotion::Move(fixed dt)
if (wasObstructed)
{
// Oops, we hit something (very likely another unit, or a new obstruction).
// Oops, we hit something (very likely another unit).
// Stop, and recompute the whole path.
// TODO: if the target has UnitMotion and is higher priority,
// we should wait a little bit.
// Recompute our path
// If we are following a long path and it is still valid
if (!m_LongPath.m_Waypoints.empty() && !m_PassabilityMapChangedRecently)
// If we are following a long path
if (!m_LongPath.m_Waypoints.empty())
{
PathGoal goal = { PathGoal::POINT, m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z };
RequestShortPath(pos, goal, true);
@ -1050,12 +1034,14 @@ void CCmpUnitMotion::PlanNextStep(const CFixedVector2D& pos)
if (m_LongPath.m_Waypoints.empty())
return;
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
const Waypoint& nextPoint = m_LongPath.m_Waypoints.back();
// The next step was obstructed the last time we checked; also check that
// the step is still obstructed (maybe the units in our way moved in the meantime)
if (!m_Planning.nextStepClean && CheckMovement(pos.X, pos.Y, nextPoint.x, nextPoint.z))
if (!m_Planning.nextStepClean &&
!cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, nextPoint.x, nextPoint.z, m_Clearance, m_PassClass))
{
// If the short path computation is over, use it, else just forget about it
if (!m_Planning.nextStepShortPath.m_Waypoints.empty())
@ -1071,13 +1057,10 @@ void CCmpUnitMotion::PlanNextStep(const CFixedVector2D& pos)
return;
const Waypoint& followingPoint = m_LongPath.m_Waypoints.rbegin()[1]; // penultimate element
m_Planning.nextStepClean = CheckMovement(nextPoint.x, nextPoint.z, followingPoint.x, followingPoint.z);
m_Planning.nextStepClean = cmpPathfinder->CheckMovement(
GetObstructionFilter(), nextPoint.x, nextPoint.z, followingPoint.x, followingPoint.z, m_Clearance, m_PassClass);
if (!m_Planning.nextStepClean)
{
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
if (!cmpPathfinder)
return;
PathGoal goal = { PathGoal::POINT, followingPoint.x, followingPoint.z };
m_Planning.expectedPathTicket = cmpPathfinder->ComputeShortPathAsync(
nextPoint.x, nextPoint.z, m_Clearance, SHORT_PATH_SEARCH_RANGE, goal, m_PassClass, false, m_TargetEntity, GetEntityId());
@ -1124,7 +1107,7 @@ bool CCmpUnitMotion::TryGoingStraightToGoalPoint(const CFixedVector2D& from)
return false;
// Check if there's any collisions on that route
if (!cmpPathfinder->CheckMovement(GetObstructionFilter(true), from.X, from.Y, goalPos.X, goalPos.Y, m_Clearance, m_PassClass))
if (!cmpPathfinder->CheckMovement(GetObstructionFilter(), from.X, from.Y, goalPos.X, goalPos.Y, m_Clearance, m_PassClass))
return false;
// That route is okay, so update our path
@ -1160,7 +1143,7 @@ bool CCmpUnitMotion::TryGoingStraightToTargetEntity(const CFixedVector2D& from)
CFixedVector2D goalPos = goal.NearestPointOnGoal(from);
// Check if there's any collisions on that route
if (!cmpPathfinder->CheckMovement(GetObstructionFilter(true), from.X, from.Y, goalPos.X, goalPos.Y, m_Clearance, m_PassClass))
if (!cmpPathfinder->CheckMovement(GetObstructionFilter(), from.X, from.Y, goalPos.X, goalPos.Y, m_Clearance, m_PassClass))
return false;
// That route is okay, so update our path
@ -1268,7 +1251,7 @@ void CCmpUnitMotion::FaceTowardsPointFromPos(const CFixedVector2D& pos, entity_p
}
}
ControlGroupMovementObstructionFilter CCmpUnitMotion::GetObstructionFilter(bool avoidPathfindingShapes) const
ControlGroupMovementObstructionFilter CCmpUnitMotion::GetObstructionFilter(bool forceAvoidMovingUnits) const
{
entity_id_t group;
if (IsFormationMember())
@ -1276,25 +1259,9 @@ ControlGroupMovementObstructionFilter CCmpUnitMotion::GetObstructionFilter(bool
else
group = GetEntityId();
return ControlGroupMovementObstructionFilter(avoidPathfindingShapes, ShouldAvoidMovingUnits(), group);
return ControlGroupMovementObstructionFilter(forceAvoidMovingUnits || ShouldAvoidMovingUnits(), group);
}
bool CCmpUnitMotion::CheckMovement(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1) const
{
// If the passability map has changed, we have to check everything in our way until we compute a new path.
if (m_PassabilityMapChangedRecently)
{
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
return cmpPathfinder && cmpPathfinder->CheckMovement(GetObstructionFilter(true), x0, z0, x1, z1, m_Clearance, m_PassClass);
}
// If an obstruction blocks tile-based pathfinding, it will be handled during the path computation
// and doesn't need to be matched by this filter for the movement.
ControlGroupMovementObstructionFilter filter = GetObstructionFilter(false);
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity());
return cmpObstructionManager && !cmpObstructionManager->TestLine(filter, x0, z0, x1, z1, m_Clearance);
}
void CCmpUnitMotion::BeginPathing(const CFixedVector2D& from, const PathGoal& goal)
@ -1310,9 +1277,6 @@ void CCmpUnitMotion::BeginPathing(const CFixedVector2D& from, const PathGoal& go
if (cmpObstruction)
cmpObstruction->SetMovingFlag(true);
// We are going to recompute our path, so we will use the most recent passability grid
m_PassabilityMapChangedRecently = false;
#if DISABLE_PATHFINDER
{
CmpPtr<ICmpPathfinder> cmpPathfinder (GetSimContext(), SYSTEM_ENTITY);

View File

@ -323,13 +323,12 @@ public:
*/
class ControlGroupMovementObstructionFilter : public IObstructionTestFilter
{
bool m_AvoidPathfindingShapes;
bool m_AvoidMoving;
entity_id_t m_Group;
public:
ControlGroupMovementObstructionFilter(bool avoidPathfindingShapes, bool avoidMoving, entity_id_t group) :
m_AvoidPathfindingShapes(avoidPathfindingShapes), m_AvoidMoving(avoidMoving), m_Group(group)
ControlGroupMovementObstructionFilter(bool avoidMoving, entity_id_t group) :
m_AvoidMoving(avoidMoving), m_Group(group)
{}
virtual bool TestShape(tag_t UNUSED(tag), flags_t flags, entity_id_t group, entity_id_t group2) const
@ -337,9 +336,6 @@ public:
if (group == m_Group || (group2 != INVALID_ENTITY && group2 == m_Group))
return false;
if ((flags & ICmpObstructionManager::FLAG_BLOCK_PATHFINDING) && !m_AvoidPathfindingShapes)
return false;
if (!(flags & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT))
return false;

View File

@ -470,19 +470,6 @@ CMessage* CMessageMinimapPing::FromJSVal(ScriptInterface& UNUSED(scriptInterface
return new CMessageMinimapPing();
}
////////////////////////////////
JS::Value CMessagePassabilityMapChanged::ToJSVal(ScriptInterface& scriptInterface) const
{
TOJSVAL_SETUP();
return JS::ObjectValue(*obj);
}
CMessage* CMessagePassabilityMapChanged::FromJSVal(ScriptInterface& UNUSED(scriptInterface), JS::HandleValue UNUSED(val))
{
return new CMessagePassabilityMapChanged();
}
////////////////////////////////////////////////////////////////
CMessage* CMessageFromJSVal(int mtid, ScriptInterface& scriptingInterface, JS::HandleValue val)