Files
StandardSence/StandardScene.Magnetic/Chained/Mag2LoopMission.cs
T
黄兆尉andCursor 7e2a5697b4 fix: Mag2 环线补锁失败时不再派车
TrafficReset 失败则跳过 AssignCarToTarget,避免无锁占用仍打上 goalSite。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-26 23:04:26 +08:00

216 lines
6.8 KiB
C#
Raw 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 LessokajiWeaverUtilities.Utilities;
using SimpleCore;
using SimpleCore.Library;
using Simple3;
using Simple3.Props;
using Simple3.RCS;
using Simple3.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))
{
return;
}
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 bool EnsureMag2HoldingCurrentSite(Mag2Car car)
{
try
{
if (car.status?.holdingLocks != null && car.status.holdingLocks.Length == 1)
return true;
var siteId = car.siteID > 0 ? car.siteID : car.GetLastSite();
if (siteId <= 0)
return false;
var site = SimpleLib.GetSite(siteId);
if (site == null)
return false;
car.TrafficReset(site, true, strict: false);
return true;
}
catch (Exception ex)
{
Diagnosis.Post(
$"Mag2 补交管锁失败,跳过派车 car={car?.id}{ex.Message}",
"Mag2Loop",
true);
return false;
}
}
}
}