From d0e2c3f99eeb6588dfa30e09fbaf8287320e2d3f Mon Sep 17 00:00:00 2001 From: RMROC451 Date: Thu, 20 Jun 2024 17:41:50 -0500 Subject: [PATCH] #12 add configurable column for fuel status tracking in engine roster --- Directory.Build.targets | 2 +- .../Enums/EngineRosterFuelDisplayColumn.cs | 9 ++ TweaksAndThings/Patches/Car_SetIdent_Patch.cs | 122 ++++++++++++++++++ .../Patches/ExpandedConsole_Patch.cs | 7 +- .../RMROC451.TweaksAndThings.csproj | 1 + TweaksAndThings/Settings.cs | 58 --------- TweaksAndThings/Settings/Settings.cs | 76 +++++++++++ TweaksAndThings/TweaksAndThings.cs | 52 +++++++- 8 files changed, 257 insertions(+), 70 deletions(-) create mode 100644 TweaksAndThings/Enums/EngineRosterFuelDisplayColumn.cs create mode 100644 TweaksAndThings/Patches/Car_SetIdent_Patch.cs delete mode 100644 TweaksAndThings/Settings.cs create mode 100644 TweaksAndThings/Settings/Settings.cs diff --git a/Directory.Build.targets b/Directory.Build.targets index 96fab01..ce06d73 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -12,7 +12,7 @@ 0 1 - 4 + 5 $(MajorVersion).$(MinorVersion).$(PatchVersion) $(AssemblyVersion) $(AssemblyVersion) diff --git a/TweaksAndThings/Enums/EngineRosterFuelDisplayColumn.cs b/TweaksAndThings/Enums/EngineRosterFuelDisplayColumn.cs new file mode 100644 index 0000000..df06b96 --- /dev/null +++ b/TweaksAndThings/Enums/EngineRosterFuelDisplayColumn.cs @@ -0,0 +1,9 @@ +namespace TweaksAndThings.Enums; + +public enum EngineRosterFuelDisplayColumn +{ + None, + Engine, + Crew, + Status +} diff --git a/TweaksAndThings/Patches/Car_SetIdent_Patch.cs b/TweaksAndThings/Patches/Car_SetIdent_Patch.cs new file mode 100644 index 0000000..2d5944b --- /dev/null +++ b/TweaksAndThings/Patches/Car_SetIdent_Patch.cs @@ -0,0 +1,122 @@ +using HarmonyLib; +using Model; +using Model.Definition; +using Model.Definition.Data; +using Model.OpsNew; +using Model.Physics; +using Railloader; +using RMROC451.TweaksAndThings.Settings; +using Serilog; +using System; +using System.Collections.Generic; +using System.Linq; +using TMPro; +using TweaksAndThings.Enums; +using UI; +using UI.Builder; +using UI.EngineRoster; +using UI.Tooltips; +using UnityEngine; +using static Model.Car; + + +namespace TweaksAndThings.Patches; + +[HarmonyPatch(typeof(EngineRosterRow))] +[HarmonyPatch(nameof(EngineRosterRow.Refresh))] +[HarmonyPatchCategory("RMROC451TweaksAndThings")] +public class EngineRosterRow_Refresh_Patch +{ + public static void Postfix(EngineRosterRow __instance) + { + TweaksAndThings? tweaksAndThings = SingletonPluginBase.Shared; + RosterFuelColumnSettings? rosterFuelColumnSettings = tweaksAndThings?.settings?.EngineRosterFuelColumnSettings; + + if (tweaksAndThings == null || + rosterFuelColumnSettings == null || + !tweaksAndThings.IsEnabled || + rosterFuelColumnSettings.EngineRosterFuelStatusColumn == EngineRosterFuelDisplayColumn.None || (!GameInput.IsAltDown && !rosterFuelColumnSettings.EngineRosterShowsFuelStatusAlways)) + { + return; + } + + try + { + string fuelInfoText = string.Empty; + string fuelInfoTooltip = string.Empty; + Car engineOrTender = __instance._engine; + List loadSlots = __instance._engine.Definition.LoadSlots; + if (!loadSlots.Any()) + { + engineOrTender = DetermineFuelCar(__instance._engine); + loadSlots = engineOrTender != null ? engineOrTender.Definition.LoadSlots : Enumerable.Empty().ToList(); + } + + var offender = loadSlots.OrderBy(ls => (engineOrTender.GetLoadInfo(ls.RequiredLoadIdentifier, out int slotIndex)?.Quantity ?? 0) / loadSlots[slotIndex].MaximumCapacity).FirstOrDefault().RequiredLoadIdentifier; + + for (int i = 0; i < loadSlots.Count; i++) + { + CarLoadInfo? loadInfo = engineOrTender.GetLoadInfo(i); + if (loadInfo.HasValue) + { + CarLoadInfo valueOrDefault = loadInfo.GetValueOrDefault(); + var fuelLevel = FuelLevel(valueOrDefault.Quantity, loadSlots[i].MaximumCapacity); + fuelInfoText += loadSlots[i].RequiredLoadIdentifier == offender ? fuelLevel + " " : string.Empty; + //fuelInfoText += TextSprites.PiePercent(valueOrDefault.Quantity, loadSlots[i].MaximumCapacity) + " "; + fuelInfoTooltip += $"{TextSprites.PiePercent(valueOrDefault.Quantity, loadSlots[i].MaximumCapacity)} {valueOrDefault.LoadString(CarPrototypeLibrary.instance.LoadForId(valueOrDefault.LoadId))}\n"; + } + } + + switch (rosterFuelColumnSettings.EngineRosterFuelStatusColumn) + { + case EngineRosterFuelDisplayColumn.Engine: + SetLabelAndTooltip(ref __instance.nameLabel, ref __instance.nameTooltip, fuelInfoText, fuelInfoTooltip); + break; + case EngineRosterFuelDisplayColumn.Crew: + SetLabelAndTooltip(ref __instance.crewLabel, ref __instance.crewTooltip, fuelInfoText, fuelInfoTooltip); + break; + case EngineRosterFuelDisplayColumn.Status: + SetLabelAndTooltip(ref __instance.infoLabel, ref __instance.infoTooltip, fuelInfoText, fuelInfoTooltip); + break; + default: + break; + } + + } catch (Exception ex) + { + rosterFuelColumnSettings.EngineRosterFuelStatusColumn = EngineRosterFuelDisplayColumn.None; + Log.Error(ex, "Error Detecting fuel status for engine roster"); + } + } + + private static void SetLabelAndTooltip(ref TMP_Text label, ref UITooltipProvider tooltip, string fuelInfoText, string fuelInfoTooltip) + { + label.text = $" {fuelInfoText} {label.text}"; + tooltip.TooltipInfo = new TooltipInfo(tooltip.tooltipTitle, fuelInfoTooltip); + } + + public static string FuelLevel(float quantity, float capacity) + { + float num = capacity <= 0f ? 0 : Mathf.Clamp(quantity / capacity * 100, 0, 100); + + return $"{Mathf.FloorToInt(num):D2}%"; + } + + public static Car DetermineFuelCar(BaseLocomotive engine) + { + Car car; + if (engine is SteamLocomotive steamLocomotive && new Func(steamLocomotive.FuelCar) != null) + { + car = steamLocomotive.FuelCar(); + } + else + { + if (!(engine is DieselLocomotive)) + { + throw new InvalidOperationException($"Unable to detect locomotive fuel source for {engine}"); + } + car = engine; + } + return car; + } +} diff --git a/TweaksAndThings/Patches/ExpandedConsole_Patch.cs b/TweaksAndThings/Patches/ExpandedConsole_Patch.cs index 98fb6c4..8579666 100644 --- a/TweaksAndThings/Patches/ExpandedConsole_Patch.cs +++ b/TweaksAndThings/Patches/ExpandedConsole_Patch.cs @@ -4,6 +4,7 @@ using HarmonyLib; using Helpers; using Newtonsoft.Json; using Railloader; +using RMROC451.TweaksAndThings.Settings; using Serilog; using System; using System.Collections.Generic; @@ -35,9 +36,7 @@ public class ExpandedConsole_Add_Patch TweaksAndThings tweaksAndThings = SingletonPluginBase.Shared; StateManager shared = StateManager.Shared; GameStorage gameStorage = shared.Storage; - WebhookSettings settings = tweaksAndThings.settings.WebhookSettingsList.FirstOrDefault(ws => ws.RailroadMark == gameStorage.RailroadMark); - - Log.Information(entry.Text); + WebhookSettings settings = tweaksAndThings?.settings?.WebhookSettingsList?.FirstOrDefault(ws => ws.RailroadMark == gameStorage.RailroadMark); if ( settings != null && @@ -50,7 +49,6 @@ public class ExpandedConsole_Add_Patch var carId = t.IsMatch(entry.Text) ? Regex.Match(entry.Text, "car:(.*?)\"").Groups[1].Captures[0].ToString() : string.Empty; Model.Car? car = TrainController.Shared.CarForString(carId); - Log.Information($"|{carId}| {car?.IsLocomotive}"); bool engineInMessage = car?.IsLocomotive ?? false; var image = engineInMessage ? new @@ -91,7 +89,6 @@ public class ExpandedConsole_Add_Patch } }; string EndPoint = settings.WebhookUrl; - Log.Information(JsonConvert.SerializeObject(SuccessWebHook)); var content = new StringContent(JsonConvert.SerializeObject(SuccessWebHook), Encoding.UTF8, "application/json"); diff --git a/TweaksAndThings/RMROC451.TweaksAndThings.csproj b/TweaksAndThings/RMROC451.TweaksAndThings.csproj index af81fa5..ccf421d 100644 --- a/TweaksAndThings/RMROC451.TweaksAndThings.csproj +++ b/TweaksAndThings/RMROC451.TweaksAndThings.csproj @@ -11,6 +11,7 @@ + diff --git a/TweaksAndThings/Settings.cs b/TweaksAndThings/Settings.cs deleted file mode 100644 index fc92a17..0000000 --- a/TweaksAndThings/Settings.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Newtonsoft.Json; -using System.IO; -using System.Runtime; -using System; -using Serilog; -using System.Collections.Generic; -using System.Linq; - -namespace TweaksAndThings; - -public class Settings -{ - - public Settings() - { - WebhookSettingsList = new[] { new WebhookSettings() }.ToList(); - } - - public Settings( - List webhookSettingsList, - bool handBrakeAndAirTagModifiers - ) - { - this.WebhookSettingsList = webhookSettingsList; - this.HandBrakeAndAirTagModifiers = handBrakeAndAirTagModifiers; - } - - public List WebhookSettingsList; - public bool HandBrakeAndAirTagModifiers; - - internal void AddAnotherRow() - { - if (!string.IsNullOrEmpty(WebhookSettingsList.Last().WebhookUrl)) - { - WebhookSettingsList.Add(new()); - Log.Information($"Adding another {nameof(WebhookSettings)} list entry, last one was filled in"); - } - } -} - -public class WebhookSettings -{ - public WebhookSettings() { } - public WebhookSettings( - bool webhookEnabled, - string railroadMark, - string webhookUrl - ) - { - this.WebhookEnabled = webhookEnabled; - this.RailroadMark = railroadMark; - this.WebhookUrl = webhookUrl; - } - - public bool WebhookEnabled = false; - public string RailroadMark = string.Empty; - public string WebhookUrl = string.Empty; -} \ No newline at end of file diff --git a/TweaksAndThings/Settings/Settings.cs b/TweaksAndThings/Settings/Settings.cs new file mode 100644 index 0000000..2e7ae63 --- /dev/null +++ b/TweaksAndThings/Settings/Settings.cs @@ -0,0 +1,76 @@ +using Serilog; +using System.Collections.Generic; +using System.Linq; +using TweaksAndThings.Enums; + +namespace RMROC451.TweaksAndThings.Settings; + +public class Settings +{ + + public Settings() + { + WebhookSettingsList = new[] { new WebhookSettings() }.ToList(); + EngineRosterFuelColumnSettings = new(); + } + + public Settings( + List webhookSettingsList, + bool handBrakeAndAirTagModifiers, + RosterFuelColumnSettings engineRosterFuelColumnSettings + ) + { + WebhookSettingsList = webhookSettingsList; + HandBrakeAndAirTagModifiers = handBrakeAndAirTagModifiers; + EngineRosterFuelColumnSettings = engineRosterFuelColumnSettings; + } + + public List? WebhookSettingsList; + public bool HandBrakeAndAirTagModifiers; + public RosterFuelColumnSettings? EngineRosterFuelColumnSettings; + + internal void AddAnotherRow() + { + WebhookSettingsList = !WebhookSettingsList?.Any() ?? false ? new[] { new WebhookSettings() }.ToList() : new List(); + if (!string.IsNullOrEmpty(WebhookSettingsList.OrderByDescending(wsl => wsl.WebhookUrl).Last().WebhookUrl)) + { + WebhookSettingsList.Add(new()); + Log.Information($"Adding another {nameof(WebhookSettings)} list entry, last one was filled in"); + } + } +} + +public class WebhookSettings +{ + public WebhookSettings() { } + public WebhookSettings( + bool webhookEnabled, + string railroadMark, + string webhookUrl + ) + { + WebhookEnabled = webhookEnabled; + RailroadMark = railroadMark; + WebhookUrl = webhookUrl; + } + + public bool WebhookEnabled = false; + public string RailroadMark = string.Empty; + public string WebhookUrl = string.Empty; +} + +public class RosterFuelColumnSettings +{ + public RosterFuelColumnSettings() { } + public RosterFuelColumnSettings( + bool engineRosterShowsFuelStatusAlways, + EngineRosterFuelDisplayColumn engineRosterFuelStatusColumn + ) + { + this.EngineRosterShowsFuelStatusAlways = engineRosterShowsFuelStatusAlways; + this.EngineRosterFuelStatusColumn = engineRosterFuelStatusColumn; + } + + public bool EngineRosterShowsFuelStatusAlways; + public EngineRosterFuelDisplayColumn EngineRosterFuelStatusColumn; +} \ No newline at end of file diff --git a/TweaksAndThings/TweaksAndThings.cs b/TweaksAndThings/TweaksAndThings.cs index c7800d1..6e7fea5 100644 --- a/TweaksAndThings/TweaksAndThings.cs +++ b/TweaksAndThings/TweaksAndThings.cs @@ -2,10 +2,14 @@ using Game.State; using HarmonyLib; using Railloader; +using RMROC451.TweaksAndThings.Settings; using Serilog; +using System; using System.Linq; using System.Net.Http; +using TweaksAndThings.Enums; using UI.Builder; +using static Model.Car; namespace TweaksAndThings { @@ -43,12 +47,6 @@ namespace TweaksAndThings //moddingContext.RegisterConsoleCommand(new EchoCommand()); settings = moddingContext.LoadSettingsData(self.Id); - if (!settings?.WebhookSettingsList?.Any() ?? true) - { - if (settings == null) settings = new(); - settings.WebhookSettingsList = new[] { new WebhookSettings() }.ToList(); - this.moddingContext.SaveSettingsData(this.modDefinition.Id, settings ?? new()); - } } public override void OnEnable() @@ -73,11 +71,53 @@ namespace TweaksAndThings public void ModTabDidOpen(UIPanelBuilder builder) { logger.Information("Daytime!"); + + if (!settings?.WebhookSettingsList?.Any() ?? true) + { + if (settings == null) settings = new(); + settings.WebhookSettingsList = new[] { new WebhookSettings() }.ToList(); + settings.EngineRosterFuelColumnSettings = new(); + } + //WebhookUISection(ref builder); //builder.AddExpandingVerticalSpacer(); WebhooksListUISection(ref builder); builder.AddExpandingVerticalSpacer(); HandbrakesAndAnglecocksUISection(ref builder); + builder.AddExpandingVerticalSpacer(); + EnginRosterShowsFuelStatusUISection(ref builder); + } + + private void EnginRosterShowsFuelStatusUISection(ref UIPanelBuilder builder) + { + var columns = Enum.GetValues(typeof(EngineRosterFuelDisplayColumn)).Cast().Select(i => i.ToString()).ToList(); + builder.AddSection("Fuel Display in Engine Roster", delegate (UIPanelBuilder builder) + { + builder.AddField( + "Enable", + builder.AddDropdown(columns, (int)(settings?.EngineRosterFuelColumnSettings?.EngineRosterFuelStatusColumn ?? EngineRosterFuelDisplayColumn.None), + delegate (int column) + { + if (settings == null) settings = new() { WebhookSettingsList = new[] { new WebhookSettings() }.ToList(), EngineRosterFuelColumnSettings = new() }; + settings.EngineRosterFuelColumnSettings.EngineRosterFuelStatusColumn = (EngineRosterFuelDisplayColumn)column; + builder.Rebuild(); + } + ) + ).Tooltip("Enable Fuel Display in Engine Roster", $"Will add remaing fuel indication to Engine Roster (with details in roster row tooltip), Examples : {string.Join(" ", Enumerable.Range(0,4).Select(i => TextSprites.PiePercent(i, 4)))}"); + + builder.AddField( + "Always Visible?", + builder.AddToggle( + () => settings?.EngineRosterFuelColumnSettings?.EngineRosterShowsFuelStatusAlways ?? false, + delegate (bool enabled) + { + if (settings == null) settings = new() { WebhookSettingsList = new[] { new WebhookSettings() }.ToList(), EngineRosterFuelColumnSettings = new() }; + settings.EngineRosterFuelColumnSettings.EngineRosterShowsFuelStatusAlways = enabled; + builder.Rebuild(); + } + ) + ).Tooltip("Fuel Display in Engine Roster Always Visible", $"Always displayed, if you want it hidden and only shown when you care to see, uncheck this, and then you can press ALT for it to populate on the next UI refresh cycle."); + }); } private void HandbrakesAndAnglecocksUISection(ref UIPanelBuilder builder)