using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Numerics; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using SimpleLite.RCS; using SimpleLite.RCS.CarTypes; using SimpleLite.CADTools; using SimpleLite.Props; using SimpleLite.UI; using SimpleCore; using SimpleCore.Compiler; using SimpleCore.Library; using SimpleCore.PropType; using SimpleCore.Traffic; using StandardScene.InterLock; using StandardScene.Model; using static StandardScene.Chained.ChainedDeliveryMission; namespace StandardScene { /// /// 插件本地化设置 /// public class CustomOperationsBeforeLoading { public static void Set() { ///死锁提醒 TrafficControl.OnDeadLock = (loopingCar) => { try { var cars = string.Join(",", loopingCar.Select(p => $"{p.id}")); var msg = $"小车:{cars}间发生死锁" + $"请及时人工介入处理!!!!"; MessageBox.Show(msg); } catch { } }; } } public class NoReflectionApi : Attribute { } public class ReflectionApiWithParameter : Attribute { public string name; public string desc; public string Hint; } public static class Commons { public static VehicleStatus GetVehicleStatus(Car car) { if(car is DummyCar && car.lstatus.Contains("上线")) return VehicleStatus.Normal; if (car.lstatus.Contains("正常但未初始化")||car.lstatus.Contains("Normal but not initialized")) return VehicleStatus.NeedInit; if (car.lstatus.Contains("正常") || car.lstatus.Contains("Normal")||car.lstatus.Contains("上线")) return VehicleStatus.Normal; if (car.lstatus.Contains("自动驾驶系统失联") || car.lstatus.Contains("Autonomous driving system lost")) return VehicleStatus.Offline; return VehicleStatus.Unknown; } /// /// 获取车辆状态 /// /// 车辆 /// 状态-键 /// 状态-值 public static string GetCarStatus(Car car, string key) { string value = "0"; if (car == null) return value; if (car.status.enums.TryGetValue(key, out var valueStr)) value = valueStr; return value; } /// /// 添加标签 /// /// /// /// public static void AddOrUpdateTag(T item, string tag, string value) where T : TagSet { if (item.Contains(tag)) item.Remove(tag); item.Add(tag, value); } /// /// 删除标签 /// /// /// /// public static void DeleteTag(T item, string tag) where T : TagSet { if (item.Contains(tag)) { item.Remove(tag); } } /// /// 清空标签 /// /// /// public static void ClearTags(T item) where T : TagSet { item.Clear(); } /// /// 添加或更新字段 /// /// /// /// public static void AddOrUpdateCarField(Car car, string field, string value) { if (car.fields.ContainsKey(field)) { car.fields.Remove(field); car.fields.Add(field, value); } else car.fields.Add(field, value); } /// /// 删除字段 /// /// /// public static void DeleteCarField(Car car, string field) { if (car.fields.ContainsKey(field)) { car.fields.Remove(field); } } /// /// 清空字段 /// /// public static void ClearCarFields(Car car) { car.fields.Clear(); } /// /// 添加或更新site的字段 /// /// /// /// public static void AddOrUpdateSiteField(Site site, string field, string value) { if (site.fields.ContainsKey(field)) { site.fields.Remove(field); site.fields.Add(field, value); } else site.fields.Add(field, value); } /// /// 删除site的字段 /// /// /// public static void DeleteSiteField(Site site, string field) { if (site.fields.ContainsKey(field)) { site.fields.Remove(field); } } /// /// 清空site的字段 /// /// public static void ClearSiteFields(Site site) { site.fields.Clear(); } /// /// 检查给定字符串是否为合法的 HTTP/HTTPS URL(至少包含协议与主机)。 /// /// 待校验的 URL 字符串 /// true 表示 URL 合法 public static bool IsValidHttpUrl(string url) { if (string.IsNullOrWhiteSpace(url)) return false; if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)) return false; if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps) return false; if (string.IsNullOrEmpty(uri.Host)) return false; return true; } public static double CarValue(Car car, string key) { if (car.fields.TryGetValue("electricCurrent", out var strelectricCurrent)) return double.Parse(strelectricCurrent); if (key == "Soc" && (car.name.Contains("模拟") || car.name.ToLower().Contains("sim"))) { if (car.fields.TryGetValue("Soc", out var strSoc)) return double.Parse(strSoc); return 100; } var value = "0"; if (car.status.enums.TryGetValue(key, out var valueStr)) value = valueStr; return double.Parse(value); } /// /// 添加或更新mission的字段 /// /// /// /// public static void AddOrUpdateMissionField(Mission mission, string field, string value) { if (mission.fields.ContainsKey(field)) { mission.fields.Remove(field); mission.fields.Add(field, value); } else mission.fields.Add(field, value); } /// /// 删除mission的字段 /// /// /// /// public static void DeleteMissionField(Mission mission, string field) { if (mission.fields.ContainsKey(field)) mission.fields.Remove(field); } public static List GetOnlineCars() { return SimpleLib.GetAllCars().Where(c => c.GetLastSite() != -1 && Commons.GetVehicleStatus((Car)c)== VehicleStatus.Normal).ToList(); } public static bool IsSceneSiteByCode(int[] siteCodes) { try { foreach (var siteCode in siteCodes) { var site = SimpleLib.GetAllSites().FirstOrDefault(s => s.id == siteCode); if (site == null) return false; } } catch (Exception ex) { Console.WriteLine($@"IsSceneSite 校验报错=>{ex.Message}"); return false; } return true; } public static readonly object PlanSession = new object(); public static int SelectCar(AbstractCar car, bool enableGoingStandbyCar = false, bool needCharge = false, bool checkHoldCar = false) { var carHaveCoordination = (Car)car; var conditions = car.GetLastSite() != -1 && GetVehicleStatus((Car)car)== VehicleStatus.Normal&& !car.tags.Contains("changePriority") && !car.tags.Contains("priority") && !car.tags.Contains("occupied") && !car.tags.Contains("agvOffline") && car.status.pendingLocks.Length == 0 && !car.tags.Contains("deliver") &&//pendingLocks临时增加解决车接多任务问题 (!car.tags.Contains("shouldCharge") || needCharge) && !car.tags.Contains("currentWorkStep") && !car.fields.ContainsKey("StopAccept") && car.tags.Contains("Online"); //巡航任务未完成的车 if (car.name.Contains("模拟")) { conditions = car.GetLastSite() != -1 && (!car.tags.Contains("holdCar") || !checkHoldCar) && !car.tags.Contains("occupied") && car.status.pendingLocks.Length == 0 && !car.tags.Contains("deliver") &&//pendingLocks临时增加解决车接多任务问题 (!car.tags.Contains("shouldCharge") || needCharge) && !car.tags.Contains("currentWorkStep") && !car.fields.ContainsKey("StopAccept"); //巡航任务未完成的车 } //((carHaveCoordination.haveCoordination || car.name.Contains("模拟")) && (!car.tags.Contains("shouldCharge") || needCharge)); if (conditions) return 1; if (enableGoingStandbyCar && car.tags.TryGetValue("dest", out var dst) && int.TryParse(dst, out var dstId) && SimpleLib.GetSite(dstId).fields.ContainsKey(GetGiveWayType((Car)car))) return 1; return -1; } private static string GetGiveWayType(Car car) { if (car.fields.ContainsKey("mover")) return "standbyMover"; if (car.fields.ContainsKey("loader")) return "standbyLoader"; return "giveWay"; } public static bool SiteHaveTask(Site site) { var siteHaveTask = SimpleLib.GetAllCars().ToList().FindAll(o => { if (o.status.pendingLocks.Length > 0) { if (o.status.pendingLocks.Contains(site.id)) { return true; } } if (o.status.holdingLocks.Length > 0) { if (o.status.holdingLocks.Contains(site.id)) { return true; } } return false; }).Count != 0; return siteHaveTask; } public static SegmentPlan GetNearestPlan(Car car, Func test, int srcId = -1, bool disableConflict = false) { var curRouteLength = float.MaxValue; SegmentPlan targetPlan = null; foreach (var site in SimpleLib.GetAllSites()) { if (!test(site)) continue; bool occupied = false; foreach (var cc in SimpleLib.GetAllCars()) { if (cc != car) { if (cc.tags.Contains("dest") && cc.tags.IsEqual("dest", site.id.ToString()) || cc.status.holdingLocks.Contains(site.id)) occupied = true; } } if (occupied) continue; var mPlan = new SegmentPlan { usingCar = car }; if (disableConflict) mPlan.fields["forbid_cross"] = "false"; try { var newRouteLength = mPlan.FindRoute( SimpleLib.GetSite(srcId == -1 ? car.GetLastSite() : srcId), SimpleLib.GetSite(site.id)); if (newRouteLength < curRouteLength) { curRouteLength = newRouteLength; targetPlan = mPlan; } } catch { // ignored } } return targetPlan; } public static void NearestTask(List deliveries, List runningDeliveries = null) { try { var curW = float.MaxValue; var priority = int.MinValue; Delivery priorityNextDelivery = null; Delivery deliveryTask = null; //车不是空闲车,但这个任务结束的时候离另一个将要执行的任务很近。 //(通常来说是同一个工序的,除非单纯地返空托(或路线规划失败,跳别的任务了未按优先级执行)在仓库) // 车空闲 foreach (var car in SimpleLib.GetAllCars().OfType()) //找到那个车 距离待执行任务最近 { DeleteTag(car.tags, "changePriority"); //车的状态是OK的 if (car.GetLastSite() == -1 || car.tags.Contains("agvOffline") || car.tags.Contains("occupied")) continue; //车已经被分配过任务了 if (deliveries.FirstOrDefault(t => t.UsingCar == car) != null) continue; int dst = 0; #region ObsoleteCode //if (car.tags.ContainsKey("occupied")) //说明是正在执行任务的车 //{ // if (car.tags.ContainsKey("dest") // && deliverys.Where(d => d.usingCar != null && d.usingCar == car) == null //并且这个车没有需要等待的任务执行的任务 // //还存在一种情况车被选了但中途有高优先级的任务进来 // ) // { // //这个车正在执行的任务 // dst = int.Parse(car.tags["dest"]); // } // else // { // //这个车已经有需要等待的任务了。 // continue; // } //} //else //车空闲 //{ // dst = car.GetLastSite(); //} //无效 #endregion dst = car.GetLastSite(); if (dst == -1) { //输出日志 变更dst; dst = car.status.holdingLocks.First(); Diagnosis.Post($"调度小车{car.name}:{car.id}的GetLastSite 为 -1 。变更 holdingLocks.First() 为小车初始点{dst}"); } //空闲的车 //如果有多个那个离的最近 foreach (var delivery in deliveries.Where(d => d.UsingCar == null)) { //车是否能接到该任务。 if (car.fields.ContainsKey("group") && !string.IsNullOrEmpty(car.fields["group"]) && !car.fields["group"].Contains(delivery.Group)) continue; var mPlan = new SegmentPlan { usingCar = car }; try { var myW = mPlan.FindRoute( SimpleLib.GetSite(dst), SimpleLib.GetSite(delivery.Src)); //找到最近的, if (myW < curW) { curW = myW; //找到优先级最高的。且距离最近 if (delivery.Priority >= priority) { priorityNextDelivery = delivery; priority = delivery.Priority; Diagnosis.Post($"{priorityNextDelivery.Id}/{priorityNextDelivery.Group}/{priority}", " delivery.priority"); } //找到距离最近的。 Delivery nextDelivery = delivery; if (nextDelivery != priorityNextDelivery) //并且这两个任务不同 优先级高的比较远 { if (runningDeliveries != null) { //优先级高的先执行 Delivery deliveryRunning = null; // runningDeliveries.Where(d => d.group == priorityNextDelivery.group).FirstOrDefault(); //有车正在执行优先级高的任务。有的话就不让车过去 if (deliveryRunning != null) //true { Diagnosis.Post($"{deliveryRunning.Id}/{deliveryRunning.UsingCar?.id}/" + $"{deliveryRunning.Group}/{deliveryRunning.Priority}", "deliveryRunning"); deliveryTask = nextDelivery; } else { deliveryTask = priorityNextDelivery; Diagnosis.Post($"{priorityNextDelivery.Id}/{priorityNextDelivery.UsingCar?.id}/" + $"{priorityNextDelivery.Group}/{priorityNextDelivery.Priority}", "priorityNextDelivery1"); } } else { deliveryTask = priorityNextDelivery; Diagnosis.Post($"{priorityNextDelivery.Id}/{priorityNextDelivery.UsingCar?.id}/" + $"{priorityNextDelivery.Group}/{priorityNextDelivery.Priority}", "priorityNextDelivery2"); } } else { deliveryTask = nextDelivery; Diagnosis.Post($"{nextDelivery.Id}/{nextDelivery.UsingCar?.id}/" + $"{nextDelivery.Group}/{nextDelivery.Priority}", "nextDelivery"); } } } catch (Exception ex) { Console.WriteLine(ex.Message + ex.ToString()); } } if (deliveryTask != null) { deliveryTask.UsingCar = car; deliveryTask.Priority = 50; } } } catch (Exception ex) { Console.WriteLine(ex.Message + ex.ToString()); } } public static async Task GoSite(AbstractCar car, Site targetSite, int step, string action = "/", bool reverse = false) { try { var plan = new SegmentPlan { usingCar = car, fields = { ["reverse"] = reverse.ToString(), ["action"] = action, ["allow_destination_on_route"] = "true" } }; /* if (stations!=null && stations.Count()>=1) { var finishLeftPtlSites = SimpleLib.GetAllSites().Where(site => site.name.Contains("TaskStation")).ToList(); foreach (var site in finishLeftPtlSites) { var stationCode = site.name.Split('-')[1]; if (stations.Contains(stationCode)) { site.fields.Add("askInfons1", "1"); } } }*/ plan.FindRoute(SimpleLib.GetSite(car.GetLastSite()), targetSite); //plan.HintNotEnding(); var program = plan.Compile("move"); car.tags.Add("occupied", $"go{targetSite.id}"); Console.WriteLine($">>Script:{program.script}"); var tsk = program.Queue(); /* if (stations != null && stations.Count() >= 1) { var finishLeftPtlSites = SimpleLib.GetAllSites().Where(site => site.name.Contains("TaskStation")).ToList(); foreach (var site in finishLeftPtlSites) { var stationCode = site.name.Split('-')[1]; if (stations.Contains(stationCode)) { site.fields.Remove("askInfons1"); } } }*/ await tsk; car.tags.Remove("occupied"); } catch (Exception ex) { Console.WriteLine(ex.Message + "重新执行"); Thread.Sleep(3000); } } public static SegmentPlan GenerateEscapePlan(SegmentPlan dstPlan, Func escapeSiteCondition = null) { var curW = float.MaxValue; var car = dstPlan.usingCar; var escapedSites = SimpleLib.GetAllCars().Where(cc => cc.status.escape.Length > 0) .Select(cc => cc.status.escape.Last()).ToHashSet(); SegmentPlan planEsc = null; foreach (var site in SimpleLib.GetAllSites()) { if (site.id == dstPlan.Destination.id || site.id == dstPlan.Source.id) continue; if (escapedSites.Contains(site.id)) continue; if (escapeSiteCondition != null && !escapeSiteCondition(site)) continue; bool occupied = false; foreach (var cc in SimpleLib.GetAllCars()) { if (cc != car) { if (cc.status.holdingLocks.Contains(site.id) || (cc.tags.Contains("dest") && cc.tags["dest"] == site.id.ToString())) occupied = true; } } if (occupied) continue; TryGeneratePlan(dstPlan.usingCar, dstPlan.Destination, site, ref curW, ref planEsc); } return planEsc; } private static void TryGeneratePlan(AbstractCar car, Site srcSite, Site dstSite, ref float curW, ref SegmentPlan generatedPlan) { var mPlan = new SegmentPlan { usingCar = car, findLoop = false, fields = new Dictionary() }; mPlan.fields["forbid_cross"] = "false"; try { var actuallyFindRoute = false; var myw = TryGetWeight(srcSite, dstSite); if (myw < 0) { myw = mPlan.FindRoute(srcSite, dstSite); AddWeight(srcSite, dstSite, myw); actuallyFindRoute = true; } if (myw < curW) { if (!actuallyFindRoute) mPlan.FindRoute(srcSite, dstSite); curW = myw; generatedPlan = mPlan; } } catch { // ignored } } public static Dictionary<(Site, Site), float> weightDictionary = new(); public static float TryGetWeight(Site s1, Site s2) { lock (weightDictionary) { if (weightDictionary.TryGetValue((s1, s2), out var w)) return w; if (weightDictionary.TryGetValue((s2, s1), out var ww)) return ww; } return -1; } public static void AddWeight(Site s1, Site s2, float w) { lock (weightDictionary) weightDictionary[(s1, s2)] = w; } public static SegmentPlan SimpleToNearestPlan(AbstractCar car, Func test, int srcID = -1) { var curw = float.MaxValue; SegmentPlan targetPlan = null; var srcSite = SimpleLib.GetSite(srcID == -1 ? car.GetLastSite() : srcID); foreach (var site in SimpleLib.GetAllSites()) { if (!test(site)) continue; if (site.id == srcSite.id) continue; bool occupied = false; foreach (var cc in SimpleLib.GetAllCars()) { // if (cc != car)//当前 { if (cc.status.holdingLocks.Contains(site.id) || (cc.tags.Contains("dest") && cc.tags["dest"] == site.id.ToString())) occupied = true; } } if (occupied) continue; TryGeneratePlan(car, srcSite, site, ref curw, ref targetPlan); } return targetPlan; } [DllImport("kernel32.dll")] static extern IntPtr GetConsoleWindow(); [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); private static bool ShowConsole = false; public static void ShowConsoleFun() { ShowConsole = !ShowConsole; var handle = GetConsoleWindow(); int n = ShowConsole ? 0 : 5; Console.WriteLine(n); ShowWindow(handle, n); } public static void HideConsoleFun() { var handle = GetConsoleWindow(); ShowWindow(handle, 0); } } }