Files

210 lines
6.6 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using SimpleCore;
using SimpleCore.Library;
using SimpleLite;
using SimpleLite.Props;
using SimpleLite.RCS;
using SimpleLite.RCS.CarTypes;
using StandardScene.CarTypes;
using StandardScene.Chained;
using StandardScene.Magnetic.Tasking;
using StandardScene.Model;
namespace StandardScene
{
/// <summary>
/// 磁导航 FASS 2.0 环线任务进程。
/// <para>任务分配/触发/流量逻辑继承 Core <see cref="LoopMission"/>。</para>
/// <para>导航执行由 <see cref="Mag2Car"/> 拦截 Loop 编译脚本(含 <c>Mag2Go</c> + <c>goalSite</c>),
/// 改为单次全程 <c>0xB1</c> 状态机任务。</para>
/// </summary>
[MissionType(Name = "磁导航FASS2环线", editor = typeof(Mag2LoopMission))]
public class Mag2LoopMission : LoopMission
{
[JsonIgnore] public override MissionStatus status { get; set; } = new LoopMissionStatus();
/// <summary>
/// Mag2 空闲时可能尚未 TrafficResetholdingLocks 为空),仍按上报站点/siteID 匹配在站车辆,
/// 否则 AutoLoop 永远找不到车、加不上 goalSite。
/// </summary>
protected override Car FindCarArrivedAtSite(int siteId)
{
var byLock = base.FindCarArrivedAtSite(siteId);
if (byLock != null)
return byLock;
try
{
return SimpleLib.GetAllCars()
.OfType<Mag2Car>()
.FirstOrDefault(car =>
{
if (car?.tags == null || car.tags.Contains("occupied") || !car.tags.Contains("Online"))
return false;
if (car.status?.pendingLocks != null && car.status.pendingLocks.Length > 0)
return false;
if (car.status?.holdingLocks != null && car.status.holdingLocks.Length > 1)
return false;
var physical = car.siteID > 0 ? car.siteID : car.GetLastSite();
return physical == siteId;
});
}
catch
{
return null;
}
}
/// <summary>
/// 分配前尽量补上本站交管锁,保证 SelectCar/GoSite 的 GetLastSite 可用。
/// </summary>
protected override void AssignCarToTarget(Car car, int targetSiteId)
{
if (car is Mag2Car mag2)
{
EnsureMag2HoldingCurrentSite(mag2);
}
base.AssignCarToTarget(car, targetSiteId);
}
/// <summary>
/// 用当前占点匹配全部 LoopTask 展开路径(不过滤 IsViaPoint)。
/// 路径用 BFS,避免 FindRoute 污染交管锁。
/// </summary>
public static List<Fass2ChainMatch> FindChainsContaining(int siteId)
{
var matches = new List<Fass2ChainMatch>();
if (siteId <= 0)
{
return matches;
}
IEnumerable<AbstractLoopMission> missions = null;
try
{
missions = SimpleProject.proj?.Missions?.OfType<AbstractLoopMission>();
}
catch
{
missions = null;
}
if (missions == null)
{
return matches;
}
foreach (var mission in missions)
{
IReadOnlyList<LoopTask> tasks;
try
{
tasks = mission.GetTasks();
}
catch
{
continue;
}
if (tasks == null)
{
continue;
}
foreach (var task in tasks)
{
var match = TryMatchTask(task, siteId);
if (match != null)
{
matches.Add(match);
}
}
}
return matches;
}
public static bool TryResolveBelongingChain(
int siteId,
int? preferGoalSiteId,
out Fass2ChainMatch selected,
out string reason)
{
var matches = FindChainsContaining(siteId);
return Fass2ReconnectChainSelector.TrySelect(matches, preferGoalSiteId, out selected, out reason);
}
private static Fass2ChainMatch TryMatchTask(LoopTask task, int siteId)
{
if (task == null || task.CurrentStationId <= 0 || task.TargetStationId <= 0)
{
return null;
}
List<int> fullPath;
try
{
fullPath = Fass2RouteHelper.GetSitesBetween(task.CurrentStationId, task.TargetStationId, null);
}
catch
{
return null;
}
if (fullPath == null || fullPath.Count == 0)
{
return null;
}
var index = fullPath.IndexOf(siteId);
if (index < 0)
{
return null;
}
var remaining = fullPath.Skip(index).ToList();
return new Fass2ChainMatch
{
TaskId = task.Id,
TaskPriority = task.Priority,
CurrentSiteId = siteId,
TargetSiteId = task.TargetStationId,
IndexInPath = index,
DistanceToTarget = Math.Max(0, fullPath.Count - index - 1),
IsAtStartPoint = index == 0,
IsAtEndPoint = index == fullPath.Count - 1,
FullPath = fullPath,
RemainingPath = remaining
};
}
private static void EnsureMag2HoldingCurrentSite(Mag2Car car)
{
try
{
if (car.status?.holdingLocks != null && car.status.holdingLocks.Length == 1)
return;
var siteId = car.siteID > 0 ? car.siteID : car.GetLastSite();
if (siteId <= 0)
return;
var site = SimpleLib.GetSite(siteId);
if (site == null)
return;
car.TrafficReset(site, true, strict: false);
}
catch (Exception)
{
// 交管失败时仍允许打上 goalSite,后续 GoSite/状态机会再处理
}
}
}
}