From 2ed33465d96e5cf352bf0d6d921e6c1c9f721e80 Mon Sep 17 00:00:00 2001 From: Ryan Mroczenski Date: Fri, 5 Jul 2024 20:21:41 -0500 Subject: [PATCH] reduce cyclomatic complexity of the cabeese hunting algorithm, and fix issue with webhook settings adding an empty row each time settings screen opens. --- TweaksAndThings/Extensions/Car_Extensions.cs | 59 +++++++++++-------- .../CarInspector_PopulateCarPanel_Patch.cs | 10 +++- TweaksAndThings/Settings/Settings.cs | 17 +++++- TweaksAndThings/TweaksAndThingsPlugin.cs | 4 ++ 4 files changed, 62 insertions(+), 28 deletions(-) diff --git a/TweaksAndThings/Extensions/Car_Extensions.cs b/TweaksAndThings/Extensions/Car_Extensions.cs index e5db62e..f861712 100644 --- a/TweaksAndThings/Extensions/Car_Extensions.cs +++ b/TweaksAndThings/Extensions/Car_Extensions.cs @@ -58,10 +58,10 @@ public static class Car_Extensions public static bool CabooseInConsist(this IEnumerable input) => input.FirstOrDefault(c => c.IsCaboose()); - public static Car? CabooseWithSufficientCrewHours(this Car car, float timeNeeded, bool decrement = false) + public static Car? CabooseWithSufficientCrewHours(this Car car, float timeNeeded, HashSet carIdsCheckedAlready, bool decrement = false) { Car? output = null; - if (!car.IsCaboose()) return null; + if (carIdsCheckedAlready.Contains(car.id) || !car.IsCaboose()) return null; List loadSlots = car.Definition.LoadSlots; for (int i = 0; i < loadSlots.Count; i++) @@ -78,33 +78,44 @@ public static class Car_Extensions return output; } - public static Car? HuntingForCabeeseNearCar(this Car car, float timeNeeded, TrainController tc, bool decrement = false) + public static Car? HuntingForCabeeseNearCar(this Car car, float timeNeeded, TrainController tc, HashSet carIdsCheckedAlready, bool decrement = false) + { + List<(string carId, float distance)> source = + CarsNearCurrentCar(car, timeNeeded, tc, carIdsCheckedAlready, decrement); + + Car output = FindNearestCabooseFromNearbyCars(tc, source); + if (output != null) output.CabooseWithSufficientCrewHours(timeNeeded, carIdsCheckedAlready, decrement); + + return output; + } + + private static Car FindNearestCabooseFromNearbyCars(TrainController tc, List<(string carId, float distance)> source) => + ( + from t in source + where t.distance < 21f //todo: add setting slider for catchment + orderby t.distance ascending + select tc.CarForId(t.carId) + ).FirstOrDefault(); + + private static List<(string carId, float distance)> CarsNearCurrentCar(Car car, float timeNeeded, TrainController tc, HashSet carIdsCheckedAlready, bool decrement) { Vector3 position = car.GetMotionSnapshot().Position; Vector3 center = WorldTransformer.WorldToGame(position); Rect rect = new Rect(new Vector2(center.x - 30f, center.z - 30f), Vector2.one * 30f * 2f); var cars = tc.CarIdsInRect(rect); Log.Information($"{nameof(HuntingForCabeeseNearCar)} => {cars.Count()}"); - bool decrementedAlready = false; - List<(string carId, float distance)> source = cars.Select(carId => - { - Car car = tc.CarForId(carId); - if (car == null || !car.CabooseWithSufficientCrewHours(timeNeeded, decrement && !decrementedAlready)) - { - return (carId: carId, distance: 1000f); - } - decrementedAlready = true; - Vector3 a = WorldTransformer.WorldToGame(car.GetMotionSnapshot().Position); - return (carId: carId, distance: Vector3.Distance(a, center)); - }).ToList(); - - Car? output = - (from t in source - where t.distance < 21f - orderby t.distance ascending - select tc.CarForId(t.carId) - ).FirstOrDefault(); - - return output; + List<(string carId, float distance)> source = + cars + .Select(carId => + { + Car car = tc.CarForId(carId); + if (car == null || !car.CabooseWithSufficientCrewHours(timeNeeded, carIdsCheckedAlready)) + { + return (carId: carId, distance: 1000f); + } + Vector3 a = WorldTransformer.WorldToGame(car.GetMotionSnapshot().Position); + return (carId: carId, distance: Vector3.Distance(a, center)); + }).ToList(); + return source; } } diff --git a/TweaksAndThings/Patches/CarInspector_PopulateCarPanel_Patch.cs b/TweaksAndThings/Patches/CarInspector_PopulateCarPanel_Patch.cs index b88547b..e878e1b 100644 --- a/TweaksAndThings/Patches/CarInspector_PopulateCarPanel_Patch.cs +++ b/TweaksAndThings/Patches/CarInspector_PopulateCarPanel_Patch.cs @@ -195,20 +195,24 @@ internal class CarInspector_PopulateCarPanel_Patch public static Car? NearbyCabooseWithAvailableCrew(Car car, float timeNeeded, bool decrement = false) { + HashSet carIdsCheckedAlready = new(); + //check current car. - Car? output = car.CabooseWithSufficientCrewHours(timeNeeded, decrement); + Car? output = car.CabooseWithSufficientCrewHours(timeNeeded, carIdsCheckedAlready, decrement); if (output != null) return output; //short out if we are good + carIdsCheckedAlready.Add(car.id); //check consist, for cabeese IEnumerable consist = car.EnumerateCoupled(LogicalEnd.A); - output = consist.FirstOrDefault(c => c.CabooseWithSufficientCrewHours(timeNeeded, decrement)); + output = consist.FirstOrDefault(c => c.CabooseWithSufficientCrewHours(timeNeeded, carIdsCheckedAlready, decrement)); if (output != null) return output; //short out if we are good + carIdsCheckedAlready.UnionWith(consist.Select(c => c.id)); //then check near consist cars for cabeese TrainController tc = UnityEngine.Object.FindObjectOfType(); foreach (var c in consist) { - output = c.HuntingForCabeeseNearCar(timeNeeded, tc, decrement); + output = c.HuntingForCabeeseNearCar(timeNeeded, tc, carIdsCheckedAlready, decrement); if (output != null) return output; //short out if we are good } diff --git a/TweaksAndThings/Settings/Settings.cs b/TweaksAndThings/Settings/Settings.cs index fbf5e5c..ff5ca35 100644 --- a/TweaksAndThings/Settings/Settings.cs +++ b/TweaksAndThings/Settings/Settings.cs @@ -34,7 +34,7 @@ public class Settings internal void AddAnotherRow() { - WebhookSettingsList = !WebhookSettingsList?.Any() ?? false ? new[] { new WebhookSettings() }.ToList() : new List(); + WebhookSettingsList ??= new[] { new WebhookSettings() }.ToList(); if (!string.IsNullOrEmpty(WebhookSettingsList.OrderByDescending(wsl => wsl.WebhookUrl).Last().WebhookUrl)) { WebhookSettingsList.Add(new()); @@ -76,4 +76,19 @@ public class RosterFuelColumnSettings public bool EngineRosterShowsFuelStatusAlways; public EngineRosterFuelDisplayColumn EngineRosterFuelStatusColumn; +} + +public static class SettingsExtensions +{ + public static List SanitizeEmptySettings(this IEnumerable? settings) + { + List output = + settings?.Where(s => !string.IsNullOrEmpty(s.WebhookUrl))?.ToList() ?? + new(); + + output.Add(new()); + + return output; + } + } \ No newline at end of file diff --git a/TweaksAndThings/TweaksAndThingsPlugin.cs b/TweaksAndThings/TweaksAndThingsPlugin.cs index 127dc94..d1e0380 100644 --- a/TweaksAndThings/TweaksAndThingsPlugin.cs +++ b/TweaksAndThings/TweaksAndThingsPlugin.cs @@ -78,6 +78,10 @@ public class TweaksAndThingsPlugin : SingletonPluginBase, if (!settings?.WebhookSettingsList?.Any() ?? true) settings.WebhookSettingsList = new[] { new WebhookSettings() }.ToList(); if (settings?.EngineRosterFuelColumnSettings == null) settings.EngineRosterFuelColumnSettings = new(); + + settings.WebhookSettingsList = + settings?.WebhookSettingsList.SanitizeEmptySettings(); + //WebhookUISection(ref builder); //builder.AddExpandingVerticalSpacer(); WebhooksListUISection(ref builder);