using System; using System.Collections.Generic; namespace StandardScene.Fass2Simulator { /// /// 对齐 Fass2ActionResolver 的到站动作判定(独立副本,避免引用 Magnetic)。 /// public static class Fass2SimActionResolver { public const byte StartStopPass = 1; public const byte StartStopStop = 2; public const byte StartStopControlStart = 11; public const byte StartStopControlStop = 12; public const byte StartStopPrecision = 22; public static bool VerifyTrajectoryFields { get; set; } private static readonly (string Name, Func Get)[] MechanismFields = { ("Obstacle", n => n.Obstacle), ("Audio", n => n.Audio), ("Light", n => n.Light), ("Charge", n => n.Charge), ("Rest", n => n.Rest), ("Lift", n => n.Lift), ("Clamp", n => n.Clamp), ("Tray", n => n.Tray), ("Roll", n => n.Roll), ("Shutdown", n => n.Shutdown) }; private static readonly (string Name, Func Get)[] TrajectoryFields = { ("Direction", n => n.Direction), ("Orientation", n => n.Orientation), ("Byroad", n => n.Byroad) }; public static bool AllowsAutoContinue(byte startStop) { return startStop == StartStopPass || startStop == StartStopControlStart; } public static bool RequiresActionWait(Fass2SimNodeMessage expected) { if (expected == null) { return false; } if (expected.StartStop is StartStopStop or StartStopPrecision or StartStopControlStop or StartStopControlStart) { return true; } foreach (var field in MechanismFields) { if (field.Get(expected) != 0) { return true; } } if (!VerifyTrajectoryFields) { return false; } foreach (var field in TrajectoryFields) { if (field.Get(expected) != 0) { return true; } } return expected.Speed != 0; } public static bool IsStationActionComplete(Fass2SimNodeMessage expected, Fass2SimVehicleSnapshot actual, byte vehicleState) { if (expected == null || actual == null) { return false; } if (actual.Node != expected.Node) { return false; } if (vehicleState is 1 or 5) { return false; } if (!RequiresActionWait(expected)) { return true; } if (expected.StartStop == StartStopPass) { return true; } if (expected.StartStop == StartStopControlStop) { return false; } return ListPendingFields(expected, actual).Count == 0; } public static List ListPendingFields(Fass2SimNodeMessage expected, Fass2SimVehicleSnapshot actual) { var pending = new List(); if (expected == null || actual == null) { return pending; } if (expected.StartStop != 0 && actual.StartStop != expected.StartStop) { pending.Add("StartStop"); } if (VerifyTrajectoryFields) { if (expected.Speed != 0 && actual.Speed != expected.Speed) { pending.Add("Speed"); } foreach (var field in TrajectoryFields) { var expectedValue = field.Get(expected); if (expectedValue != 0 && GetActualField(actual, field.Name) != expectedValue) { pending.Add(field.Name); } } } foreach (var field in MechanismFields) { var expectedValue = field.Get(expected); if (expectedValue != 0 && GetActualField(actual, field.Name) != expectedValue) { pending.Add(field.Name); } } return pending; } public static string DescribePending(Fass2SimNodeMessage expected, Fass2SimVehicleSnapshot actual) { var pending = ListPendingFields(expected, actual); return pending.Count == 0 ? string.Empty : string.Join(",", pending); } private static byte GetActualField(Fass2SimVehicleSnapshot actual, string name) { switch (name) { case "Direction": return actual.Direction; case "Orientation": return actual.Orientation; case "Byroad": return actual.Byroad; case "Obstacle": return actual.Obstacle; case "Audio": return actual.Audio; case "Light": return actual.Light; case "Charge": return actual.Charge; case "Rest": return actual.Rest; case "Lift": return actual.Lift; case "Clamp": return actual.Clamp; case "Tray": return actual.Tray; case "Roll": return actual.Roll; case "Shutdown": return actual.Shutdown; default: return 0; } } } }