692 lines
23 KiB
C#
692 lines
23 KiB
C#
namespace Application.Domain;
|
||
|
||
// ===================== 核心定义:全局坐标体系 =====================
|
||
/// <summary>
|
||
/// 全局坐标结构体(所有城市共享唯一坐标)
|
||
/// </summary>
|
||
public struct Point
|
||
{
|
||
public int X; // 全局X坐标
|
||
public int Y; // 全局Y坐标
|
||
|
||
public Point(int x, int y)
|
||
{
|
||
X = x;
|
||
Y = y;
|
||
}
|
||
|
||
public override bool Equals(object obj)
|
||
{
|
||
return obj is Point point && X == point.X && Y == point.Y;
|
||
}
|
||
|
||
public override int GetHashCode()
|
||
{
|
||
return HashCode.Combine(X, Y);
|
||
}
|
||
|
||
public static bool operator ==(Point a, Point b) => a.X == b.X && a.Y == b.Y;
|
||
public static bool operator !=(Point a, Point b) => !(a == b);
|
||
|
||
public override string ToString() => $"({X},{Y})";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 城市节点(全局坐标管辖范围)
|
||
/// </summary>
|
||
public class CityNode
|
||
{
|
||
public int CityId { get; set; } // 城市ID
|
||
public string CityName { get; set; } // 城市名称
|
||
public Point CoreAnchor { get; set; } // 核心锚点(全局坐标)
|
||
public string CoreAnchorName { get; set; } // 核心锚点名称
|
||
public int MinX { get; set; } // 城市管辖范围-最小X(全局)
|
||
public int MaxX { get; set; } // 城市管辖范围-最大X(全局)
|
||
public int MinY { get; set; } // 城市管辖范围-最小Y(全局)
|
||
public int MaxY { get; set; } // 城市管辖范围-最大Y(全局)
|
||
public List<InterCityPortal> Portals { get; set; } // 所属传送点(全局坐标)
|
||
|
||
public CityNode(int cityId, string cityName, Point coreAnchor, string coreAnchorName,
|
||
int minX, int maxX, int minY, int maxY)
|
||
{
|
||
CityId = cityId;
|
||
CityName = cityName;
|
||
CoreAnchor = coreAnchor;
|
||
CoreAnchorName = coreAnchorName;
|
||
MinX = minX;
|
||
MaxX = maxX;
|
||
MinY = minY;
|
||
MaxY = maxY;
|
||
Portals = new List<InterCityPortal>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 校验全局坐标是否属于当前城市管辖范围
|
||
/// </summary>
|
||
public bool IsPointInCity(Point point)
|
||
{
|
||
return point.X >= MinX && point.X <= MaxX && point.Y >= MinY && point.Y <= MaxY;
|
||
}
|
||
|
||
public void AddPortal(InterCityPortal portal)
|
||
{
|
||
if (!Portals.Any(p => p.PortalId == portal.PortalId))
|
||
Portals.Add(portal);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 城际传送点(全局坐标,PortalId改为字符串)
|
||
/// </summary>
|
||
public class InterCityPortal
|
||
{
|
||
public string PortalId { get; set; } // 1. 改为字符串类型
|
||
public int BelongCityId { get; set; } // 所属城市ID
|
||
public Point Position { get; set; } // 传送点全局坐标
|
||
public int TargetCityId { get; set; } // 目标城市ID
|
||
public string PortalName { get; set; } // 传送点名称
|
||
public int Priority { get; set; } = 1; // 优先级
|
||
public string? ReversePortalId { get; set; } // 反向传送点ID(字符串)
|
||
|
||
public InterCityPortal(string portalId, int belongCityId, Point pos, int targetCityId, string name,
|
||
int priority = 1, string? reversePortalId = null)
|
||
{
|
||
PortalId = portalId;
|
||
BelongCityId = belongCityId;
|
||
Position = pos;
|
||
TargetCityId = targetCityId;
|
||
PortalName = name;
|
||
Priority = priority;
|
||
ReversePortalId = reversePortalId;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 全局路网(基于全局坐标管理城市+传送点)
|
||
/// </summary>
|
||
public class GlobalRoadNetwork
|
||
{
|
||
public Dictionary<int, CityNode> CityDict { get; private set; }
|
||
public Dictionary<string, InterCityPortal> PortalDict { get; private set; } // 适配字符串PortalId
|
||
|
||
public GlobalRoadNetwork()
|
||
{
|
||
CityDict = new Dictionary<int, CityNode>();
|
||
PortalDict = new Dictionary<string, InterCityPortal>(); // 改为字符串Key
|
||
}
|
||
|
||
public void AddCity(CityNode city)
|
||
{
|
||
if (!CityDict.ContainsKey(city.CityId))
|
||
CityDict.Add(city.CityId, city);
|
||
}
|
||
|
||
public void AddPortal(InterCityPortal portal)
|
||
{
|
||
if (!PortalDict.ContainsKey(portal.PortalId))
|
||
{
|
||
PortalDict.Add(portal.PortalId, portal);
|
||
if (CityDict.ContainsKey(portal.BelongCityId))
|
||
CityDict[portal.BelongCityId].AddPortal(portal);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据全局坐标获取所属城市
|
||
/// </summary>
|
||
public CityNode GetCityByGlobalPoint(Point point)
|
||
{
|
||
return CityDict.Values.FirstOrDefault(city => city.IsPointInCity(point));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取最优传送点(修复反向寻路筛选逻辑)
|
||
/// </summary>
|
||
public InterCityPortal GetOptimalPortal(int startCityId, int targetCityId, Point startPos,
|
||
Dictionary<int, CityRoadNetwork> cityNetworks, bool isReverse = false)
|
||
{
|
||
if (!CityDict.ContainsKey(startCityId) || !cityNetworks.ContainsKey(startCityId))
|
||
return null;
|
||
|
||
var startCity = CityDict[startCityId];
|
||
var startCityNetwork = cityNetworks[startCityId];
|
||
|
||
// 修复反向寻路筛选逻辑:
|
||
// - 正向:当前城市传送点 → 目标城市
|
||
// - 反向:目标城市传送点 → 当前城市(但从当前城市视角找)
|
||
var candidatePortals = isReverse
|
||
? CityDict.Values
|
||
.Where(c => c.CityId == targetCityId)
|
||
.SelectMany(c => c.Portals)
|
||
.Where(p => p.TargetCityId == startCityId)
|
||
.Where(p => startCityNetwork.IsPointWalkable(p.Position))
|
||
.Where(p => startCityNetwork.FindPathInCity(startPos, p.Position) != null)
|
||
: startCity.Portals
|
||
.Where(p => p.TargetCityId == targetCityId)
|
||
.Where(p => startCityNetwork.IsPointWalkable(p.Position))
|
||
.Where(p => startCityNetwork.FindPathInCity(startPos, p.Position) != null);
|
||
|
||
// 计算距离并排序
|
||
var sortedPortals = candidatePortals
|
||
.Select(p => new
|
||
{
|
||
Portal = p,
|
||
Distance = GetManhattanDistance(startPos, p.Position)
|
||
})
|
||
.OrderBy(p => p.Portal.Priority)
|
||
.ThenBy(p => p.Distance);
|
||
|
||
return sortedPortals.FirstOrDefault()?.Portal;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取反向传送点(适配字符串PortalId)
|
||
/// </summary>
|
||
public InterCityPortal GetReversePortal(InterCityPortal portal)
|
||
{
|
||
if (!string.IsNullOrEmpty(portal.ReversePortalId) && PortalDict.ContainsKey(portal.ReversePortalId))
|
||
return PortalDict[portal.ReversePortalId];
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 校验全局坐标合法性(属于某城市+该城市内可通行)
|
||
/// </summary>
|
||
public bool IsPointValid(Point point, Dictionary<int, CityRoadNetwork> cityNetworks)
|
||
{
|
||
var city = GetCityByGlobalPoint(point);
|
||
if (city == null || !cityNetworks.ContainsKey(city.CityId))
|
||
return false;
|
||
return cityNetworks[city.CityId].IsPointWalkable(point);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 修复:使用BFS获取所有连通的城市链(支持多中转)
|
||
/// </summary>
|
||
public List<int> GetConnectedCityChain(int startCityId, int endCityId)
|
||
{
|
||
if (startCityId == endCityId)
|
||
return new List<int> { startCityId };
|
||
|
||
// BFS队列:存储(当前城市ID, 路径)
|
||
var queue = new Queue<Tuple<int, List<int>>>();
|
||
var visited = new HashSet<int>();
|
||
|
||
queue.Enqueue(Tuple.Create(startCityId, new List<int> { startCityId }));
|
||
visited.Add(startCityId);
|
||
|
||
while (queue.Count > 0)
|
||
{
|
||
var current = queue.Dequeue();
|
||
int currCityId = current.Item1;
|
||
List<int> path = current.Item2;
|
||
|
||
// 获取当前城市所有可达的传送点目标城市
|
||
var reachableCities = CityDict[currCityId].Portals
|
||
.Select(p => p.TargetCityId)
|
||
.Distinct()
|
||
.Where(c => !visited.Contains(c));
|
||
|
||
foreach (int nextCityId in reachableCities)
|
||
{
|
||
var newPath = new List<int>(path) { nextCityId };
|
||
|
||
// 找到终点,返回路径
|
||
if (nextCityId == endCityId)
|
||
return newPath;
|
||
|
||
visited.Add(nextCityId);
|
||
queue.Enqueue(Tuple.Create(nextCityId, newPath));
|
||
}
|
||
}
|
||
|
||
return null; // 无可达路线
|
||
}
|
||
|
||
private int GetManhattanDistance(Point a, Point b)
|
||
{
|
||
return Math.Abs(a.X - b.X) + Math.Abs(a.Y - b.Y);
|
||
}
|
||
}
|
||
|
||
public class AStarNode : IComparable<AStarNode>
|
||
{
|
||
public Point Position { get; set; }
|
||
public AStarNode Parent { get; set; }
|
||
public int G { get; set; } // 起点到当前节点的代价
|
||
public int H { get; set; } // 当前节点到终点的预估代价
|
||
public int F => G + H; // 总代价
|
||
|
||
// 实现IComparable接口,解决SortedSet重复元素问题
|
||
public int CompareTo(AStarNode other)
|
||
{
|
||
if (other == null) return 1;
|
||
|
||
// 先按F值排序,再按H值,最后按坐标(避免重复)
|
||
int fCompare = F.CompareTo(other.F);
|
||
if (fCompare != 0) return fCompare;
|
||
|
||
int hCompare = H.CompareTo(other.H);
|
||
if (hCompare != 0) return hCompare;
|
||
|
||
int xCompare = Position.X.CompareTo(other.Position.X);
|
||
return xCompare != 0 ? xCompare : Position.Y.CompareTo(other.Position.Y);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 单城市路网(基于全局坐标管理可通行区域)
|
||
/// </summary>
|
||
public class CityRoadNetwork
|
||
{
|
||
public int CityId { get; set; }
|
||
public Dictionary<Point, bool> WalkablePoints { get; private set; } // 全局坐标可通行列表
|
||
|
||
public CityRoadNetwork(int cityId)
|
||
{
|
||
CityId = cityId;
|
||
WalkablePoints = new Dictionary<Point, bool>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加全局坐标可通行点
|
||
/// </summary>
|
||
public void AddWalkablePoint(int x, int y, bool walkable = true)
|
||
{
|
||
var point = new Point(x, y);
|
||
WalkablePoints[point] = walkable;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 批量添加全局坐标可通行区域
|
||
/// </summary>
|
||
public void AddWalkableRect(int minX, int maxX, int minY, int maxY, bool walkable = true)
|
||
{
|
||
if (minX > maxX || minY > maxY)
|
||
throw new ArgumentException("矩形范围不合法:min不能大于max");
|
||
|
||
for (int x = minX; x <= maxX; x++)
|
||
for (int y = minY; y <= maxY; y++)
|
||
AddWalkablePoint(x, y, walkable);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 校验全局坐标是否可走
|
||
/// </summary>
|
||
public bool IsPointWalkable(Point point)
|
||
{
|
||
return WalkablePoints.TryGetValue(point, out bool walkable) && walkable;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 修复后的A*寻路(基于全局坐标)
|
||
/// </summary>
|
||
public List<Point> FindPathInCity(Point start, Point end)
|
||
{
|
||
// 基础校验
|
||
if (!WalkablePoints.ContainsKey(start) || !WalkablePoints.ContainsKey(end))
|
||
return null;
|
||
if (!IsPointWalkable(start) || !IsPointWalkable(end))
|
||
return null;
|
||
if (start == end)
|
||
return new List<Point> { start };
|
||
|
||
// 开放列表(排序集合)和关闭列表
|
||
var openSet = new SortedSet<AStarNode>();
|
||
var openDict = new Dictionary<Point, AStarNode>(); // 快速查找
|
||
var closeDict = new Dictionary<Point, AStarNode>();
|
||
|
||
// 初始化起点
|
||
var startNode = new AStarNode
|
||
{
|
||
Position = start,
|
||
Parent = null,
|
||
G = 0,
|
||
H = GetManhattanDistance(start, end)
|
||
};
|
||
openSet.Add(startNode);
|
||
openDict[start] = startNode;
|
||
|
||
// 四方向移动
|
||
var dirs = new[] { new Point(0, 1), new Point(0, -1), new Point(1, 0), new Point(-1, 0) };
|
||
|
||
while (openSet.Count > 0)
|
||
{
|
||
// 获取F值最小的节点
|
||
var currentNode = openSet.Min;
|
||
openSet.Remove(currentNode);
|
||
openDict.Remove(currentNode.Position);
|
||
closeDict[currentNode.Position] = currentNode;
|
||
|
||
// 到达终点,回溯路径
|
||
if (currentNode.Position == end)
|
||
{
|
||
var path = new List<Point>();
|
||
var node = currentNode;
|
||
while (node != null)
|
||
{
|
||
path.Add(node.Position);
|
||
node = node.Parent;
|
||
}
|
||
|
||
path.Reverse();
|
||
return path;
|
||
}
|
||
|
||
// 遍历邻接节点
|
||
foreach (var dir in dirs)
|
||
{
|
||
var neighborPos = new Point(currentNode.Position.X + dir.X, currentNode.Position.Y + dir.Y);
|
||
|
||
// 跳过不可通行或已关闭的节点
|
||
if (!IsPointWalkable(neighborPos) || closeDict.ContainsKey(neighborPos))
|
||
continue;
|
||
|
||
// 计算新的G值
|
||
int newG = currentNode.G + 1;
|
||
|
||
// 邻接节点不存在或找到更优路径
|
||
if (!openDict.TryGetValue(neighborPos, out var neighborNode) || newG < neighborNode.G)
|
||
{
|
||
// 如果节点已存在,先移除
|
||
if (neighborNode != null)
|
||
{
|
||
openSet.Remove(neighborNode);
|
||
openDict.Remove(neighborPos);
|
||
}
|
||
|
||
// 创建/更新节点
|
||
neighborNode = new AStarNode
|
||
{
|
||
Position = neighborPos,
|
||
Parent = currentNode,
|
||
G = newG,
|
||
H = GetManhattanDistance(neighborPos, end)
|
||
};
|
||
|
||
openSet.Add(neighborNode);
|
||
openDict[neighborPos] = neighborNode;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 无路径
|
||
return null;
|
||
}
|
||
|
||
private int GetManhattanDistance(Point a, Point b)
|
||
{
|
||
return Math.Abs(a.X - b.X) + Math.Abs(a.Y - b.Y);
|
||
}
|
||
}
|
||
|
||
// ===================== 路径步骤定义 =====================
|
||
public enum PathStepType
|
||
{
|
||
Move,
|
||
Teleport
|
||
}
|
||
|
||
public class PathStep
|
||
{
|
||
public int CityId { get; set; }
|
||
public Point Position { get; set; } // 全局坐标
|
||
public PathStepType StepType { get; set; }
|
||
public int? TargetCityId { get; set; }
|
||
public Point? TargetAnchor { get; set; } // 目标锚点全局坐标
|
||
public string? TargetAnchorName { get; set; }
|
||
|
||
public string ToWapDesc(GlobalRoadNetwork globalNetwork)
|
||
{
|
||
var cityName = globalNetwork?.CityDict?.ContainsKey(CityId) == true
|
||
? globalNetwork.CityDict[CityId].CityName
|
||
: "未知城市";
|
||
|
||
return StepType switch
|
||
{
|
||
PathStepType.Move => $"【{cityName}】移动到全局坐标{Position}",
|
||
PathStepType.Teleport => GetTeleportDesc(globalNetwork, cityName),
|
||
_ => string.Empty
|
||
};
|
||
}
|
||
|
||
private string GetTeleportDesc(GlobalRoadNetwork globalNetwork, string currentCityName)
|
||
{
|
||
if (globalNetwork == null || !TargetCityId.HasValue)
|
||
return $"【{currentCityName}】通过传送阵→【未知城市】未知锚点";
|
||
|
||
var targetCityName = globalNetwork.CityDict.ContainsKey(TargetCityId.Value)
|
||
? globalNetwork.CityDict[TargetCityId.Value].CityName
|
||
: "未知城市";
|
||
|
||
var anchorName = string.IsNullOrEmpty(TargetAnchorName) ? "未知锚点" : TargetAnchorName;
|
||
var anchorPos = TargetAnchor.HasValue ? $"(全局坐标{TargetAnchor})" : "";
|
||
|
||
return $"【{currentCityName}】通过传送阵→【{targetCityName}】{anchorName}{anchorPos}";
|
||
}
|
||
}
|
||
|
||
// ===================== 跨城寻路核心服务(全自动适配) =====================
|
||
public class CrossCityPathFinder
|
||
{
|
||
private readonly GlobalRoadNetwork _globalNetwork;
|
||
private readonly Dictionary<int, CityRoadNetwork> _cityNetworks;
|
||
|
||
public CrossCityPathFinder(GlobalRoadNetwork globalNetwork)
|
||
{
|
||
_globalNetwork = globalNetwork;
|
||
_cityNetworks = new Dictionary<int, CityRoadNetwork>();
|
||
}
|
||
|
||
public void AddCityRoadNetwork(CityRoadNetwork cityNetwork)
|
||
{
|
||
if (!_cityNetworks.ContainsKey(cityNetwork.CityId))
|
||
_cityNetworks.Add(cityNetwork.CityId, cityNetwork);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 核心方法:输入起止点,全自动判定同城/跨城/多城市,自动适配正向/反向
|
||
/// </summary>
|
||
public List<PathStep> FindCrossCityPath(Point startPos, Point endPos)
|
||
{
|
||
// 1. 基础校验:识别起止点所属城市
|
||
var startCity = _globalNetwork.GetCityByGlobalPoint(startPos);
|
||
var endCity = _globalNetwork.GetCityByGlobalPoint(endPos);
|
||
|
||
if (startCity == null || endCity == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
// 2. 同城寻路
|
||
if (startCity.CityId == endCity.CityId)
|
||
{
|
||
return FindSameCityPath(startCity.CityId, startPos, endPos);
|
||
}
|
||
|
||
// 3. 跨城/多城市寻路(使用修复后的BFS路径链)
|
||
var cityChain = _globalNetwork.GetConnectedCityChain(startCity.CityId, endCity.CityId);
|
||
if (cityChain == null || cityChain.Count < 2)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
// 自动适配正向/反向
|
||
var cityStartPoints = new Dictionary<int, Point>
|
||
{
|
||
{ startCity.CityId, startPos },
|
||
{ endCity.CityId, endPos }
|
||
};
|
||
|
||
// 自动判断是否需要反向寻路
|
||
var isReverse = IsNeedReverseRoute(startCity.CityId, endCity.CityId);
|
||
|
||
return FindMultiCityPath(cityChain, cityStartPoints, isReverse);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 同城寻路
|
||
/// </summary>
|
||
private List<PathStep> FindSameCityPath(int cityId, Point startPos, Point endPos)
|
||
{
|
||
if (!_globalNetwork.IsPointValid(startPos, _cityNetworks) ||
|
||
!_globalNetwork.IsPointValid(endPos, _cityNetworks))
|
||
{
|
||
return null;
|
||
}
|
||
|
||
var cityPath = _cityNetworks[cityId].FindPathInCity(startPos, endPos);
|
||
return cityPath?.Select(p => new PathStep
|
||
{
|
||
CityId = cityId,
|
||
Position = p,
|
||
StepType = PathStepType.Move
|
||
}).ToList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 多城市寻路(自动适配正向/反向)
|
||
/// </summary>
|
||
private List<PathStep> FindMultiCityPath(List<int> cityChain, Dictionary<int, Point> cityStartPoints,
|
||
bool isReverse)
|
||
{
|
||
var finalPath = new List<PathStep>();
|
||
var actualChain = isReverse ? cityChain.AsEnumerable().Reverse().ToList() : cityChain;
|
||
|
||
for (int i = 0; i < actualChain.Count - 1; i++)
|
||
{
|
||
int currCityId = actualChain[i];
|
||
int nextCityId = actualChain[i + 1];
|
||
Point currStartPoint = cityStartPoints.ContainsKey(currCityId)
|
||
? cityStartPoints[currCityId]
|
||
: _globalNetwork.CityDict[currCityId].CoreAnchor;
|
||
|
||
// 校验起点坐标归属
|
||
var currCity = _globalNetwork.CityDict[currCityId];
|
||
if (!currCity.IsPointInCity(currStartPoint))
|
||
{
|
||
return null;
|
||
}
|
||
|
||
if (!_globalNetwork.IsPointValid(currStartPoint, _cityNetworks))
|
||
return null;
|
||
|
||
// 获取最优传送点(自动传入反向标识)
|
||
var optimalPortal =
|
||
_globalNetwork.GetOptimalPortal(currCityId, nextCityId, currStartPoint, _cityNetworks, isReverse);
|
||
if (optimalPortal == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
// 当前城市内:起点 → 传送点
|
||
var currToPortal = _cityNetworks[currCityId].FindPathInCity(currStartPoint, optimalPortal.Position);
|
||
if (currToPortal == null)
|
||
return null;
|
||
finalPath.AddRange(currToPortal.Select(p => new PathStep
|
||
{
|
||
CityId = currCityId,
|
||
Position = p,
|
||
StepType = PathStepType.Move
|
||
}));
|
||
|
||
// 跨城传送
|
||
var nextCity = _globalNetwork.CityDict[nextCityId];
|
||
finalPath.Add(new PathStep
|
||
{
|
||
CityId = currCityId,
|
||
Position = optimalPortal.Position,
|
||
StepType = PathStepType.Teleport,
|
||
TargetCityId = nextCityId,
|
||
TargetAnchor = nextCity.CoreAnchor,
|
||
TargetAnchorName = nextCity.CoreAnchorName
|
||
});
|
||
|
||
// 更新下一个城市的起点
|
||
if (!cityStartPoints.ContainsKey(nextCityId))
|
||
cityStartPoints.Add(nextCityId, nextCity.CoreAnchor);
|
||
|
||
// 最后一段:核心锚点→终点
|
||
if (i == actualChain.Count - 2)
|
||
{
|
||
Point nextEndPoint = cityStartPoints[nextCityId];
|
||
var anchorToEnd = _cityNetworks[nextCityId].FindPathInCity(nextCity.CoreAnchor, nextEndPoint);
|
||
if (anchorToEnd == null)
|
||
return null;
|
||
finalPath.AddRange(anchorToEnd.Select(p => new PathStep
|
||
{
|
||
CityId = nextCityId,
|
||
Position = p,
|
||
StepType = PathStepType.Move
|
||
}));
|
||
}
|
||
}
|
||
|
||
return finalPath;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动判断是否需要反向寻路
|
||
/// </summary>
|
||
private bool IsNeedReverseRoute(int startCityId, int endCityId)
|
||
{
|
||
// 检查正向传送点
|
||
var startCity = _globalNetwork.CityDict[startCityId];
|
||
var hasForward = startCity.Portals.Any(p => p.TargetCityId == endCityId);
|
||
|
||
// 正向无则反向
|
||
if (!hasForward)
|
||
{
|
||
var endCity = _globalNetwork.CityDict[endCityId];
|
||
var hasReverse = endCity.Portals.Any(p => p.TargetCityId == startCityId);
|
||
return hasReverse;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 辅助方法:获取城市名称
|
||
/// </summary>
|
||
private string GetCityName(CityNode city)
|
||
{
|
||
return city?.CityName ?? "未知城市";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 简化路径描述(用于展示)
|
||
/// </summary>
|
||
public List<string> SimplifyPathForWap(List<PathStep> fullPath)
|
||
{
|
||
if (fullPath == null || fullPath.Count == 0)
|
||
return new List<string>();
|
||
|
||
var simplified = new List<string>();
|
||
PathStep? lastTeleport = null;
|
||
|
||
foreach (var step in fullPath)
|
||
{
|
||
if (step.StepType == PathStepType.Teleport)
|
||
{
|
||
simplified.Add(step.ToWapDesc(_globalNetwork));
|
||
lastTeleport = step;
|
||
}
|
||
else if (lastTeleport == null && step == fullPath.First())
|
||
{
|
||
var cityName = _globalNetwork.CityDict.ContainsKey(step.CityId)
|
||
? _globalNetwork.CityDict[step.CityId].CityName
|
||
: "未知城市";
|
||
simplified.Add($"【{cityName}】从起点(全局坐标{step.Position})出发");
|
||
}
|
||
else if (step == fullPath.Last())
|
||
{
|
||
var cityName = _globalNetwork.CityDict.ContainsKey(step.CityId)
|
||
? _globalNetwork.CityDict[step.CityId].CityName
|
||
: "未知城市";
|
||
simplified.Add($"【{cityName}】到达终点(全局坐标{step.Position})");
|
||
}
|
||
}
|
||
|
||
return simplified;
|
||
}
|
||
} |