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
{
///
/// 磁导航 FASS 2.0 环线任务进程。
/// 任务分配/触发/流量逻辑继承 Core 。
/// 导航执行由 拦截 Loop 编译脚本(含 Mag2Go + goalSite),
/// 改为单次全程 0xB1 状态机任务。
///
[MissionType(Name = "磁导航FASS2环线", editor = typeof(Mag2LoopMission))]
public class Mag2LoopMission : LoopMission
{
[JsonIgnore] public override MissionStatus status { get; set; } = new LoopMissionStatus();
///
/// Mag2 空闲时可能尚未 TrafficReset(holdingLocks 为空),仍按上报站点/siteID 匹配在站车辆,
/// 否则 AutoLoop 永远找不到车、加不上 goalSite。
///
protected override Car FindCarArrivedAtSite(int siteId)
{
var byLock = base.FindCarArrivedAtSite(siteId);
if (byLock != null)
return byLock;
try
{
return SimpleLib.GetAllCars()
.OfType()
.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;
}
}
///
/// 分配前尽量补上本站交管锁,保证 SelectCar/GoSite 的 GetLastSite 可用。
///
protected override void AssignCarToTarget(Car car, int targetSiteId)
{
if (car is Mag2Car mag2 && !EnsureMag2HoldingCurrentSite(mag2))
{
return;
}
base.AssignCarToTarget(car, targetSiteId);
}
///
/// 用当前占点匹配全部 LoopTask 展开路径(不过滤 IsViaPoint)。
/// 路径用 BFS,避免 FindRoute 污染交管锁。
///
public static List FindChainsContaining(int siteId)
{
var matches = new List();
if (siteId <= 0)
{
return matches;
}
IEnumerable missions = null;
try
{
missions = SimpleProject.proj?.Missions?.OfType();
}
catch
{
missions = null;
}
if (missions == null)
{
return matches;
}
foreach (var mission in missions)
{
IReadOnlyList 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 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;
}
}
}
}