using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using LessokajiWeaverUtilities.MagicAttributes;
using LessokajiWeaverUtilities.Utilities;
using Newtonsoft.Json;
using Simple3.RCS;
using Simple3.RCS.CarTypes;
using SimpleCore;
using SimpleCore.Library;
using SimpleCore.PropType;
using SimpleCore.Traffic;
using StandardScene.Utils;
namespace StandardScene.ExtendDevice.Door
{
//todo:2026.1.21 1,门控制器的通信参数配置移动到具体门控制器类中管理,实现对不同通信类型的支持
[MissionType(Name = "门控进程")]
[I18N.DocumentTranslation(Name = "DoorMission", locale = "en")]
public class DoorMission : Mission
{
private const string DataFileName = "DoorConfig.json";
private string _dataFilePath;
///
/// 当前所有门控制器实例列表
///
private List _doorControllers = new List();
///
/// 用于管理异步循环的取消令牌源
///
private CancellationTokenSource _cancellationTokenSource;
///
/// 保存监控配置与状态的后台任务
///
private Task _configTask;
private Task _stateTask;
///
/// 同步锁,用于保护门控制器列表的并发访问
///
private readonly object _syncLock = new object();
///
/// 门区域内的小车记录:(ControllerIndex, DoorIndex) -> List
///
[JsonIgnore] private readonly Dictionary<(int ControllerIndex, int DoorIndex), List> carsInAreas = new Dictionary<(int ControllerIndex, int DoorIndex), List>();
///
/// 需要打开的门:(ControllerIndex, DoorIndex) -> bool
///
[JsonIgnore] private readonly Dictionary<(int ControllerIndex, int DoorIndex), bool> _needOpen = new Dictionary<(int ControllerIndex, int DoorIndex), bool>();
///
/// 手动控制请求:(ControllerIndex, DoorIndex) -> ManualControlRequest
///
[JsonIgnore] private readonly Dictionary<(int ControllerIndex, int DoorIndex), ManualControlRequest> _manualRequests = new Dictionary<(int ControllerIndex, int DoorIndex), ManualControlRequest>();
private const int DefaultManualHoldSeconds = 10;
public enum ControlSource
{
Auto = 0,
Manual = 1
}
private class ManualControlRequest
{
public bool Target { get; set; }
public DateTime ExpireAt { get; set; }
}
public class DoorControlStatus
{
public bool Target { get; set; }
public ControlSource Source { get; set; }
public double? ManualRemainingSeconds { get; set; }
public IReadOnlyList CarsInArea { get; set; } = Array.Empty();
}
///
/// 监控界面快照项(线程安全快照,避免UI直接枚举可变字典)
///
public class DoorMonitorSnapshotItem
{
public int ControllerIndex { get; set; }
public int DoorIndex { get; set; }
public DoorState State { get; set; }
public bool Target { get; set; }
public ControlSource Source { get; set; }
public double? ManualRemainingSeconds { get; set; }
public IReadOnlyList CarsInArea { get; set; } = Array.Empty();
public ushort ControlAddress { get; set; }
public ushort OpenStatusAddress { get; set; }
}
[MethodMember(Name = "启动进程")]
[I18N.DocumentTranslation(Name = "Start Mission", locale = "en")]
public override void Execute()
{
// 设置数据文件路径
_dataFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DataFileName);
// 如果已经启动,先停止之前的循环
StopInternalAsync().GetAwaiter().GetResult();
TrafficControl.BeforeLock += BeforeLockEvent;
TrafficControl.AfterLeave += AfterLeaveEvent;
TrafficControl.OnLockAcquired += OnLockAcquiredEvent;
// 启动时立即加载一次配置,避免监控界面在第一次轮询前无数据
try
{
var configControllers = LoadDoorControllerConfig();
SyncDoorControllers(configControllers);
}
catch (Exception ex)
{
Diagnosis.Log($"启动时加载门控制器配置失败: {ExceptionFormatter.FormatEx(ex)}", "DoorMission", true);
}
// 创建新的取消令牌源
_cancellationTokenSource = new CancellationTokenSource();
// 启动异步循环
var token = _cancellationTokenSource.Token;
_configTask = Task.Run(async () => await MonitorDoorConfigAsync(token), token);
_stateTask = Task.Run(async () => await MonitorDoorLogicAsync(token), token);
status.status = "Running";
}
///
/// 停止监控任务
///
[MethodMember(Name = "停止进程")]
[I18N.DocumentTranslation(Name = "Stop Mission", locale = "en")]
public override void Stop()
{
StopInternalAsync().GetAwaiter().GetResult();
status.status = "/";
}
///
/// 取消并释放当前的取消令牌源
///
private async Task StopInternalAsync()
{
// 取消事件订阅
TrafficControl.BeforeLock -= BeforeLockEvent;
TrafficControl.AfterLeave -= AfterLeaveEvent;
TrafficControl.OnLockAcquired -= OnLockAcquiredEvent;
var cts = Interlocked.Exchange(ref _cancellationTokenSource, null);
var configTask = Interlocked.Exchange(ref _configTask, null);
var stateTask = Interlocked.Exchange(ref _stateTask, null);
if (cts == null && configTask == null && stateTask == null)
{
return;
}
try
{
cts?.Cancel();
}
catch (ObjectDisposedException)
{
// 已释放,忽略
}
var runningTasks = new[] { configTask, stateTask }
.Where(t => t != null)
.ToArray();
if (runningTasks.Length > 0)
{
var aggregateTask = Task.WhenAll(runningTasks);
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(5));
var completedTask = await Task.WhenAny(aggregateTask, timeoutTask).ConfigureAwait(false);
if (completedTask == timeoutTask)
{
Diagnosis.Log("停止门控任务超时", "DoorMission", true);
}
else
{
try
{
await aggregateTask.ConfigureAwait(false);
}
catch (Exception ex)
{
Diagnosis.Log($"停止门控任务时发生异常: {ExceptionFormatter.FormatEx(ex)}", "DoorMission", true);
}
}
}
cts?.Dispose();
DisconnectAllDoorControllers();
}
///
/// 断开所有门控制器连接
///
private void DisconnectAllDoorControllers()
{
List snapshot;
lock (_syncLock)
{
snapshot = _doorControllers.ToList();
}
foreach (var controller in snapshot)
{
try
{
controller.Disconnect();
}
catch (Exception ex)
{
Diagnosis.Log($"停止门控制器失败: Index={controller.Index}, Error={ExceptionFormatter.FormatEx(ex)}", "DoorMission", true);
}
}
}
///
/// 异步监控门控制器配置文件
///
private async Task MonitorDoorConfigAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
// 读取配置文件
var configControllers = LoadDoorControllerConfig();
// 同步门控制器列表
SyncDoorControllers(configControllers);
// 等待10秒
await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);
}
catch (OperationCanceledException)
{
// 正常取消,退出循环
break;
}
catch (Exception ex)
{
Diagnosis.Log($"门控制器配置监控错误: {ExceptionFormatter.FormatEx(ex)}", "DoorMission", true);
// 发生错误时等待5秒后重试
try
{
await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken);
}
catch (OperationCanceledException)
{
break;
}
}
}
}
///
/// 监控门控逻辑
///
private async Task MonitorDoorLogicAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
lock (_syncLock)
{
foreach (var controller in _doorControllers)
{
foreach (var doorConfig in controller.DoorConfigs.Values)
{
var doorIndex = doorConfig.Index;
var key = (controller.Index, doorIndex);
var needOpen = _needOpen.TryGetValue(key, out var open) && open;
// 自动目标:有车或需要打开
var hasCarsInArea = carsInAreas.TryGetValue(key, out var cars) && cars.Count > 0;
var autoTarget = needOpen || hasCarsInArea;
// 手动请求仲裁:优先级 Manual > Auto,手动过期后自动恢复
bool finalTarget = autoTarget;
if (_manualRequests.TryGetValue(key, out var manual))
{
if (manual.ExpireAt <= DateTime.Now)
{
_manualRequests.Remove(key);
}
else
{
finalTarget = manual.Target;
}
}
// 仅更新门控制器中的目标控制字段,不直接进行通信
controller.SetDoorControlTarget(doorIndex, finalTarget);
}
}
}
await Task.Delay(TimeSpan.FromMilliseconds(500), cancellationToken);
}
catch (OperationCanceledException)
{
// 正常取消,退出循环
break;
}
catch (Exception ex)
{
Diagnosis.Log($"门控逻辑监控错误: {ExceptionFormatter.FormatEx(ex)}", "DoorMission", true);
// 发生错误时等待5秒后重试
try
{
await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken);
}
catch (OperationCanceledException)
{
break;
}
}
}
}
///
/// 加载门控制器配置文件
///
private List LoadDoorControllerConfig()
{
try
{
if (File.Exists(_dataFilePath))
{
var jsonContent = File.ReadAllText(_dataFilePath, Encoding.UTF8);
if (!string.IsNullOrWhiteSpace(jsonContent))
{
var controllers = jsonContent.JsonTo>();
return controllers ?? new List();
}
}
}
catch (Exception ex)
{
Diagnosis.Log($"加载门控制器配置文件失败: {ExceptionFormatter.FormatEx(ex)}", "DoorMission", true);
}
return new List();
}
///
/// 同步门控制器列表,根据配置文件进行增删改
///
private void SyncDoorControllers(List configControllers)
{
var controllersToAdd = new List();
lock (_syncLock)
{
// 创建配置中的门控制器索引字典
var configDict = configControllers.ToDictionary(c => c.Index);
// 创建当前门控制器索引字典
var currentDict = _doorControllers.ToDictionary(c => c.Index);
// 1. 删除:在配置中不存在的门控制器
var toRemove = _doorControllers.Where(c => !configDict.ContainsKey(c.Index)).ToList();
foreach (var controller in toRemove)
{
try
{
controller.Disconnect();
_doorControllers.Remove(controller);
Diagnosis.Post($"删除门控制器: Index={controller.Index}, IP={controller.Ip}", "DoorMission", true);
}
catch (Exception ex)
{
Diagnosis.Log($"删除门控制器失败: {ExceptionFormatter.FormatEx(ex)}", "DoorMission", true);
}
}
// 2. 添加和修改:遍历配置中的门控制器
foreach (var configController in configControllers)
{
if (currentDict.TryGetValue(configController.Index, out var existingController))
{
// 修改:检查是否需要更新
if (ShouldUpdateDoorController(existingController, configController))
{
try
{
UpdateDoorController(existingController, configController);
Diagnosis.Post($"更新门控制器: Index={configController.Index}, IP={configController.Ip}, Type={configController.Type}", "DoorMission", true);
}
catch (Exception ex)
{
Diagnosis.Log($"更新门控制器失败: {ExceptionFormatter.FormatEx(ex)}", "DoorMission", true);
}
}
}
else
{
controllersToAdd.Add(configController);
}
}
}
foreach (var configController in controllersToAdd)
{
try
{
var newController = CreateDoorControllerInstance(configController);
if (newController != null)
{
lock (_syncLock)
{
_doorControllers.Add(newController);
}
Diagnosis.Post($"添加门控制器: Index={configController.Index}, IP={configController.Ip}, Type={configController.Type}", "DoorMission", true);
}
else
{
Diagnosis.Log($"无法创建门控制器实例: Index={configController.Index}, Type={configController.Type}", "DoorMission", true);
}
}
catch (Exception ex)
{
Diagnosis.Log($"添加门控制器失败: {ExceptionFormatter.FormatEx(ex)}", "DoorMission", true);
}
}
}
///
/// 获取门控制器类型的 DoorTypeAttribute.Name
///
private string GetDoorTypeName(Type controllerType)
{
if (controllerType == null)
{
return string.Empty;
}
var attr = controllerType.GetCustomAttribute();
return attr?.Name ?? controllerType.Name;
}
///
/// 判断是否需要更新门控制器
///
private bool ShouldUpdateDoorController(BasicDoorController existingController, DoorControllerModel configController)
{
// 检查基本属性是否变更
var existingTypeName = GetDoorTypeName(existingController.GetType());
if (existingController.Ip != configController.Ip
|| existingController.Port != configController.Port
|| existingTypeName != configController.Type)
{
return true;
}
// 检查门配置信息是否变更
return HasDoorConfigsChanged(existingController, configController);
}
///
/// 检查门配置信息是否变更
///
private bool HasDoorConfigsChanged(BasicDoorController existingController, DoorControllerModel configController)
{
var configDoors = configController.Doors ?? new List();
var configDict = configDoors.ToDictionary(d => d.Index);
var existingDict = existingController.DoorConfigs;
// 检查门数量是否变化
if (existingDict.Count != configDict.Count)
{
return true;
}
// 检查每个门的配置是否变化
foreach (var configDoor in configDoors)
{
if (!existingDict.TryGetValue(configDoor.Index, out var existingDoor))
{
// 新增了门
return true;
}
// 检查门配置是否变化
if (existingDoor.ControlAddress != configDoor.ControlAddress
|| existingDoor.OpenStatusAddress != configDoor.OpenStatusAddress)
{
return true;
}
}
// 检查是否有门被删除
foreach (var existingKey in existingDict.Keys)
{
if (!configDict.ContainsKey(existingKey))
{
return true;
}
}
return false;
}
///
/// 更新门控制器属性
///
private void UpdateDoorController(BasicDoorController controller, DoorControllerModel configController)
{
// 如果类型改变,需要重新创建实例
var existingTypeName = GetDoorTypeName(controller.GetType());
if (existingTypeName != configController.Type)
{
// 断开旧连接
controller.Disconnect();
// 从列表中移除
_doorControllers.Remove(controller);
// 创建新实例
var newController = CreateDoorControllerInstance(configController);
if (newController != null)
{
_doorControllers.Add(newController);
}
}
else
{
// 只更新属性
bool needReconnect = controller.Ip != configController.Ip || controller.Port != configController.Port;
controller.Ip = configController.Ip;
controller.Port = configController.Port;
// 更新门配置信息
controller.UpdateDoorConfigs(configController.Doors);
// 初始化门状态(基于配置中的门索引)
var doorIndices = configController.Doors?.Select(d => d.Index).ToList() ?? new List();
controller.InitializeDoors(doorIndices);
// 如果IP或端口改变,需要重新连接
if (needReconnect)
{
controller.Disconnect();
controller.Connect();
}
}
}
///
/// 根据 DoorTypeAttribute.Name 获取类型
///
private Type GetControllerTypeByDoorTypeName(string doorTypeName)
{
if (string.IsNullOrWhiteSpace(doorTypeName))
{
return null;
}
try
{
// 在插件/宿主环境下 GetExecutingAssembly 可能不是 StandardScene.dll
// 这里固定从门控制器基类所在程序集查找
// 跨程序集发现:门控制器具体类型可能位于卫星插件 dll(StandardScene.Devices.Door),
// 用内核同款全域类型发现替代仅扫基类所在程序集。
var allControllerTypes = Simple3.Utils.UiTypeDiscovery.AllTypes()
.Where(t => t.IsClass
&& !t.IsAbstract
&& t.Namespace == typeof(BasicDoorController).Namespace
&& t.IsSubclassOf(typeof(BasicDoorController))
&& t.IsDefined(typeof(DoorTypeAttribute), false));
foreach (var type in allControllerTypes)
{
var attr = type.GetCustomAttribute();
if (attr != null && attr.Name == doorTypeName)
{
return type;
}
}
return null;
}
catch (Exception ex)
{
Diagnosis.Log($"获取门控制器类型失败: DoorTypeName={doorTypeName}, Error={ExceptionFormatter.FormatEx(ex)}", "DoorMission", true);
return null;
}
}
///
/// 通过 DoorTypeAttribute.Name 创建门控制器实例
///
private BasicDoorController CreateDoorControllerInstance(DoorControllerModel configController)
{
if (string.IsNullOrWhiteSpace(configController.Type))
{
return null;
}
try
{
// 通过 DoorTypeAttribute.Name 查找类型
var controllerType = GetControllerTypeByDoorTypeName(configController.Type);
if (controllerType == null)
{
Diagnosis.Log($"未找到门控制器类型: {configController.Type}", "DoorMission", true);
return null;
}
// 使用反射创建实例
var instance = (BasicDoorController)Activator.CreateInstance(controllerType);
// 设置属性
instance.Index = configController.Index;
instance.Ip = configController.Ip;
instance.Port = configController.Port;
// 初始化门配置信息
instance.InitializeDoorConfigs(configController.Doors);
// 初始化门状态(基于配置中的门索引)
var doorIndices = configController.Doors?.Select(d => d.Index).ToList() ?? new List();
instance.InitializeDoors(doorIndices);
// 自动连接
instance.Connect();
return instance;
}
catch (Exception ex)
{
Diagnosis.Log($"创建门控制器实例失败: Type={configController.Type}, Error={ExceptionFormatter.FormatEx(ex)}", "DoorMission", true);
return null;
}
}
///
/// 获取当前所有门控制器实例(只读)
///
public IReadOnlyList GetDoorControllers()
{
lock (_syncLock)
{
return _doorControllers.ToList().AsReadOnly();
}
}
///
/// 获取用于监控界面的门状态快照
///
public IReadOnlyList GetDoorMonitorSnapshot()
{
lock (_syncLock)
{
var snapshot = new List();
var now = DateTime.Now;
foreach (var controller in _doorControllers)
{
var doorConfigs = controller.DoorConfigs?.Values?.ToList() ?? new List();
foreach (var doorConfig in doorConfigs)
{
var key = (controller.Index, doorConfig.Index);
var cars = carsInAreas.TryGetValue(key, out var list) && list != null
? list.ToList().AsReadOnly()
: new List().AsReadOnly();
var source = ControlSource.Auto;
double? manualRemaining = null;
bool target = false;
if (_manualRequests.TryGetValue(key, out var manual))
{
if (manual.ExpireAt > now)
{
source = ControlSource.Manual;
target = manual.Target;
manualRemaining = (manual.ExpireAt - now).TotalSeconds;
}
else
{
_manualRequests.Remove(key);
}
}
if (source == ControlSource.Auto)
{
var needOpen = _needOpen.TryGetValue(key, out var open) && open;
target = needOpen || cars.Count > 0;
}
snapshot.Add(new DoorMonitorSnapshotItem
{
ControllerIndex = controller.Index,
DoorIndex = doorConfig.Index,
State = controller.GetDoorState(doorConfig.Index),
Target = target,
Source = source,
ManualRemainingSeconds = manualRemaining,
CarsInArea = cars,
ControlAddress = doorConfig.ControlAddress,
OpenStatusAddress = doorConfig.OpenStatusAddress
});
}
}
return snapshot.AsReadOnly();
}
}
///
/// 解析门标识符字符串(格式:控制器索引.门索引)
///
/// 门标识符字符串,格式:控制器索引.门索引
/// 如果解析成功返回(控制器索引, 门索引),否则返回null
private (int ControllerIndex, int DoorIndex)? ParseDoorIdentifier(string doorIdentifier)
{
if (string.IsNullOrWhiteSpace(doorIdentifier))
{
return null;
}
var parts = doorIdentifier.Split('.');
if (parts.Length != 2)
{
return null;
}
if (int.TryParse(parts[0].Trim(), out int controllerIndex) &&
int.TryParse(parts[1].Trim(), out int doorIndex))
{
return (controllerIndex, doorIndex);
}
return null;
}
///
/// 读取门状态
///
/// 门控制器索引
/// 门索引
/// true=打开,false=关闭
public bool GetDoorState(int controllerIndex, int doorIndex)
{
lock (_syncLock)
{
var controller = _doorControllers.FirstOrDefault(c => c.Index == controllerIndex);
if (controller != null && controller.DoorConfigs.ContainsKey(doorIndex))
{
// 只访问控制器中的门状态字段,不直接进行通信
var state = controller.GetDoorState(doorIndex);
return state == DoorState.Open;
}
}
return false;
}
///
/// 写入门控制状态
///
/// 门控制器索引
/// 门索引
/// true=打开,false=关闭
public void SetDoorControlTarget(int controllerIndex, int doorIndex, bool open)
{
lock (_syncLock)
{
var controller = _doorControllers.FirstOrDefault(c => c.Index == controllerIndex);
if (controller != null && controller.DoorConfigs.ContainsKey(doorIndex))
{
// 仅设置门的目标控制状态,由门控制器内部线程负责实际通信
controller.SetDoorControlTarget(doorIndex, open);
}
}
}
///
/// 设置手动控制目标,支持保持时间,车辆占用时禁止手动关闭
///
/// 控制器索引
/// 门索引
/// 目标开关
/// 手动保持秒数,默认10秒
/// 成功返回true;当占用且尝试关闭时返回false
public bool SetManualDoorControl(int controllerIndex, int doorIndex, bool open, int? holdSeconds = null)
{
lock (_syncLock)
{
// 车辆占用时禁止手动关闭
var key = (controllerIndex, doorIndex);
if (!open && carsInAreas.TryGetValue(key, out var cars) && cars.Count > 0)
{
return false;
}
var seconds = holdSeconds.GetValueOrDefault(DefaultManualHoldSeconds);
_manualRequests[key] = new ManualControlRequest
{
Target = open,
ExpireAt = DateTime.Now.AddSeconds(seconds)
};
return true;
}
}
///
/// 清除手动控制,恢复自动
///
public void ClearManualDoorControl(int controllerIndex, int doorIndex)
{
lock (_syncLock)
{
var key = (controllerIndex, doorIndex);
_manualRequests.Remove(key);
}
}
///
/// 清空车辆占用记录
///
public void ClearCarsInArea(int controllerIndex, int doorIndex)
{
lock (_syncLock)
{
var key = (controllerIndex, doorIndex);
if (carsInAreas.ContainsKey(key))
{
carsInAreas[key].Clear();
}
}
}
///
/// 获取门的控制状态(目标、来源、手动剩余时间、占用车辆)
///
public DoorControlStatus GetDoorControlStatus(int controllerIndex, int doorIndex)
{
lock (_syncLock)
{
var key = (controllerIndex, doorIndex);
// 车辆占用
IReadOnlyList cars;
if (carsInAreas.TryGetValue(key, out var list) && list != null)
{
cars = list.ToList().AsReadOnly();
}
else
{
cars = new List().AsReadOnly();
}
// 当前目标来源与剩余
var source = ControlSource.Auto;
double? remaining = null;
bool target = false;
if (_manualRequests.TryGetValue(key, out var manual))
{
if (manual.ExpireAt > DateTime.Now)
{
source = ControlSource.Manual;
target = manual.Target;
remaining = (manual.ExpireAt - DateTime.Now).TotalSeconds;
}
else
{
_manualRequests.Remove(key);
}
}
if (source == ControlSource.Auto)
{
var needOpen = _needOpen.TryGetValue(key, out var open) && open;
var hasCars = cars.Count > 0;
target = needOpen || hasCars;
}
return new DoorControlStatus
{
Target = target,
Source = source,
ManualRemainingSeconds = remaining,
CarsInArea = cars
};
}
}
///
/// 获取门的车辆占用情况
///
/// 门控制器索引
/// 门索引
/// 车辆ID列表,如果没有车辆则返回空列表
public IReadOnlyList GetCarsInArea(int controllerIndex, int doorIndex)
{
lock (_syncLock)
{
var key = (controllerIndex, doorIndex);
if (carsInAreas.TryGetValue(key, out var cars) && cars != null)
{
return cars.ToList().AsReadOnly();
}
return new List().AsReadOnly();
}
}
private bool BeforeLockEvent(AbstractCar car, int siteId)
{
var site = SimpleLib.GetSite(siteId);
if (!site.fields.TryGetValue("EnterDoor", out string fieldStr)) return true;
var lastSiteId = car.status.holdingLocks.LastOrDefault();
var lastSite = SimpleLib.GetSite(lastSiteId);
if (lastSite == null || !lastSite.fields.TryGetValue("PreEnterDoor",out var value)) return true;
if (value != fieldStr) return true;
var doorInfo = ParseDoorIdentifier(fieldStr);
if (!doorInfo.HasValue) return true;
var (controllerIndex, doorIndex) = doorInfo.Value;
lock (_syncLock)
{
_needOpen[(controllerIndex, doorIndex)] = true;
return GetDoorState(controllerIndex, doorIndex);
}
}
private void AfterLeaveEvent(AbstractCar car, int siteId)
{
var site = SimpleLib.GetSite(siteId);
if (!site.fields.TryGetValue("LeaveDoor", out string fieldStr)) return;
var carSiteId = car.status.holdingLocks.FirstOrDefault();
var carSite = SimpleLib.GetSite(carSiteId);
if (carSite == null || !carSite.fields.TryGetValue("RearLeaveDoor",out var value)) return;
if (value != fieldStr) return;
var doorInfo = ParseDoorIdentifier(fieldStr);
if (!doorInfo.HasValue) return;
var (controllerIndex, doorIndex) = doorInfo.Value;
var key = (controllerIndex, doorIndex);
lock (_syncLock)
{
if (carsInAreas.TryGetValue(key, out var list))
{
list.Remove(car.id);
}
}
}
private void OnLockAcquiredEvent(AbstractCar car, int siteId)
{
var site = SimpleLib.GetSite(siteId);
if (!site.fields.TryGetValue("EnterDoor", out string fieldStr)) return;
if(car.status.holdingLocks.Length<2) return;
var preSiteId = car.status.holdingLocks[car.status.holdingLocks.Length-2];
var preSite = SimpleLib.GetSite(preSiteId);
if (preSite == null || !preSite.fields.TryGetValue("PreEnterDoor", out var value)) return ;
if (value != fieldStr) return ;
var doorInfo = ParseDoorIdentifier(fieldStr);
if (!doorInfo.HasValue) return;
var (controllerIndex, doorIndex) = doorInfo.Value;
var key = (controllerIndex, doorIndex);
lock (_syncLock)
{
if (!carsInAreas.TryGetValue(key, out var list))
{
list = new List();
carsInAreas[key] = list;
}
if (!list.Contains(car.id))
{
list.Add(car.id);
}
_needOpen[key] = false;
}
}
///
/// 打开门控制器管理界面
///
[MethodMember(Name = "打开管理界面")]
[I18N.DocumentTranslation(Name = "Open Manager", locale = "en")]
public static void OpenViewer()
{
DoorManager.OpenViewer();
}
///
/// 打开门控监控界面
///
[MethodMember(Name = "打开监控界面")]
[I18N.DocumentTranslation(Name = "Open Monitor", locale = "en")]
public static void OpenMonitor()
{
try
{
DoorMonitor.Open();
}
catch (Exception ex)
{
FairyUiHelper.Alert("错误", $"打开门控监控界面失败: {ex.Message}");
}
}
}
}