diff --git a/.gitignore b/.gitignore index 8a30d25..80b3e40 100644 --- a/.gitignore +++ b/.gitignore @@ -396,3 +396,8 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml + +# Trash +.claude +claude.md +todo.md \ No newline at end of file diff --git a/Assembly.version b/Assembly.version index 8829fb5..10bd975 100644 --- a/Assembly.version +++ b/Assembly.version @@ -2,6 +2,6 @@ 2 1 - 7 + 8 \ No newline at end of file diff --git a/README.md b/README.md index 0255838..8a0be5b 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,18 @@ This is a mod for Railroader which is available on Steam. This mod requires Railloader by Zamu. +## Credits & Project History + +This project was originally created and developed by RMROC451. + +I have created fixes and additional features which maybe pulled to main project over time. + +The goal of this repository is to preserve, maintain, and continue improving the mod for the Railroader community while respecting and crediting the original work and vision of RMROC451. + +Special thanks to: +- RMROC451 — original creator of Tweaks and Things +- Zamu + ## Usage 1. Download and install Railloader by Zamu from here: https://railroader.stelltis.ch/ * Verify you have a Mods folder in the root of your railroader directory. If You do NOT have a Mods folder, you didn't complete this step successfully. diff --git a/TweaksAndThings/Patches/AutoEngineerWaypointControls_ConfigureOptionsDropdown_Patch.cs b/TweaksAndThings/Patches/AutoEngineerWaypointControls_ConfigureOptionsDropdown_Patch.cs index 6737d87..1f234d3 100644 --- a/TweaksAndThings/Patches/AutoEngineerWaypointControls_ConfigureOptionsDropdown_Patch.cs +++ b/TweaksAndThings/Patches/AutoEngineerWaypointControls_ConfigureOptionsDropdown_Patch.cs @@ -1,4 +1,5 @@ using Game.Messages; +using Game.Notices; using Game.State; using HarmonyLib; using Model; @@ -41,12 +42,22 @@ internal class LocomotiveControlsUIAdapter_UpdateCarText_Postfix() { try { + if (lastLocoSeenCarId != null && + lastLocoSeenCarId.Equals(TrainController.Shared?.SelectedLocomotive.id) && + watchyWatchy != null) + return; + + if (watchyWatchy != null) + ((MonoBehaviour)__instance).StopCoroutine(watchyWatchy); - if (lastLocoSeenCarId != null && lastLocoSeenCarId.Equals(TrainController.Shared?.SelectedLocomotive.id) && watchyWatchy != null) return; - if (watchyWatchy != null) ((MonoBehaviour)__instance).StopCoroutine(watchyWatchy); watchyWatchy = null; - if (__instance._persistence.Orders.Mode == AutoEngineerMode.Waypoint) watchyWatchy = ((MonoBehaviour)__instance).StartCoroutine(UpdateCogCoroutine(__instance)); + if (__instance._persistence.Orders.Mode == AutoEngineerMode.Waypoint) + { + watchyWatchy = + ((MonoBehaviour)__instance) + .StartCoroutine(UpdateCogCoroutine(__instance)); + } } catch (Exception ex) { @@ -61,11 +72,19 @@ internal class LocomotiveControlsUIAdapter_UpdateCarText_Postfix() while (true) { - if (__instance._persistence.Orders.Mode != AutoEngineerMode.Waypoint || ((AutoEngineerWaypointControls)__instance.aiWaypointControls).Locomotive == null) yield return wait; + if (__instance._persistence.Orders.Mode != AutoEngineerMode.Waypoint || ((AutoEngineerWaypointControls)__instance.aiWaypointControls).Locomotive == null) + { + yield return wait; + continue; + } PrepLocoUsage((AutoEngineerWaypointControls)__instance.aiWaypointControls, out BaseLocomotive selectedLoco, out int numberOfCars); HashSet destinations = []; - if (!tweaksAndThings.IsEnabled() || !ShouldRecalc(__instance, selectedLoco, out destinations)) yield return wait; + if (!tweaksAndThings.IsEnabled() || tweaksAndThings.DisableWaypointControls() || !ShouldRecalc(__instance, selectedLoco, out destinations)) + { + yield return wait; + continue; + } timetableSaveTime = TimetableController.Shared.CurrentDocument.Modified; lastSeenIntegrationSetCount = selectedLoco.set.NumberOfCars; @@ -132,7 +151,18 @@ internal class LocomotiveControlsUIAdapter_UpdateCarText_Postfix() private static OptionsDropdownConfiguration WireUpJumpTosToSettingMenu(AutoEngineerWaypointControls __instance, BaseLocomotive selectedLoco, List rowDatas, Action func, int origCount, int maxRowOrig, AutoEngineerOrdersHelper aeoh, ref List<(string destinationId, string destination, float? distance, float sortDistance, Location? location)> jumpTos) { OptionsDropdownConfiguration __result; - jumpTos = jumpTos?.OrderBy(c => c.sortDistance)?.ToList() ?? default; + TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase.Shared; + + // Check if waypoint controls are disabled + if (tweaksAndThings.DisableWaypointControls()) + { + jumpTos = new List<(string, string, float?, float, Location?)>(); + } + else + { + jumpTos = jumpTos?.OrderBy(c => c.sortDistance)?.ToList() ?? default; + } + var localJumpTos = jumpTos.ToList(); var safetyFirst = AutoEngineerPlanner_HandleCommand_Patch.SafetyFirstGoverningApplies(selectedLoco) && jumpTos.Any(); @@ -364,6 +394,12 @@ internal class LocomotiveControlsUIAdapter_UpdateOptionsDropdown_Prefix { static bool Prefix(LocomotiveControlsUIAdapter __instance) { - return false; + TweaksAndThingsPlugin tweaksAndThings = + SingletonPluginBase.Shared; + + if (!tweaksAndThings.IsEnabled()) + return true; + + return tweaksAndThings.DisableWaypointControls(); } -} +} \ No newline at end of file diff --git a/TweaksAndThings/Patches/CarInspector_PopulateEquipmentPanel_Patch.cs b/TweaksAndThings/Patches/CarInspector_PopulateEquipmentPanel_Patch.cs new file mode 100644 index 0000000..8b5bd39 --- /dev/null +++ b/TweaksAndThings/Patches/CarInspector_PopulateEquipmentPanel_Patch.cs @@ -0,0 +1,75 @@ +using Game.Messages; +using Game.Notices; +using Game.State; +using HarmonyLib; +using Model; +using Model.Ops; +using Network; +using Railloader; +using System; +using System.Linq; +using UI.Builder; +using UI.CarInspector; +using Core; + +namespace RMROC451.TweaksAndThings.Patches; + +[HarmonyPatch(typeof(CarInspector))] +[HarmonyPatch(nameof(CarInspector.PopulateEquipmentPanel))] +[HarmonyPatchCategory("RMROC451TweaksAndThings")] +internal static class CarInspector_PopulateEquipmentPanel_Patch +{ + [HarmonyPrefix] + private static void Prefix(CarInspector __instance, UIPanelBuilder builder) + { + TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase.Shared; + if (!tweaksAndThings.IsEnabled()) return; + + builder.HStack(hstack => + { + hstack.AddButtonCompact("Copy Repair Dest", delegate + { + Car selectedCar = __instance._car; + + bool hasDestination = selectedCar.TryGetOverrideDestination( + OverrideDestination.Repair, + OpsController.Shared, + out (OpsCarPosition, string)? destination); + + int updatedCount = selectedCar + .EnumerateCoupled() + .Where(car => car.id != selectedCar.id) + .Select(car => + { + if (hasDestination) + { + car.SetOverrideDestination( + OverrideDestination.Repair, + destination); + } + else + { + car.SetOverrideDestination( + OverrideDestination.Repair, + null); + } + + return 1; + }) + .Sum(); + + Multiplayer.SendError( + StateManager.Shared.PlayersManager.LocalPlayer, + hasDestination + ? $"Copied repair destination to {updatedCount} connected {"car".Pluralize(updatedCount == 1 ? 1 : 0)}." + : $"Cleared repair destination from {updatedCount} connected {"car".Pluralize(updatedCount == 1 ? 1 : 0)}.", + default); + + hstack.Rebuild(); + }) + .Tooltip( + "Copy Repair Destination", + "Copies or clears this car's repair destination across all connected cars in the consist."); + }); + } +} \ No newline at end of file diff --git a/TweaksAndThings/Settings/Settings.cs b/TweaksAndThings/Settings/Settings.cs index c8e93af..1e9b659 100644 --- a/TweaksAndThings/Settings/Settings.cs +++ b/TweaksAndThings/Settings/Settings.cs @@ -31,7 +31,8 @@ public class Settings bool safetyFirstClientEnforce, CrewHourLoadMethod loadCrewHoursMethod, float cabeeseSearchRadiusFtInMeters, - bool trainBrakeDisplayShowsColorsInCalloutMode + bool trainBrakeDisplayShowsColorsInCalloutMode, + bool disableWaypointControls ) { WebhookSettingsList = webhookSettingsList; @@ -47,6 +48,7 @@ public class Settings LoadCrewHoursMethod = loadCrewHoursMethod; CabeeseSearchRadiusFtInMeters = cabeeseSearchRadiusFtInMeters; TrainBrakeDisplayShowsColorsInCalloutMode = trainBrakeDisplayShowsColorsInCalloutMode; + DisableWaypointControls = disableWaypointControls; } public readonly UIState _selectedTabState = new UIState(null); @@ -63,6 +65,7 @@ public class Settings public CrewHourLoadMethod LoadCrewHoursMethod; public float CabeeseSearchRadiusFtInMeters; public bool TrainBrakeDisplayShowsColorsInCalloutMode; + public bool DisableWaypointControls; internal void AddAnotherRow() { @@ -145,5 +148,7 @@ public static class SettingsExtensions (input?.settings?.LoadCrewHoursMethod ?? CrewHourLoadMethod.Tracks) == CrewHourLoadMethod.Daily; public static bool TrainBrakeDisplayShowsColorsInCalloutMode(this TweaksAndThingsPlugin input) => input?.settings?.TrainBrakeDisplayShowsColorsInCalloutMode ?? false; + public static bool DisableWaypointControls(this TweaksAndThingsPlugin input) => + input?.settings?.DisableWaypointControls ?? false; } \ No newline at end of file diff --git a/TweaksAndThings/TweaksAndThingsPlugin.cs b/TweaksAndThings/TweaksAndThingsPlugin.cs index e7382f5..f4da1c3 100644 --- a/TweaksAndThings/TweaksAndThingsPlugin.cs +++ b/TweaksAndThings/TweaksAndThingsPlugin.cs @@ -262,6 +262,18 @@ AutoHotboxSpotter Update: decrease the random wait from 30 - 300 seconds to 15 - } ).Tooltip("Train Brake Color Mode", $@"When enabled/checked and car tag callout mode is enabled (showing car tags hovering over them), the train brake display of the selected locomotive will change the cars/engines to their destination area's color to help you visualize sets of cars at a glance."); + builder.Spacer(spacing); + builder.AddFieldToggle( + "Disable Waypoint Controls", + () => settings?.DisableWaypointControls ?? false, + delegate (bool enabled) + { + if (settings == null) settings = new(); + settings.DisableWaypointControls = enabled; + builder.Rebuild(); + } + ).Tooltip("Disable Waypoint Controls", @"When enabled, removes the waypoint set/jump options from the engine control menu. This disables the option to jump to waypoints or set waypoints based on consist car destinations, allowing only default engine controls."); + builder.Spacer(spacing); EngineRosterShowsFuelStatusUISection(builder); }