Unstable v0.15.17.0 (Hex is out of town edition)
This commit is contained in:
@@ -84,18 +84,17 @@ namespace Barotrauma
|
||||
public bool IsBlocked()
|
||||
{
|
||||
if (blocked.HasValue) { return blocked.Value; }
|
||||
|
||||
blocked = false;
|
||||
|
||||
if (Waypoint.Submarine != null) { return blocked.Value; }
|
||||
if (Waypoint.Tunnel?.Type != Level.TunnelType.Cave) { return blocked.Value; }
|
||||
foreach (var w in Level.Loaded.ExtraWalls)
|
||||
{
|
||||
if (!(w is DestructibleLevelWall d)) { return blocked.Value; }
|
||||
if (d.Destroyed) { return blocked.Value; }
|
||||
if (!d.IsPointInside(Waypoint.Position)) { return blocked.Value; }
|
||||
blocked = true;
|
||||
break;
|
||||
if (!w.IsPointInside(Waypoint.Position)) { continue; }
|
||||
if (w is DestructibleLevelWall d)
|
||||
{
|
||||
blocked = !d.Destroyed;
|
||||
}
|
||||
if (blocked.Value) { break; }
|
||||
}
|
||||
return blocked.Value;
|
||||
}
|
||||
@@ -125,6 +124,7 @@ namespace Barotrauma
|
||||
{
|
||||
wp.OnLinksChanged += WaypointLinksChanged;
|
||||
}
|
||||
sortedNodes = new List<PathNode>(nodes.Count);
|
||||
this.isCharacter = isCharacter;
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<PathNode> sortedNodes = new List<PathNode>();
|
||||
private readonly List<PathNode> sortedNodes;
|
||||
|
||||
public SteeringPath FindPath(Vector2 start, Vector2 end, Submarine hostSub = null, string errorMsgStr = null, float minGapSize = 0, Func<PathNode, bool> startNodeFilter = null, Func<PathNode, bool> endNodeFilter = null, Func<PathNode, bool> nodeFilter = null, bool checkVisibility = true)
|
||||
{
|
||||
@@ -175,8 +175,7 @@ namespace Barotrauma
|
||||
node.ResetBlocked();
|
||||
}
|
||||
|
||||
//sort nodes roughly according to distance
|
||||
sortedNodes.Clear();
|
||||
// First calculate the temp positions for all nodes.
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
node.TempPosition = node.Position;
|
||||
@@ -194,8 +193,15 @@ namespace Barotrauma
|
||||
else if (hostSub == null && wpSub != null)
|
||||
{
|
||||
// Outside and targeting inside
|
||||
node.TempPosition += wpSub.SimPosition;
|
||||
node.TempPosition += wpSub.SimPosition;
|
||||
}
|
||||
}
|
||||
|
||||
//sort nodes roughly according to distance
|
||||
sortedNodes.Clear();
|
||||
PathNode startNode = null;
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
float xDiff = Math.Abs(start.X - node.TempPosition.X);
|
||||
float yDiff = Math.Abs(start.Y - node.TempPosition.Y);
|
||||
if (InsideSubmarine && !(node.Waypoint.Submarine?.Info?.IsRuin ?? false))
|
||||
@@ -215,13 +221,20 @@ namespace Barotrauma
|
||||
//much higher cost to waypoints that are outside
|
||||
if (node.Waypoint.CurrentHull == null && ApplyPenaltyToOutsideNodes) { node.TempDistance *= 10.0f; }
|
||||
|
||||
//optimization:
|
||||
//node extremely far, don't try to use it as a start node
|
||||
if (node.TempDistance > 800.0f)
|
||||
//optimization: node extremely far, don't try to use it as a start node
|
||||
if (node.TempDistance > (InsideSubmarine ? 100.0f : 800.0f))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//optimization: node extremely close (< 1 m). If it's valid, choose it as the start node and skip the more exhaustive search for the closest one
|
||||
if (node.TempDistance < 1.0f)
|
||||
{
|
||||
if (IsValidStartNode(node))
|
||||
{
|
||||
startNode = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//prefer nodes that are closer to the end position
|
||||
node.TempDistance += (Math.Abs(end.X - node.TempPosition.X) + Math.Abs(end.Y - node.TempPosition.Y)) / 100.0f;
|
||||
|
||||
@@ -233,6 +246,88 @@ namespace Barotrauma
|
||||
sortedNodes.Insert(i, node);
|
||||
}
|
||||
|
||||
//find the most suitable start node, starting from the ones that are the closest
|
||||
if (startNode == null)
|
||||
{
|
||||
foreach (PathNode node in sortedNodes)
|
||||
{
|
||||
if (IsValidStartNode(node))
|
||||
{
|
||||
startNode = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (startNode == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage("Pathfinding error, couldn't find a start node. "+ errorMsgStr, Color.DarkRed);
|
||||
#endif
|
||||
return new SteeringPath(true);
|
||||
}
|
||||
|
||||
//sort nodes again, now based on distance from the end position
|
||||
sortedNodes.Clear();
|
||||
PathNode endNode = null;
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
node.TempDistance = Vector2.DistanceSquared(end, node.TempPosition);
|
||||
if (InsideSubmarine)
|
||||
{
|
||||
if (ApplyPenaltyToOutsideNodes)
|
||||
{
|
||||
//much higher cost to waypoints that are outside
|
||||
if (node.Waypoint.CurrentHull == null) { node.TempDistance *= 10.0f; }
|
||||
}
|
||||
//avoid stopping at a doorway
|
||||
if (node.Waypoint.ConnectedDoor != null) { node.TempDistance *= 10.0f; }
|
||||
//avoid stopping at a ladder
|
||||
if (node.Waypoint.Ladders != null) { node.TempDistance *= 10.0f; }
|
||||
}
|
||||
//optimization: node extremely far (> 100m / 800 m) from the end position, don't try to use it as an end node
|
||||
if (node.TempDistance > (InsideSubmarine ? 100.0f * 100.0f : 800.0f * 800.0f))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//optimization: node extremely close (< 1 m). If it's valid, choose it as the end node and skip the more exhaustive search for the closest one
|
||||
if (node.TempDistance < 1.0f)
|
||||
{
|
||||
if (IsValidEndNode(node))
|
||||
{
|
||||
endNode = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int i = 0;
|
||||
while (i < sortedNodes.Count && sortedNodes[i].TempDistance < node.TempDistance)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
sortedNodes.Insert(i, node);
|
||||
}
|
||||
if (endNode == null)
|
||||
{
|
||||
//find the most suitable end node, starting from the ones closest to the end position
|
||||
foreach (PathNode node in sortedNodes)
|
||||
{
|
||||
if (IsValidEndNode(node))
|
||||
{
|
||||
endNode = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (endNode == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage("Pathfinding error, couldn't find an end node. " + errorMsgStr, Color.DarkRed);
|
||||
#endif
|
||||
return new SteeringPath(true);
|
||||
}
|
||||
var path = FindPath(startNode, endNode, nodeFilter, errorMsgStr, minGapSize);
|
||||
return path;
|
||||
|
||||
bool IsWaypointVisible(PathNode node, Vector2 rayStart, bool checkVisibility = true)
|
||||
{
|
||||
//if searching for a path inside the sub, make sure the waypoint is visible
|
||||
@@ -251,85 +346,33 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
//find the most suitable start node, starting from the ones that are the closest
|
||||
PathNode startNode = null;
|
||||
foreach (PathNode node in sortedNodes)
|
||||
bool IsValidStartNode(PathNode node)
|
||||
{
|
||||
if (nodeFilter != null && !nodeFilter(node)) { continue; }
|
||||
if (startNodeFilter != null && !startNodeFilter(node)) { continue; }
|
||||
if (nodeFilter != null && !nodeFilter(node)) { return false; }
|
||||
if (startNodeFilter != null && !startNodeFilter(node)) { return false; }
|
||||
// Always check the visibility for the start node
|
||||
if (!IsWaypointVisible(node, start)) { continue; }
|
||||
if (node.IsBlocked()) { continue; }
|
||||
if (!IsWaypointVisible(node, start)) { return false; }
|
||||
if (node.IsBlocked()) { return false; }
|
||||
if (node.Waypoint.ConnectedGap != null)
|
||||
{
|
||||
if (!CanFitThroughGap(node.Waypoint.ConnectedGap, minGapSize)) { continue; }
|
||||
if (!CanFitThroughGap(node.Waypoint.ConnectedGap, minGapSize)) { return false; }
|
||||
}
|
||||
startNode = node;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (startNode == null)
|
||||
bool IsValidEndNode(PathNode node)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage("Pathfinding error, couldn't find a start node. "+ errorMsgStr, Color.DarkRed);
|
||||
#endif
|
||||
return new SteeringPath(true);
|
||||
}
|
||||
|
||||
//sort nodes again, now based on distance from the end position
|
||||
sortedNodes.Clear();
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
node.TempDistance = Vector2.DistanceSquared(end, node.TempPosition);
|
||||
if (InsideSubmarine)
|
||||
{
|
||||
if (ApplyPenaltyToOutsideNodes)
|
||||
{
|
||||
//much higher cost to waypoints that are outside
|
||||
if (node.Waypoint.CurrentHull == null) { node.TempDistance *= 10.0f; }
|
||||
}
|
||||
//avoid stopping at a doorway
|
||||
if (node.Waypoint.ConnectedDoor != null) { node.TempDistance *= 10.0f; }
|
||||
//avoid stopping at a ladder
|
||||
if (node.Waypoint.Ladders != null) { node.TempDistance *= 10.0f; }
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (i < sortedNodes.Count && sortedNodes[i].TempDistance < node.TempDistance)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
sortedNodes.Insert(i, node);
|
||||
}
|
||||
|
||||
//find the most suitable end node, starting from the ones closest to the end position
|
||||
PathNode endNode = null;
|
||||
foreach (PathNode node in sortedNodes)
|
||||
{
|
||||
if (nodeFilter != null && !nodeFilter(node)) { continue; }
|
||||
if (endNodeFilter != null && !endNodeFilter(node)) { continue; }
|
||||
if (nodeFilter != null && !nodeFilter(node)) { return false; }
|
||||
if (endNodeFilter != null && !endNodeFilter(node)) { return false; }
|
||||
// Only check the visibility for the end node when allowed (fix leaks)
|
||||
if (!IsWaypointVisible(node, end, checkVisibility: checkVisibility)) { continue; }
|
||||
if (node.IsBlocked()) { continue; }
|
||||
if (!IsWaypointVisible(node, end, checkVisibility: checkVisibility)) { return false; }
|
||||
if (node.IsBlocked()) { return false; }
|
||||
if (node.Waypoint.ConnectedGap != null)
|
||||
{
|
||||
if (!CanFitThroughGap(node.Waypoint.ConnectedGap, minGapSize)) { continue; }
|
||||
if (!CanFitThroughGap(node.Waypoint.ConnectedGap, minGapSize)) { return false; }
|
||||
}
|
||||
endNode = node;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (endNode == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage("Pathfinding error, couldn't find an end node. " + errorMsgStr, Color.DarkRed);
|
||||
#endif
|
||||
return new SteeringPath(true);
|
||||
}
|
||||
|
||||
var path = FindPath(startNode, endNode, nodeFilter, errorMsgStr, minGapSize);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private SteeringPath FindPath(PathNode start, PathNode end, Func<PathNode, bool> filter = null, string errorMsgStr = "", float minGapSize = 0)
|
||||
|
||||
Reference in New Issue
Block a user