diff --git a/Assembly.version b/Assembly.version
index 45f4823..a8136ea 100644
--- a/Assembly.version
+++ b/Assembly.version
@@ -1,7 +1,7 @@
2
- 0
- 1
+ 1
+ 0
\ No newline at end of file
diff --git a/TweaksAndThings/Commands/CrewUpdateCommand.cs b/TweaksAndThings/Commands/CrewUpdateCommand.cs
index a949ac9..f2cffdc 100644
--- a/TweaksAndThings/Commands/CrewUpdateCommand.cs
+++ b/TweaksAndThings/Commands/CrewUpdateCommand.cs
@@ -46,9 +46,9 @@ public class EchoCommand : IConsoleCommand
EntityReference loco = new EntityReference(EntityType.Car, car.id);
if (comps[2] == "+") message = new Hyperlink(entityReference.URI(), string.Format(message, OpsController.Shared.ClosestArea(car)?.name ?? "???"));
- car.PostNotice(nameof(EchoCommand), $"{message} :{StateManager.Shared._playersManager.LocalPlayer}");
+ if (StateManager.IsHost) car.PostNotice(nameof(EchoCommand), $"{message} :{StateManager.Shared._playersManager.LocalPlayer}");
ExpandedConsole_Add_Patch.SendMs(null, $"{Hyperlink.To(car)} {message}");
- Multiplayer.Broadcast($"{StateManager.Shared._playersManager.LocalPlayer} {Hyperlink.To(car)}: \"{message}\"");
+ if (!StateManager.IsHost) Multiplayer.Broadcast($"{StateManager.Shared._playersManager.LocalPlayer} {Hyperlink.To(car)}: \"{message}\"");
return string.Empty;
}
diff --git a/TweaksAndThings/Definition.json b/TweaksAndThings/Definition.json
index a29b876..31fd06d 100644
--- a/TweaksAndThings/Definition.json
+++ b/TweaksAndThings/Definition.json
@@ -21,6 +21,7 @@
"mixintos": {
"container:ne-caboose01": "file(mroc-cabeese.json)",
"container:ne-caboose02": "file(mroc-cabeese.json)",
- "container:ne-caboose03": "file(mroc-cabeese.json)"
+ "container:ne-caboose03": "file(mroc-cabeese.json)",
+ "game-graph": "file(tweakedLoadIDS.json)"
}
}
\ No newline at end of file
diff --git a/TweaksAndThings/Extensions/AutoEngineer_Extensions.cs b/TweaksAndThings/Extensions/AutoEngineer_Extensions.cs
index a71600c..e96a908 100644
--- a/TweaksAndThings/Extensions/AutoEngineer_Extensions.cs
+++ b/TweaksAndThings/Extensions/AutoEngineer_Extensions.cs
@@ -30,7 +30,7 @@ namespace RMROC451.TweaksAndThings.Extensions
yield break;
}
oiler._reverse = originIndex > oiler._cars.Count - originIndex;
- _log.Information(
+ _log.Debug(
"AutoOiler {name} starting, rev = {reverse}, caboose required = {req}, caboose halving adjustment = {hasCaboose}, oil limit = {limit}",
oiler.name,
oiler._reverse,
@@ -58,11 +58,11 @@ namespace RMROC451.TweaksAndThings.Extensions
num += num3;
oiler._pendingRunDuration += num3;
oiler._oiledCount++;
- _log.Information("AutoOiler {name}: oiled {car} from {orig} => {new}", oiler.name, car, origOil, car.Oiled);
+ _log.Debug("AutoOiler {name}: oiled {car} from {orig} => {new}", oiler.name, car, origOil, car.Oiled);
}
if (car.HasHotbox && car.Oiled == 1f && cabooseRequired && foundCaboose)
{
- _log.Information("AutoOiler {name}: {foundCaboose} repaired hotbox {car}", oiler.name, foundCaboose, car);
+ _log.Debug("AutoOiler {name}: {foundCaboose} repaired hotbox {car}", oiler.name, foundCaboose, car);
Multiplayer.Broadcast($"{Hyperlink.To(oiler._originCar)}: \"{Hyperlink.To(car)} hotbox repaired!\"");
car.SendPropertyChange(PropertyChange.Control.Hotbox, false);
}
@@ -89,7 +89,7 @@ namespace RMROC451.TweaksAndThings.Extensions
continue;
}
var fc = foundCaboose();
- _log.Information("AutoHotboxSpotter {name}: Hotbox Spotter Running, Found Caboose => {hasCaboose}; Has Cars {hasCars}; Requires Caboose {requiresCaboose}",
+ _log.Debug("AutoHotboxSpotter {name}: Hotbox Spotter Running, Found Caboose => {hasCaboose}; Has Cars {hasCars}; Requires Caboose {requiresCaboose}",
spotter.name, fc, spotter.HasCars, cabooseRequired);
if (CabooseRequirementChecker(string.Format("{0} {1}", spotter.GetType().Name, spotter.name), cabooseRequired, fc, _log))
{
@@ -104,7 +104,7 @@ namespace RMROC451.TweaksAndThings.Extensions
{
var numOrig = num;
num = Random.Range(15, 30);
- _log.Information("AutoHotboxSpotter {name}: Next check went from num(60,300) => {numOrig}; to num(15,30) => {hasCaboose}; Requires Caboose {requiresCaboose}", spotter.name, numOrig, num, fc, cabooseRequired);
+ _log.Debug("AutoHotboxSpotter {name}: Next check went from num(60,300) => {numOrig}; to num(15,30) => {hasCaboose}; Requires Caboose {requiresCaboose}", spotter.name, numOrig, num, fc, cabooseRequired);
}
yield return new WaitForSeconds(num);
spotter.CheckForHotbox();
diff --git a/TweaksAndThings/Extensions/Car_Extensions.cs b/TweaksAndThings/Extensions/Car_Extensions.cs
index 18f62c6..67a6c2b 100644
--- a/TweaksAndThings/Extensions/Car_Extensions.cs
+++ b/TweaksAndThings/Extensions/Car_Extensions.cs
@@ -140,7 +140,7 @@ public static class Car_Extensions
.Union(car.EnumerateCoupled())
.Where(c => c.IsCaboose());
- //if (cabeese?.Any() ?? false) Log.Information($"{nameof(CarsNearCurrentCar)}[{car.DisplayName}] => {cabeese.Count()}");
+ if (cabeese?.Any() ?? false) Log.Debug($"{nameof(CarsNearCurrentCar)}[{car.DisplayName}] => {cabeese.Count()}");
List<(Car car, bool crewCar, float distance)> source =
cabeese.Select(c => (car: c, crewCar: c.IsCrewCar(), distance: car.Distance(c))).ToList();
diff --git a/TweaksAndThings/Patches/AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch.cs b/TweaksAndThings/Patches/AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch.cs
index 623a66f..9869789 100644
--- a/TweaksAndThings/Patches/AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch.cs
+++ b/TweaksAndThings/Patches/AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch.cs
@@ -38,7 +38,7 @@ internal class AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch
if (orig != maxSpeedMph)
{
- _log.Information($"{Enum.GetName(typeof(AutoEngineerMode), mode)}[{TrainController.Shared.SelectedLocomotive.DisplayName}] {nameof(AutoEngineerOrdersExtensions.MaxSpeedMph)} limited to {limitedSpeed} from {orig}; No Caboose in Consist;");
+ _log.Debug($"{Enum.GetName(typeof(AutoEngineerMode), mode)}[{TrainController.Shared.SelectedLocomotive.DisplayName}] {nameof(AutoEngineerOrdersExtensions.MaxSpeedMph)} limited to {limitedSpeed} from {orig}; No Caboose in Consist;");
}
}
@@ -50,7 +50,9 @@ internal class AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch
{
var _persistence = new AutoEngineerPersistence(TrainController.Shared.SelectedLocomotive.KeyValueObject);
var OrdersHelper = new AutoEngineerOrdersHelper(TrainController.Shared.SelectedLocomotive, _persistence);
-
+
+ if (TrainController.Shared.SelectedLocomotive.EnumerateCoupled().All(c => c.IsCaboose() || c.MotivePower())) return false;
+
bool cabooseReq = SingletonPluginBase.Shared.RequireConsistCabooseForOilerAndHotboxSpotter();
string logMessage = $"\n{nameof(SafetyFirstGoverningApplies)}:{Enum.GetName(typeof(AutoEngineerMode), OrdersHelper.Mode)}[{TrainController.Shared.SelectedLocomotive.DisplayName}] ";
Func firstClass = () =>
@@ -85,7 +87,7 @@ internal class AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch
logMessage += $"\nGovern AE? {output}";
- _log.Information(logMessage);
+ _log.Debug(logMessage);
return output;
}
diff --git a/TweaksAndThings/Patches/AutoEngineerOrdersHelper_SetWaypoint_patch.cs b/TweaksAndThings/Patches/AutoEngineerOrdersHelper_SetWaypoint_patch.cs
index a512189..e270df8 100644
--- a/TweaksAndThings/Patches/AutoEngineerOrdersHelper_SetWaypoint_patch.cs
+++ b/TweaksAndThings/Patches/AutoEngineerOrdersHelper_SetWaypoint_patch.cs
@@ -1,6 +1,8 @@
using Game.Notices;
+using Game.State;
using HarmonyLib;
using Model;
+using Network;
using Serilog;
using UI.EngineControls;
using UnityEngine;
@@ -16,11 +18,14 @@ internal class AutoEngineerOrdersHelper_SetWaypoint_patch
private static Serilog.ILogger _log => Log.ForContext();
static void Postfix(AutoEngineerOrdersHelper __instance, Track.Location location, string coupleToCarId)
{
- _log.Information($"start setWP");
- Car selectedLoco = __instance._locomotive;
- _log.Information($"{selectedLoco?.DisplayName ?? ""} set WP");
- Vector3 gamePoint = location.GetPosition();
- EntityReference entityReference = new EntityReference(EntityType.Position, new Vector4(gamePoint.x, gamePoint.y, gamePoint.z, 0));
- selectedLoco.PostNotice("ai-wpt-rmroc451", new Hyperlink(entityReference.URI(), $"WP SET"));
+ if (StateManager.IsHost)
+ {
+ _log.Debug($"start setWP");
+ Car selectedLoco = __instance._locomotive;
+ _log.Debug($"{selectedLoco?.DisplayName ?? ""} set WP");
+ Vector3 gamePoint = location.GetPosition();
+ EntityReference entityReference = new EntityReference(EntityType.Position, new Vector4(gamePoint.x, gamePoint.y, gamePoint.z, 0));
+ selectedLoco.PostNotice("ai-wpt-rmroc451", new Hyperlink(entityReference.URI(), $"WP SET"));
+ }
}
}
diff --git a/TweaksAndThings/Patches/AutoEngineerWaypointControls_ConfigureOptionsDropdown_Patch.cs b/TweaksAndThings/Patches/AutoEngineerWaypointControls_ConfigureOptionsDropdown_Patch.cs
new file mode 100644
index 0000000..4b8bf7b
--- /dev/null
+++ b/TweaksAndThings/Patches/AutoEngineerWaypointControls_ConfigureOptionsDropdown_Patch.cs
@@ -0,0 +1,224 @@
+using Game.State;
+using HarmonyLib;
+using KeyValue.Runtime;
+using Model;
+using Model.AI;
+using Model.Ops;
+using Network;
+using Network.Messages;
+using Railloader;
+using Serilog;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Track;
+using Track.Search;
+using UI;
+using UI.EngineControls;
+using UnityEngine;
+using static Track.Search.RouteSearch;
+using Location = Track.Location;
+
+namespace RMROC451.TweaksAndThings.Patches;
+
+[HarmonyPatch(typeof(AutoEngineerWaypointControls))]
+[HarmonyPatch(nameof(AutoEngineerWaypointControls.ConfigureOptionsDropdown))]
+[HarmonyPatchCategory("RMROC451TweaksAndThings")]
+internal class AutoEngineerWaypointControls_ConfigureOptionsDropdown_Patch
+{
+ private static Serilog.ILogger _log => Log.ForContext();
+
+ private static readonly HashSet _keyChangeObservers = new HashSet();
+ private static readonly HashSet destinations = new HashSet();
+ private static readonly HashSet consist = new HashSet();
+ private static string _lastLocoCarId = string.Empty;
+ private static bool recalcing = false;
+
+ static void Postfix(AutoEngineerWaypointControls __instance, ref OptionsDropdownConfiguration __result)
+ {
+
+ _log.Information($"HI BOB");
+ foreach(var o in _keyChangeObservers) o.Dispose();
+ _keyChangeObservers.Clear();
+ destinations.Clear();
+ recalcing = false;
+ TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase.Shared;
+ if (!tweaksAndThings.IsEnabled()) return;
+ //_log.Information($"HI2");
+
+
+ List rowDatas = __result.Rows.ToList();
+ var func = __result.OnRowSelected;
+ int origCount = rowDatas.Count;
+ int maxRowOrig = origCount - 1;
+
+ var selectedLoco = TrainController.Shared.SelectedLocomotive;
+ if (selectedLoco.id != _lastLocoCarId || !(consist?.Any() ?? false))
+ {
+ _lastLocoCarId = selectedLoco.id;
+ consist.Clear();
+ consist.UnionWith(selectedLoco.EnumerateCoupled()?.ToList() ?? Enumerable.Empty());
+ }
+ var aeoh = new AutoEngineerOrdersHelper(persistence: new AutoEngineerPersistence(selectedLoco.KeyValueObject), locomotive: selectedLoco);
+ List<(string destinationId, string destination, float? distance, Location? location)> jumpTos = new();
+
+ foreach(var c in consist)
+ {
+ AddObserversToCar(__instance, c);
+ OpsCarPosition? destination = c.Waybill.HasValue && !c.Waybill.Value.Completed ? c.Waybill.Value.Destination : null;
+ bool completed = c.Waybill?.Completed ?? false;
+ if (!destination.HasValue && c.TryGetOverrideDestination(OverrideDestination.Repair, OpsController.Shared, out (OpsCarPosition, string)? result)) destination = result.Value.Item1;
+ _log.Information($"{c.DisplayName} -> {destination.HasValue}");
+
+ string destId = destination?.Identifier ?? string.Empty;
+
+ if (destinations.Contains(destId)) continue;
+
+ if (destination.HasValue && !completed)
+ {
+ string destName = destination.Value.DisplayName;
+ float? distance = null;
+
+ if (Graph.Shared.TryGetLocationFromPoint(destination.Value.Spans?.FirstOrDefault().GetSegments().FirstOrDefault(), destination.Value.Spans?.FirstOrDefault()?.GetCenterPoint() ?? default, 200f, out Location destLoc))
+ {
+
+ float trainMomentum = 0f;
+ Location start = StateManager.IsHost ? selectedLoco.AutoEngineerPlanner.RouteStartLocation(out trainMomentum) : RouteStartLocation(__instance, selectedLoco);
+ HeuristicCosts autoEngineer = HeuristicCosts.AutoEngineer;
+ List list = new List();
+ var totLen = StateManager.IsHost ? selectedLoco.AutoEngineerPlanner.CalculateTotalLength() : CalculateTotalLength(selectedLoco);
+ distance = Graph.Shared.FindRoute(start, destLoc, autoEngineer, list, out var metrics, checkForCars: false, totLen, trainMomentum)
+ ? metrics.Distance
+ : null;
+ };
+ _log.Information($"{c.DisplayName} -> {destName} {destId} {distance?.ToString()}");
+ if (distance.HasValue)
+ {
+ destinations.Add(destId);
+ jumpTos.Add((
+ destinationId: destId,
+ destination: $"WP> {destName}"
+ , distance: distance
+ , location: (Location?)destLoc
+ ));
+ }
+ }
+ }
+
+ jumpTos = jumpTos?.OrderBy(c => c.distance)?.ToList() ?? [];
+ var safetyFirst = AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch.SafetyFirstGoverningApplies() && jumpTos.Any();
+
+ rowDatas.AddRange(jumpTos.Select(j =>
+ new DropdownMenu.RowData(
+ $"{j.destination} ({(j.distance.HasValue ? Units.DistanceText(j.distance.Value) : "N/A")})",
+ !safetyFirst ? null : "Disabled; Safety First!"
+ )
+ ));
+
+ __result = new OptionsDropdownConfiguration(
+ rowDatas
+ , delegate (int row)
+ {
+ _log.Information($"{TrainController.Shared.SelectedLocomotive.DisplayName} row {row}/{jumpTos.Count}/{rowDatas.Count}");
+ if (row <= maxRowOrig)
+ {
+ func(row);
+ }
+ if (row > maxRowOrig && jumpTos[row - origCount].location.HasValue)
+ {
+ if (safetyFirst)
+ {
+ Multiplayer.SendError(StateManager.Shared.PlayersManager.LocalPlayer, "Safety First, find yourself a caboose!", AlertLevel.Error);
+ return;
+ }
+ float trainMomentum = 0f;
+ Location end = jumpTos[row - origCount].location.Value;
+ Location start = RouteStartLocation(__instance, selectedLoco);
+ HeuristicCosts autoEngineer = HeuristicCosts.AutoEngineer;
+ List list = new List();
+
+ var totLen = StateManager.IsHost ? selectedLoco.AutoEngineerPlanner.CalculateTotalLength() : CalculateTotalLength(selectedLoco);
+ if (!Graph.Shared.FindRoute(start, end, autoEngineer, list, out var metrics, checkForCars: false, totLen, trainMomentum))
+ {
+ RouteSearch.Metrics metrics2;
+ bool flag = Graph.Shared.FindRoute(start, end, autoEngineer, null, out metrics2);
+ Multiplayer.SendError(StateManager.Shared.PlayersManager.LocalPlayer, flag ? (selectedLoco.DisplayName + " Train too long to navigate to waypoint.") : (selectedLoco.DisplayName + " Unable to find a path to waypoint."), AlertLevel.Error);
+ } else
+ {
+ var mw = (location: end, carId: string.Empty);
+ aeoh.SetWaypoint(mw.location, mw.carId);
+ aeoh.SetOrdersValue(maybeWaypoint: mw);
+ }
+ }
+ }
+ );
+
+ }
+
+ private static Location RouteStartLocation(AutoEngineerWaypointControls __instance, BaseLocomotive _locomotive) {
+ bool num = _locomotive.IsStopped();
+ bool? flag = (num ? null : new bool?(_locomotive.velocity >= 0f));
+
+ bool flag2 = flag ?? __instance.OrdersHelper.Orders.Forward;
+ if (_locomotive.EndToLogical((!flag2) ? Car.End.R : Car.End.F) == Car.LogicalEnd.A)
+ {
+ return _locomotive.EnumerateCoupled().First().WheelBoundsA;
+ }
+
+ return _locomotive.EnumerateCoupled(Car.LogicalEnd.B).First().WheelBoundsB.Flipped();
+ }
+
+ private static float CalculateTotalLength(BaseLocomotive selectedLoco)
+ {
+ List coupledCarsCached = selectedLoco.EnumerateCoupled().ToList();
+ float num = 0f;
+ foreach (Car item in coupledCarsCached)
+ {
+ num += item.carLength;
+ }
+
+ return num + 1.04f * (float)(coupledCarsCached.Count - 1);
+ }
+
+ private static void AddObserversToCar(AutoEngineerWaypointControls __instance, Car c)
+ {
+ AddObserver(__instance, c, Car.KeyOpsWaybill);
+ AddObserver(__instance, c, Car.KeyOpsRepairDestination);
+ foreach (Car.LogicalEnd logicalEnd in CarInspector_PopulateCarPanel_Patch.ends)
+ {
+ AddObserver(__instance, c, Car.KeyValueKeyFor(Car.EndGearStateKey.IsCoupled, c.LogicalToEnd(logicalEnd)), true);
+ }
+ }
+
+ private static void AddObserver(AutoEngineerWaypointControls __instance, Model.Car car, string key, bool clearCarCache = false)
+ {
+ _keyChangeObservers.Add(
+ car.KeyValueObject.Observe(
+ key,
+ delegate (Value value)
+ {
+ _log.Information($"{car.DisplayName} OBSV {key}: {value}; recalcing {recalcing}");
+ if (recalcing) return;
+ try
+ {
+ foreach(var o in _keyChangeObservers)
+ {
+ o.Dispose();
+ }
+ var loco = TrainController.Shared.SelectedLocomotive;
+ TrainController.Shared.SelectedCar = null;
+ _keyChangeObservers.Clear();
+ recalcing = true;
+ new WaitForSeconds(0.25f);
+ TrainController.Shared.SelectedCar = loco;
+ }
+ catch (Exception ex)
+ {
+ _log.ForContext("car", car).Warning(ex, $"{nameof(AddObserver)} {car} Exception logged for {key}");
+ }
+ },
+ false
+ )
+ );
+ }
+}
diff --git a/TweaksAndThings/Patches/BaseLocomotive_FindSourceLocomotive_Patch.cs b/TweaksAndThings/Patches/BaseLocomotive_FindSourceLocomotive_Patch.cs
index bc2db78..887d234 100644
--- a/TweaksAndThings/Patches/BaseLocomotive_FindSourceLocomotive_Patch.cs
+++ b/TweaksAndThings/Patches/BaseLocomotive_FindSourceLocomotive_Patch.cs
@@ -43,3 +43,89 @@ internal class BaseLocomotive_FindSourceLocomotive_Patch
return null;
}
}
+
+//[HarmonyPatch(typeof(LocomotiveAirSystem))]
+//[HarmonyPatch(nameof(LocomotiveAirSystem._ShouldDeferToLocomotiveAir))]
+//[HarmonyPatchCategory("RMROC451TweaksAndThings")]
+//internal class LocomotiveAirSystem__ShouldDeferToLocomotiveAir_Patch
+//{
+// private static void Postfix(LocomotiveAirSystem __instance, ref LocomotiveAirSystem locomotiveAirSystem, ref bool __result)
+// {
+// TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase.Shared;
+// if (!tweaksAndThings.IsEnabled()) return;
+
+// __result = _ShouldDeferToLocomotiveAir(__instance, out locomotiveAirSystem);
+// }
+// public static bool _ShouldDeferToLocomotiveAir(LocomotiveAirSystem __instance, out LocomotiveAirSystem locomotiveAirSystem)
+// {
+// locomotiveAirSystem = null;
+// if (__instance.car.set == null)
+// {
+// return false;
+// }
+// if (!(__instance.car.air is LocomotiveAirSystem locomotiveAirSystem2) || !(__instance.car is BaseLocomotive baseLocomotive))
+// {
+// return false;
+// }
+// if (!locomotiveAirSystem2.IsCutOut || locomotiveAirSystem2.IsMuEnabled)
+// {
+// return false;
+// }
+// BaseLocomotive baseLocomotive2 = baseLocomotive.FindMuSourceLocomotive();
+// if (baseLocomotive2 == null)
+// {
+// return false;
+// }
+// if (!(baseLocomotive2.air is LocomotiveAirSystem locomotiveAirSystem3))
+// {
+// return false;
+// }
+// locomotiveAirSystem = locomotiveAirSystem3;
+// return true;
+// }
+//}
+
+//[HarmonyPatch(typeof(CarAirSystem))]
+//[HarmonyPatch(nameof(CarAirSystem.ShouldDeferToLocomotiveAir))]
+//[HarmonyPatchCategory("RMROC451TweaksAndThings")]
+//internal class CarAirSystem_ShouldDeferToLocomotiveAir_Patch
+//{
+// private static void Postfix(CarAirSystem __instance, ref LocomotiveAirSystem locomotiveAirSystem, ref bool __result)
+// {
+// TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase.Shared;
+// if (!tweaksAndThings.IsEnabled()) return;
+
+// __result = ShouldDeferToLocomotiveAir(__instance, out locomotiveAirSystem);
+// }
+
+// public static bool ShouldDeferToLocomotiveAir(CarAirSystem __instance, out LocomotiveAirSystem locomotiveAirSystem)
+// {
+// locomotiveAirSystem = null;
+// if (__instance.car.set == null)
+// {
+// return false;
+// }
+// if (__instance.car.Archetype != CarArchetype.Tender)
+// {
+// return false;
+// }
+// if (!__instance.car.TryGetAdjacentCar(__instance.car.EndToLogical(Car.End.F), out var adjacent) || !adjacent.IsLocomotive)
+// {
+// return false;
+// }
+// if (!(adjacent.air is LocomotiveAirSystem locomotiveAirSystem2))
+// {
+// return false;
+// }
+// locomotiveAirSystem = locomotiveAirSystem2;
+// if (locomotiveAirSystem.IsMuEnabled)
+// {
+// return true;
+// }
+// if (!locomotiveAirSystem.IsCutOut)
+// {
+// return true;
+// }
+// return locomotiveAirSystem.ShouldDeferToLocomotiveAir(out locomotiveAirSystem);
+// }
+//}
diff --git a/TweaksAndThings/Patches/CarInspector_PopulateCarPanel_Patch.cs b/TweaksAndThings/Patches/CarInspector_PopulateCarPanel_Patch.cs
index ecd6ae8..ed52750 100644
--- a/TweaksAndThings/Patches/CarInspector_PopulateCarPanel_Patch.cs
+++ b/TweaksAndThings/Patches/CarInspector_PopulateCarPanel_Patch.cs
@@ -28,7 +28,7 @@ namespace RMROC451.TweaksAndThings.Patches;
internal class CarInspector_PopulateCarPanel_Patch
{
private static ILogger _log => Log.ForContext();
- private static IEnumerable ends = Enum.GetValues(typeof(LogicalEnd)).Cast();
+ internal static IEnumerable ends = Enum.GetValues(typeof(LogicalEnd)).Cast();
///
/// If a caboose inspector is opened, it will auto set Anglecocks, gladhands and hand brakes
@@ -181,7 +181,7 @@ internal class CarInspector_PopulateCarPanel_Patch
case MrocHelperType.BleedAirSystem:
consist = consist.Where(c => !c.MotivePower());
- _log.ForContext("car", car).Information($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
+ _log.ForContext("car", car).Debug($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
foreach (Model.Car bleed in consist)
{
StateManager.ApplyLocal(new PropertyChange(bleed.id, PropertyChange.Control.Bleed, 1));
@@ -190,7 +190,7 @@ internal class CarInspector_PopulateCarPanel_Patch
case MrocHelperType.Oil:
consist = consist.Where(c => c.NeedsOiling || c.HasHotbox);
- _log.ForContext("car", car).Information($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
+ _log.ForContext("car", car).Debug($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
foreach (Model.Car oil in consist)
{
StateManager.ApplyLocal(new PropertyChange(oil.id, nameof(Car.Oiled).ToLower(), new FloatPropertyValue(1)));
@@ -232,7 +232,7 @@ internal class CarInspector_PopulateCarPanel_Patch
if (cabooseWithAvailCrew == null) timeCost *= 1.5f;
var cabooseFoundDisplay = cabooseWithAvailCrew?.DisplayName ?? "No caboose";
- _log.ForContext("car", car).Information($"{nameof(MrocConsistHelper)} {mrocHelperType} : [VACINITY CABEESE FOUND:{cabooseWithAvailCrew?.ToString() ?? "NONE"}] => Consist Length {consist.Count()} => costs {timeCost / 60} minutes of AI Engineer time, $5 per hour = ~${Math.Ceiling((decimal)(timeCost / 3600) * 5)} (*2 if no caboose nearby)");
+ _log.ForContext("car", car).Debug($"{nameof(MrocConsistHelper)} {mrocHelperType} : [VACINITY CABEESE FOUND:{cabooseWithAvailCrew?.ToString() ?? "NONE"}] => Consist Length {consist.Count()} => costs {timeCost / 60} minutes of AI Engineer time, $5 per hour = ~${Math.Ceiling((decimal)(timeCost / 3600) * 5)} (*2 if no caboose nearby)");
Multiplayer.SendError(StateManager.Shared._playersManager.LocalPlayer, $"{(cabooseWithAvailCrew != null ? $"{cabooseWithAvailCrew.DisplayName} Hours Adjusted: ({tsString})\n" : string.Empty)}Wages: ~(${Math.Ceiling((decimal)(timeCost / 3600) * 5)})");
diff --git a/TweaksAndThings/Patches/CarPickable_Activate_Patch.cs b/TweaksAndThings/Patches/CarPickable_Activate_Patch.cs
index f20795a..32dfc7d 100644
--- a/TweaksAndThings/Patches/CarPickable_Activate_Patch.cs
+++ b/TweaksAndThings/Patches/CarPickable_Activate_Patch.cs
@@ -2,6 +2,7 @@
using HarmonyLib;
using Model;
using Model.Ops;
+using Model.Physics;
using Network;
using Railloader;
using RMROC451.TweaksAndThings.Enums;
@@ -9,6 +10,7 @@ using RMROC451.TweaksAndThings.Extensions;
using RollingStock;
using Serilog;
using System;
+using System.Collections.Generic;
using System.Linq;
using UI;
using UI.Tags;
@@ -40,92 +42,179 @@ internal class CarPickable_Activate_Patch
{
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase.Shared;
if (!tweaksAndThings.IsEnabled()) return true;
- bool bCtrlAltHeld = GameInput.IsControlDown && GameInput.IsAltDown;
- _log.ForContext("car", __instance.car).Information($"{GameInput.IsShiftDown} {GameInput.IsControlDown} {GameInput.IsAltDown} {bCtrlAltHeld} ");
+ _log.ForContext("car", __instance.car).Debug($"{GameInput.IsShiftDown} {GameInput.IsControlDown} {GameInput.IsAltDown}");
if (OnPointerDown(evt, PickableActivation.Primary))
{
CameraSelector.shared.FollowCar(__instance.car);
- _log.ForContext("car", __instance.car).Information("just click!");
+ _log.ForContext("car", __instance.car).Debug("just click!");
return false;
- }
- //single click with keys pressed:
- else if (evt.Activation == PickableActivation.Primary)
- {
- bool output = true;
- var consist = __instance.car.EnumerateCoupled();
- bool handbrakesApplied = consist.Any(c => c.HandbrakeApplied());
- bool airSystemIssues = consist.Any(c => c.EndAirSystemIssue());
- Func cabooseNear = () => (bool)__instance.car.FindMyCaboose(0.0f, false);
- bool needsOiling = GameInput.IsShiftDown && consist.All(c => c.IsStopped()) && consist.Any(c => c.NeedsOiling || c.HasHotbox) && (!tweaksAndThings.RequireConsistCabooseForOilerAndHotboxSpotter() || cabooseNear());
- var chargeIt = handbrakesApplied || airSystemIssues || needsOiling;
- //CTRL + ALT + SHIFT : BrakesAngleCocksAndOiling
- //CTRL + ALT : Release Consist Brakes and Check AngleCocks
- //ALT + SHIFT : toggle consist brakes
- //CTRL + SHIFT : Check Consist Angle Cocks
- //ALT : Toggle car brakes and & air up cars
- //CTRL : NOTHING; BASE CAR INSPECTOR
+ }
+ return HandleCarOrTrainBrakeDisplayClick(__instance.car, tweaksAndThings, evt.Activation);
+ }
+ internal static bool HandleCarOrTrainBrakeDisplayClick(Car car, TweaksAndThingsPlugin tweaksAndThings, PickableActivation activation)
+ {
+ bool bCtrlAltHeld = GameInput.IsControlDown && GameInput.IsAltDown;
+ bool output = true;
+ var consist = car.EnumerateCoupled();
+ bool handbrakesApplied = consist.Any(c => c.HandbrakeApplied());
+ bool airSystemIssues = consist.Any(c => c.EndAirSystemIssue());
+ Func cabooseNear = () => (bool)car.FindMyCaboose(0.0f, false);
+ bool needsOiling = GameInput.IsShiftDown && consist.All(c => c.IsStopped()) && consist.Any(c => c.NeedsOiling || c.HasHotbox) && (!tweaksAndThings.RequireConsistCabooseForOilerAndHotboxSpotter() || cabooseNear());
+ var chargeIt = handbrakesApplied || airSystemIssues || needsOiling;
+ //CTRL + ALT + SHIFT : BrakesAngleCocksAndOiling
+ //CTRL + ALT : Release Consist Brakes and Check AngleCocks
+ //ALT + SHIFT : toggle consist brakes
+ //CTRL + SHIFT : Check Consist Angle Cocks
+ //ALT : Toggle car brakes and & air up cars
+ //CTRL : NOTHING; BASE CAR INSPECTOR
+ //SHIFT : FOLLOW
+
+ if (activation == PickableActivation.Primary)
+ {
if (bCtrlAltHeld)
{
- BrakesAngleCocksAndOiling(__instance, tweaksAndThings, GameInput.IsShiftDown, consist, handbrakesApplied, airSystemIssues, needsOiling, chargeIt);
- _log.ForContext("car", __instance.car).Information($"ctrlAlt{(GameInput.IsShiftDown ? "shift" : string.Empty)}Held!");
+ BrakesAngleCocksAndOiling(car, tweaksAndThings, GameInput.IsShiftDown, consist, handbrakesApplied, airSystemIssues, needsOiling, chargeIt);
+ _log.ForContext("car", car).Debug($"ctrlAlt{(GameInput.IsShiftDown ? "shift" : string.Empty)}Held!");
output = false;
}
else if (GameInput.IsAltDown && GameInput.IsShiftDown)
{
- CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(__instance.car, MrocHelperType.Handbrake, tweaksAndThings.EndGearHelpersRequirePayment());
- _log.ForContext("car", __instance.car).Information("ctrlShiftHeld!");
+ CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Handbrake, tweaksAndThings.EndGearHelpersRequirePayment());
+ _log.ForContext("car", car).Debug("ctrlShiftHeld!");
output = false;
}
else if (GameInput.IsControlDown && GameInput.IsShiftDown)
{
if (airSystemIssues)
- CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(__instance.car, MrocHelperType.GladhandAndAnglecock, tweaksAndThings.EndGearHelpersRequirePayment());
- _log.ForContext("car", __instance.car).Information("altShiftHeld!");
+ CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.GladhandAndAnglecock, tweaksAndThings.EndGearHelpersRequirePayment());
+ _log.ForContext("car", car).Debug("altShiftHeld!");
output = false;
}
else if (GameInput.IsAltDown)
{
- __instance.car.SetHandbrake(!__instance.car.HandbrakeApplied());
- CarInspector_PopulateCarPanel_Patch.CarEndAirUpdate(__instance.car);
- if (__instance.car.TryGetAdjacentCar(Car.LogicalEnd.A, out Model.Car cA)) CarInspector_PopulateCarPanel_Patch.CarEndAirUpdate(cA);
- if (__instance.car.TryGetAdjacentCar(Car.LogicalEnd.B, out Model.Car cB)) CarInspector_PopulateCarPanel_Patch.CarEndAirUpdate(cB);
- _log.ForContext("car", __instance.car).Information("ctrlHeld!");
- TagController.Shared.UpdateTag(__instance.car, __instance.car.TagCallout, OpsController.Shared);
- __instance.car.TagCallout.Update();
+ car.SetHandbrake(!car.HandbrakeApplied());
+ CarInspector_PopulateCarPanel_Patch.CarEndAirUpdate(car);
+ if (car.TryGetAdjacentCar(Car.LogicalEnd.A, out Model.Car cA)) CarInspector_PopulateCarPanel_Patch.CarEndAirUpdate(cA);
+ if (car.TryGetAdjacentCar(Car.LogicalEnd.B, out Model.Car cB)) CarInspector_PopulateCarPanel_Patch.CarEndAirUpdate(cB);
+ _log.ForContext("car", car).Debug("ctrlHeld!");
+ TagController.Shared.UpdateTag(car, car.TagCallout, OpsController.Shared);
+ car.TagCallout.Update();
output = false;
}
- return output;
-
-
- //else if (ctrlHeld && shiftHeld)
- //{
- // var selected = UI.CarInspector.CarInspector._instance._selectedTabState.Value;
- // UI.CarInspector.CarInspector.Show(__instance.car);
- // UI.CarInspector.CarInspector._instance._selectedTabState.Value = selected;
-
- //}
+ else if (GameInput.IsShiftDown)
+ {
+ CameraSelector.shared.FollowCar(car);
+ output = false;
+ }
+ }
+ else if ((GameInput.IsControlDown || GameInput.IsAltDown) && activation == PickableActivation.Secondary)
+ {
+ AltClickageMyBrosif(car, activation);
+ output = false;
+ }
+ else if (activation == PickableActivation.Secondary)
+ {
+ //AltClickageMyBrosif(car, activation);
+ CarPickable.HandleShowContextMenu(car);
+ output = false;
}
- return true;
+ return output;
}
- private static void BrakesAngleCocksAndOiling(CarPickable __instance, TweaksAndThingsPlugin tweaksAndThings, bool shiftHeld, System.Collections.Generic.IEnumerable consist, bool handbrakesApplied, bool airSystemIssues, bool needsOiling, bool chargeIt)
+ private static void AltClickageMyBrosif(Car car, PickableActivation activation)
+ {
+ //if (GameInput.IsControlDown)
+ //{
+
+ //}
+ //else if (GameInput.IsAltDown)
+ //{
+ // logSet(car);
+ // //car.TryGetAdjacentCar(Car.LogicalEnd.A, out var OutCarA);
+ // //car.TryGetAdjacentCar(Car.LogicalEnd.B, out var OutCarB);
+ // output = false;
+ //}
+ List cars = TrainController.Shared.SelectedLocomotive.EnumerateCoupled().ToList();
+ logSet(car);
+ //car.TryGetAdjacentCar(Car.LogicalEnd.A, out var OutCarA);
+ //car.TryGetAdjacentCar(Car.LogicalEnd.B, out var OutCarB);
+ //bool b4 = false;
+ //if ((Object)(object)OutCarA != (Object)null && OutCarA.id == cars[i - 1].id)
+ //{
+ // cars[i - 1].ApplyEndGearChange(Car.LogicalEnd.B, Car.EndGearStateKey.Anglecock, 0f);
+ // ccar.ApplyEndGearChange(Car.LogicalEnd.A, Car.EndGearStateKey.Anglecock, 0f);
+ // ccar.HandleCouplerClick(ccar.EndGearA.Coupler);
+ // logger.Information("{indName}: Decoupled {ccarName} from {cars1Name} at NOA{FR}", new object[4]
+ // {
+ // ((Object)base.Industry).name,
+ // ccar.DisplayName,
+ // cars[i - 1].DisplayName,
+ // (ccar.LogicalToEnd(Car.LogicalEnd.A) == Car.End.F) ? "F" : "R"
+ // });
+ // Storage.LastCarEnd = ccar.LogicalToEnd(Car.LogicalEnd.A);
+ // b4 = true;
+ //}
+ //if ((Object)(object)OutCarB != (Object)null && !b4 && OutCarB.id == cars[i - 1].id)
+ //{
+ // cars[i - 1].ApplyEndGearChange(Car.LogicalEnd.A, Car.EndGearStateKey.Anglecock, 0f);
+ // ccar.ApplyEndGearChange(Car.LogicalEnd.B, Car.EndGearStateKey.Anglecock, 0f);
+ // ccar.HandleCouplerClick(ccar.EndGearB.Coupler);
+ // logger.Information("{indName}: Decoupled {ccarName} from {carsm1Name} at NOB{FR}", new object[4]
+ // {
+ // ((Object)base.Industry).name,
+ // ccar.DisplayName,
+ // cars[i - 1].DisplayName,
+ // (ccar.LogicalToEnd(Car.LogicalEnd.A) == Car.End.F) ? "F" : "R"
+ // });
+ // Storage.LastCarEnd = ccar.LogicalToEnd(Car.LogicalEnd.B);
+ // b4 = true;
+ //}
+ //if (!b4)
+ //{
+ // logger.Information("{IndName}: ERROR: NLC {ccarName} can't find LCC {carsm1Name} ({OutCarAName},{OutCarBName})", new object[5]
+ // {
+ // ((Object)base.Industry).name,
+ // ccar.DisplayName,
+ // cars[i - 1].DisplayName,
+ // ((Object)(object)OutCarA != (Object)null) ? OutCarA.DisplayName : "no Car",
+ // ((Object)(object)OutCarB != (Object)null) ? OutCarB.DisplayName : "no Car"
+ // });
+ // return;
+ //}
+ }
+
+ private static void logSet(Car refCar)
+ {
+ IntegrationSet set = refCar.set;
+ foreach (Car car in set.Cars)
+ {
+ Car acar;
+ string endA = (car.TryGetAdjacentCar(Car.LogicalEnd.A, out acar) ? acar.DisplayName : "none");
+ Car bcar;
+ string endB = (car.TryGetAdjacentCar(Car.LogicalEnd.B, out bcar) ? bcar.DisplayName : "none");
+ _log.Information("[Car: {id}:(EndA:{carA}),(EndB:{carB}),(FisA:{fisA})]", new object[4] { car.DisplayName, endA, endB, car.FrontIsA });
+ }
+ }
+
+
+ private static void BrakesAngleCocksAndOiling(Car car, TweaksAndThingsPlugin tweaksAndThings, bool shiftHeld, System.Collections.Generic.IEnumerable consist, bool handbrakesApplied, bool airSystemIssues, bool needsOiling, bool chargeIt)
{
int hbFix = 0;
if (handbrakesApplied)
- CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(__instance.car, MrocHelperType.Handbrake, false);
+ CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Handbrake, false);
if (airSystemIssues)
- CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(__instance.car, MrocHelperType.GladhandAndAnglecock, false);
+ CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.GladhandAndAnglecock, false);
if (needsOiling)
- hbFix = CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(__instance.car, MrocHelperType.Oil, false);
+ hbFix = CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Oil, false);
if (hbFix > 0)
- Multiplayer.Broadcast($"Near {Hyperlink.To(__instance.car)}: \"{hbFix.Pluralize("hotbox") + " repaired!"}\"");
+ Multiplayer.Broadcast($"Near {Hyperlink.To(car)}: \"{hbFix.Pluralize("hotbox") + " repaired!"}\"");
if (chargeIt)
- CarInspector_PopulateCarPanel_Patch.CalculateCostIfEnabled(__instance.car, MrocHelperType.Handbrake, tweaksAndThings.EndGearHelpersRequirePayment(), consist);
+ CarInspector_PopulateCarPanel_Patch.CalculateCostIfEnabled(car, MrocHelperType.Handbrake, tweaksAndThings.EndGearHelpersRequirePayment(), consist);
}
public static bool OnPointerDown(
diff --git a/TweaksAndThings/Patches/CarPickable_HandleShowContextMenu_Patch.cs b/TweaksAndThings/Patches/CarPickable_HandleShowContextMenu_Patch.cs
index fc174b0..0b36b59 100644
--- a/TweaksAndThings/Patches/CarPickable_HandleShowContextMenu_Patch.cs
+++ b/TweaksAndThings/Patches/CarPickable_HandleShowContextMenu_Patch.cs
@@ -44,23 +44,24 @@ internal class CarPickable_HandleShowContextMenu_Patch
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.BleedAirSystem, buttonsHaveCost);
});
}
-
- shared.AddButton(ContextMenuQuadrant.Brakes, $"{(car.EnumerateCoupled().Any(c => c.HandbrakeApplied()) ? "Release " : "Set ")} Consist", SpriteName.Handbrake, delegate
- {
- CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Handbrake, buttonsHaveCost);
- });
- if (car.EnumerateCoupled().Any(c => c.EndAirSystemIssue()))
- {
+ shared.AddButton(ContextMenuQuadrant.Brakes, $"{(car.EnumerateCoupled().Any(c => c.HandbrakeApplied()) ? "Release " : "Set ")} Consist", SpriteName.Handbrake, delegate
+ {
+ CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Handbrake, buttonsHaveCost);
+ });
+
+ if (car.EnumerateCoupled().Any(c => c.EndAirSystemIssue()))
+ {
shared.AddButton(ContextMenuQuadrant.Unused2, $"Air Up Consist", SpriteName.Select, delegate
{
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.GladhandAndAnglecock, buttonsHaveCost);
});
+ }
}
- }
- else {
- if (car.SupportsBleed())
+ else
{
+ if (car.SupportsBleed())
+ {
shared.AddButton(ContextMenuQuadrant.Brakes, "Bleed", SpriteName.Bleed, car.SetBleed);
}
shared.AddButton(ContextMenuQuadrant.Brakes, car.air.handbrakeApplied ? "Release Handbrake" : "Apply Handbrake", SpriteName.Handbrake, delegate
diff --git a/TweaksAndThings/Patches/MapWindow_OnClick_Patch.cs b/TweaksAndThings/Patches/MapWindow_OnClick_Patch.cs
index 5619df3..c1aef99 100644
--- a/TweaksAndThings/Patches/MapWindow_OnClick_Patch.cs
+++ b/TweaksAndThings/Patches/MapWindow_OnClick_Patch.cs
@@ -39,7 +39,7 @@ internal class MapWindow_OnClick_Patch
texture2D.wrapMode = TextureWrapMode.Clamp;
if (!ImageConversion.LoadImage(texture2D, File.ReadAllBytes(path)))
{
- _log.Information($"Unable to load {name} icon!");
+ _log.Debug($"Unable to load {name} icon!");
return null;
}
Sprite sprite = Sprite.Create(texture2D, new Rect(0f, 0f, texture2D.width, texture2D.height), new Vector2(0.5f, 0.5f));
diff --git a/TweaksAndThings/Patches/NoticeExtensions_PostNotice_Patch.cs b/TweaksAndThings/Patches/NoticeExtensions_PostNotice_Patch.cs
index 27fe48c..17f0d19 100644
--- a/TweaksAndThings/Patches/NoticeExtensions_PostNotice_Patch.cs
+++ b/TweaksAndThings/Patches/NoticeExtensions_PostNotice_Patch.cs
@@ -1,4 +1,5 @@
using Game.Notices;
+using Game.State;
using HarmonyLib;
using Model;
using Serilog;
@@ -14,10 +15,11 @@ internal class NoticeExtensions_PostNotice_Patch
private static ILogger _log => Log.ForContext();
static void Postfix(Car car, string key, string content)
{
+ if (!StateManager.IsHost) return;
try
{
- //Log.Information($"{car.DisplayName} patch PostNotice");
+ //Log.Debug($"{car.DisplayName} patch PostNotice");
if (!string.IsNullOrEmpty(content) &&
key.Equals("ai-wpt") &&
content.ToLower().Contains("Arrived at Waypoint".ToLower())
diff --git a/TweaksAndThings/Patches/OpsController_AnnounceCoalescedPayments_Patch.cs b/TweaksAndThings/Patches/OpsController_AnnounceCoalescedPayments_Patch.cs
index 337045a..6692686 100644
--- a/TweaksAndThings/Patches/OpsController_AnnounceCoalescedPayments_Patch.cs
+++ b/TweaksAndThings/Patches/OpsController_AnnounceCoalescedPayments_Patch.cs
@@ -113,18 +113,18 @@ internal class OpsController_AnnounceCoalescedPayments_Patch
var passengerStops = OpsController.Shared.AllIndustries
.SelectMany(i => i.TrackDisplayables.Where(t => refillLocations.Contains(t.GetType())));
- //Log.Information($"{nameof(OpsController_AnnounceCoalescedPayments_Patch)} => Caboose Helper => PassengerStops => {string.Join(",", passengerStops)}");
+ //Log.Debug($"{nameof(OpsController_AnnounceCoalescedPayments_Patch)} => Caboose Helper => PassengerStops => {string.Join(",", passengerStops)}");
var cabeese = passengerStops
.SelectMany(t => t.TrackSpans?.Select(s => (tc.CarsOnSpan(s) ?? Enumerable.Empty()).Where(c => c.IsCaboose()))?.SelectMany(c => c?.Select(c2 => (t, c2))));
- //Log.Information($"{nameof(OpsController_AnnounceCoalescedPayments_Patch)} => Caboose Helper => PassengerStops Cabeese => {string.Join(",", cabeese?.Select(c => $"{c.t} : {c.c2}") ?? [])}");
+ //Log.Debug($"{nameof(OpsController_AnnounceCoalescedPayments_Patch)} => Caboose Helper => PassengerStops Cabeese => {string.Join(",", cabeese?.Select(c => $"{c.t} : {c.c2}") ?? [])}");
CrewCarDict = CrewCarDict.Where(kvp => cabeese.Select(c => c.c2.id).Contains(kvp.Key)).ToDictionary(k => k.Key, v => v.Value);
var deltaTime = (float)(TimeWeather.Now.TotalSeconds - dateTime.TotalSeconds);
foreach (var caboose in cabeese)
{
- //Log.Information($"{nameof(OpsController_AnnounceCoalescedPayments_Patch)} => Caboose Helper ({deltaTime}) => {caboose.t} : {caboose.c2}");
+ //Log.Debug($"{nameof(OpsController_AnnounceCoalescedPayments_Patch)} => Caboose Helper ({deltaTime}) => {caboose.t} : {caboose.c2}");
CarLoadCrewHelper(caboose.c2, deltaTime);
}
dateTime = TimeWeather.Now;
diff --git a/TweaksAndThings/Patches/TagController_UpdateTag_Patch.cs b/TweaksAndThings/Patches/TagController_UpdateTag_Patch.cs
index 724e5b1..971dc0d 100644
--- a/TweaksAndThings/Patches/TagController_UpdateTag_Patch.cs
+++ b/TweaksAndThings/Patches/TagController_UpdateTag_Patch.cs
@@ -28,7 +28,7 @@ internal class TagController_UpdateTag_Patch
return;
}
- ProceedWithPostFix(car, tagCallout, tweaksAndThings.RequireConsistCabooseForOilerAndHotboxSpotter() || !tweaksAndThings.CabooseRequiredForLocoOilIndicator());
+ ProceedWithPostFix(car, tagCallout, tweaksAndThings.CabooseRequiredForLocoOilIndicator());
return;
}
diff --git a/TweaksAndThings/Patches/TrainBrakeDisplay_GetCarImage_Patch.cs b/TweaksAndThings/Patches/TrainBrakeDisplay_GetCarImage_Patch.cs
new file mode 100644
index 0000000..05d80a4
--- /dev/null
+++ b/TweaksAndThings/Patches/TrainBrakeDisplay_GetCarImage_Patch.cs
@@ -0,0 +1,42 @@
+using HarmonyLib;
+using Model;
+using Railloader;
+using UI;
+using UI.Tags;
+using UnityEngine;
+
+namespace RMROC451.TweaksAndThings.Patches;
+
+[HarmonyPatch(typeof(TrainBrakeDisplay))]
+[HarmonyPatch(nameof(TrainBrakeDisplay.Update))]
+[HarmonyPatchCategory("RMROC451TweaksAndThings")]
+internal class TrainBrakeDisplay_Update_Patch()
+{
+ private static bool Prefix(TrainBrakeDisplay __instance)
+ {
+
+ TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase.Shared;
+ if (!tweaksAndThings.IsEnabled()) return true;
+
+ TweakedOriginalMethods.TrainBrakeDisplay.Update(__instance);
+
+ return false;
+ }
+}
+
+[HarmonyPatch(typeof(TrainBrakeDisplay))]
+[HarmonyPatch(nameof(TrainBrakeDisplay.ColorForCar))]
+[HarmonyPatchCategory("RMROC451TweaksAndThings")]
+internal class TrainBrakeDisplay_ColorForCar_Patch
+{
+ private static bool Prefix(TrainBrakeDisplay __instance, Car car, ref Color __result)
+ {
+ TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase.Shared;
+ if (!tweaksAndThings.IsEnabled() || !tweaksAndThings.TrainBrakeDisplayShowsColorsInCalloutMode() || !TagController.Shared.TagsVisible) return true;
+
+ TweakedOriginalMethods.TrainBrakeDisplay.ColorForCar(__instance, car, ref __result);
+
+ return false;
+ }
+}
+
diff --git a/TweaksAndThings/RMROC451.TweaksAndThings.csproj b/TweaksAndThings/RMROC451.TweaksAndThings.csproj
index c4d70df..8069656 100644
--- a/TweaksAndThings/RMROC451.TweaksAndThings.csproj
+++ b/TweaksAndThings/RMROC451.TweaksAndThings.csproj
@@ -1,9 +1,8 @@
-
+
+
-
- False
False
diff --git a/TweaksAndThings/Settings/Settings.cs b/TweaksAndThings/Settings/Settings.cs
index de4b2a1..26ff960 100644
--- a/TweaksAndThings/Settings/Settings.cs
+++ b/TweaksAndThings/Settings/Settings.cs
@@ -29,7 +29,8 @@ public class Settings
bool servicingFundPenalty,
bool safetyFirst,
CrewHourLoadMethod loadCrewHoursMethod,
- float cabeeseSearchRadiusFtInMeters
+ float cabeeseSearchRadiusFtInMeters,
+ bool trainBrakeDisplayShowsColorsInCalloutMode
)
{
WebhookSettingsList = webhookSettingsList;
@@ -43,6 +44,7 @@ public class Settings
SafetyFirst = safetyFirst;
LoadCrewHoursMethod = loadCrewHoursMethod;
CabeeseSearchRadiusFtInMeters = cabeeseSearchRadiusFtInMeters;
+ TrainBrakeDisplayShowsColorsInCalloutMode = trainBrakeDisplayShowsColorsInCalloutMode;
}
public readonly UIState _selectedTabState = new UIState(null);
@@ -57,6 +59,7 @@ public class Settings
public bool SafetyFirst;
public CrewHourLoadMethod LoadCrewHoursMethod;
public float CabeeseSearchRadiusFtInMeters;
+ public bool TrainBrakeDisplayShowsColorsInCalloutMode;
internal void AddAnotherRow()
{
@@ -64,7 +67,7 @@ public class Settings
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");
+ Log.Debug($"Adding another {nameof(WebhookSettings)} list entry, last one was filled in");
}
}
}
@@ -135,7 +138,7 @@ public static class SettingsExtensions
input?.settings?.SafetyFirst ?? false;
public static bool DayLoadCrewHours(this TweaksAndThingsPlugin input) =>
(input?.settings?.LoadCrewHoursMethod ?? CrewHourLoadMethod.Tracks) == CrewHourLoadMethod.Daily;
- public static float CabeeseSearchRadiusInMeters(this TweaksAndThingsPlugin input) =>
- input?.settings?.CabeeseSearchRadiusFtInMeters ?? 21f;
+ public static bool TrainBrakeDisplayShowsColorsInCalloutMode(this TweaksAndThingsPlugin input) =>
+ input?.settings?.TrainBrakeDisplayShowsColorsInCalloutMode ?? false;
}
\ No newline at end of file
diff --git a/TweaksAndThings/TweakedOriginalMethods/TrainBrakeDisplay.cs b/TweaksAndThings/TweakedOriginalMethods/TrainBrakeDisplay.cs
new file mode 100644
index 0000000..08ad136
--- /dev/null
+++ b/TweaksAndThings/TweakedOriginalMethods/TrainBrakeDisplay.cs
@@ -0,0 +1,177 @@
+using Model;
+using Model.Ops;
+using Model.Physics;
+using Railloader;
+using RMROC451.TweaksAndThings.Patches;
+using UI;
+using UI.CarInspector;
+using UI.Common;
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+using static UnityEngine.UI.Image;
+using Object = UnityEngine.Object;
+
+namespace RMROC451.TweaksAndThings.TweakedOriginalMethods
+{
+ internal static class TrainBrakeDisplay
+ {
+ internal static void ColorForCar(UI.TrainBrakeDisplay __instance, Car car, ref Color __result)
+ {
+ __result = Color.gray;
+
+ if (car.IsDerailed)
+ {
+ __result = __instance.derailedColor;
+ return;
+ }
+ CarAirSystem air = car.air;
+ OpsController opsController = OpsController.Shared;
+ if (air.handbrakeApplied)
+ {
+ __result = __instance.handbrakeAppliedColor;
+ return;
+ }
+ else if (
+ (Object)(object)opsController != (Object)null &&
+ opsController.TryGetDestinationInfo(car, out var destinationName, out var isAtDestination, out var destinationPosition, out var destination)
+ )
+ {
+ Area area = opsController.AreaForCarPosition(destination);
+ if ((Object)(object)area != (Object)null)
+ {
+ __result = area.tagColor;
+ }
+ if (!isAtDestination)
+ {
+ float num = 1f / __result.maxColorComponent;
+ __result *= num;
+ }
+ }
+
+ if (Mathf.InverseLerp(0f, 72f, air.BrakeCylinder.Pressure) >= 10f) __result = (__result + __instance.ColorForPsi(air.BrakeCylinder.Pressure)) / 2f;
+ }
+
+ internal static Image GetCarImage(UI.TrainBrakeDisplay __instance, int index, float xCyl, float yCyl, Car car)
+ {
+ Image output = null;
+ if (__instance._carImages.Count - 1 < index)
+ {
+ var tweaksAndThings = SingletonPluginBase.Shared;
+ GameObject val = new GameObject();
+ val.transform.SetParent(((Component)__instance).transform, false);
+ ((Object)val).name = $"Car {index}";
+ float height = 12f;
+ val.AddComponent().SetFrame(xCyl, yCyl, __instance._imageWidth, height);
+ EventTrigger trigger = val.AddComponent();
+ EventTrigger.Entry entry = new EventTrigger.Entry();
+ entry.eventID = EventTriggerType.PointerClick;
+ entry.callback.AddListener((eventData) => {
+ PointerEventData ped = (PointerEventData)eventData;
+ PickableActivation pa = PickableActivation.Primary;
+ if (ped.button == PointerEventData.InputButton.Right) pa = PickableActivation.Secondary;
+
+ bool checkFurther = ped.button == PointerEventData.InputButton.Middle ? true : CarPickable_Activate_Patch.HandleCarOrTrainBrakeDisplayClick(car, tweaksAndThings, pa);
+ if (checkFurther & GameInput.IsControlDown) CarInspector.Show(car);
+ });
+ trigger.triggers.Add(entry);
+ output = val.AddComponent();
+
+ output.type = (Type)1;
+ __instance._carImages.Add(output);
+ }
+ else
+ {
+ output = __instance._carImages[index];
+ ((Component)output).gameObject.SetActive(true);
+ }
+ output.sprite = (car.IsLocomotive ? __instance.locomotiveTile : __instance.carTile);
+ return output;
+ }
+
+ internal static void Update(UI.TrainBrakeDisplay __instance)
+ {
+ Car selectedCar = __instance._trainController.SelectedCar;
+ if (selectedCar == null || selectedCar.set == null) return;
+
+ int numberOfCars = selectedCar.set.NumberOfCars;
+ if (numberOfCars != __instance._lastNumCars)
+ {
+ __instance.RemoveAllImages();
+ int num = Mathf.Clamp(numberOfCars, 0, 100);
+ float num2 = (float)num * 8f + (float)(num - 1) * 1f;
+ if (num2 > __instance._rectTransform.rect.width)
+ {
+ float num3 = __instance._rectTransform.rect.width / num2;
+ __instance._imageWidth = 8f * num3;
+ __instance._spacing = 1f * num3;
+ }
+ else
+ {
+ __instance._imageWidth = 8f;
+ __instance._spacing = 1f;
+ }
+
+ __instance._lastNumCars = numberOfCars;
+ }
+
+ int num4 = 0;
+ float num5 = __instance._imageWidth / 2f;
+ float num6 = 0f;
+ float y = 12f - 2f * __instance._spacing;
+ Car.LogicalEnd logicalEnd = ((selectedCar.set.IndexOfCar(selectedCar).GetValueOrDefault(0) >= numberOfCars / 2) ? Car.LogicalEnd.B : Car.LogicalEnd.A);
+ Car.LogicalEnd end = ((logicalEnd == Car.LogicalEnd.A) ? Car.LogicalEnd.B : Car.LogicalEnd.A);
+ bool stop = false;
+ int carIndex = selectedCar.set.StartIndexForConnected(selectedCar, logicalEnd, IntegrationSet.EnumerationCondition.Coupled);
+ Car car;
+ while (!stop && (car = selectedCar.set.NextCarConnected(ref carIndex, logicalEnd, IntegrationSet.EnumerationCondition.Coupled, out stop)) != null && !(num5 > __instance._rectTransform.rect.width))
+ {
+ Image carImage = TweakedOriginalMethods.TrainBrakeDisplay.GetCarImage(__instance, num4, num5, 0f, car);
+ num5 += __instance._imageWidth + __instance._spacing;
+ carImage.color = __instance.ColorForCar(car);
+ Image airImage = __instance.GetAirImage(num4, num6, y);
+ num6 += __instance._imageWidth + __instance._spacing;
+ Color color;
+ if (!car[logicalEnd].IsCoupled)
+ {
+ color = ColorForOuterAnglecock(car[logicalEnd].AnglecockSetting);
+ }
+ else
+ {
+ Car car2 = car.CoupledTo(logicalEnd);
+ bool num7 = car2 != null && car2[end].AnglecockSetting > 0.9f;
+ bool flag = car[logicalEnd].AnglecockSetting > 0.9f;
+ color = ((num7 && flag && car[logicalEnd].IsAirConnected) ? Color.clear : Color.white);
+ }
+
+ airImage.color = color;
+ if (!car[end].IsCoupled)
+ {
+ __instance.GetAirImage(num4 + 1, num6, y).color = ColorForOuterAnglecock(car[end].AnglecockSetting);
+ }
+
+ num4++;
+ }
+
+ for (int i = num4; i < __instance._carImages.Count; i++)
+ {
+ __instance._carImages[i].gameObject.SetActive(value: false);
+ }
+
+ for (int j = num4 + 1; j < __instance._airImages.Count; j++)
+ {
+ __instance._airImages[j].gameObject.SetActive(value: false);
+ }
+
+ static Color ColorForOuterAnglecock(float value)
+ {
+ if (!((double)value < 0.01))
+ {
+ return Color.white;
+ }
+
+ return Color.clear;
+ }
+ }
+ }
+}
diff --git a/TweaksAndThings/TweaksAndThingsPlugin.cs b/TweaksAndThings/TweaksAndThingsPlugin.cs
index 7a623b2..1cf6011 100644
--- a/TweaksAndThings/TweaksAndThingsPlugin.cs
+++ b/TweaksAndThings/TweaksAndThingsPlugin.cs
@@ -40,7 +40,7 @@ public class TweaksAndThingsPlugin : SingletonPluginBase,
static TweaksAndThingsPlugin()
{
- Log.Information("Hello! Static Constructor was called!");
+ Log.Debug("Hello! Static Constructor was called!");
}
public TweaksAndThingsPlugin(IModdingContext moddingContext, IModDefinition self)
@@ -49,7 +49,7 @@ public class TweaksAndThingsPlugin : SingletonPluginBase,
this.moddingContext = moddingContext;
- logger.Information("Hello! Constructor was called for {modId}/{modVersion}!", self.Id, self.Version);
+ logger.Debug("Hello! Constructor was called for {modId}/{modVersion}!", self.Id, self.Version);
moddingContext.RegisterConsoleCommand(new EchoCommand());
@@ -58,7 +58,7 @@ public class TweaksAndThingsPlugin : SingletonPluginBase,
public override void OnEnable()
{
- logger.Information("OnEnable() was called!");
+ logger.Debug("OnEnable() was called!");
var harmony = new Harmony(modDefinition.Id);
harmony.PatchCategory(modDefinition.Id.Replace(".", string.Empty));
}
@@ -77,7 +77,7 @@ public class TweaksAndThingsPlugin : SingletonPluginBase,
public void ModTabDidOpen(UIPanelBuilder builder)
{
- logger.Information("Daytime!");
+ logger.Debug("Daytime!");
if (settings == null) settings = new();
if (!settings?.WebhookSettingsList?.Any() ?? true) settings.WebhookSettingsList = new[] { new WebhookSettings() }.ToList();
@@ -88,7 +88,9 @@ public class TweaksAndThingsPlugin : SingletonPluginBase,
settings?.WebhookSettingsList.SanitizeEmptySettings();
builder.AddSection("Adjustments To Base Game", (UIPanelBuilder builder) => {
- builder.AddLabel("Repair tracks now require cars to be waybilled, or they will not be serviced/overhauled.\nThey will report on the company window's location section as 'No Work Order Assigned'.");
+ builder.AddLabel("1) Repair tracks now require cars to be waybilled, or they will not be serviced/overhauled.\nThey will report on the company window's location section as 'No Work Order Assigned'.");
+ builder.Spacer(spacing * spacing);
+ builder.AddLabel("2) You now have the same click options on the little car icons in the lower left engine controls ui, as you do with cars in the game. Ctrl click -> open car inspector, etc.");
});
builder.Spacer(spacing * spacing);
builder.AddTabbedPanels(settings._selectedTabState, delegate (UITabbedPanelBuilder tabBuilder)
@@ -236,6 +238,18 @@ AutoHotboxSpotter Update: decrease the random wait from 30 - 300 seconds to 15 -
}
).Tooltip("Allow Insufficient Funds", $@"Will allow interchange service and repair shops to still function when you are insolvent, at a 20% overdraft fee.");
+ builder.Spacer(spacing);
+ builder.AddFieldToggle(
+ "Train Brake Color Mode",
+ () => this.TrainBrakeDisplayShowsColorsInCalloutMode(),
+ delegate (bool enabled)
+ {
+ if (settings == null) settings = new();
+ settings.TrainBrakeDisplayShowsColorsInCalloutMode = enabled;
+ builder.Rebuild();
+ }
+ ).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);
EngineRosterShowsFuelStatusUISection(builder);
}
@@ -256,7 +270,7 @@ AutoHotboxSpotter Update: decrease the random wait from 30 - 300 seconds to 15 -
builder.Rebuild();
}
)
- ).Tooltip("Enable Fuel Display in Engine Roster", $"Will add reaming fuel indication to Engine Roster (with details in roster row tool tip), Examples : {string.Join(" ", Enumerable.Range(0, 4).Select(i => TextSprites.PiePercent(i, 4)))}");
+ ).Tooltip("Enable Fuel Display in Engine Roster", $"Will add reamaing fuel indication to Engine Roster (with details in roster row tool tip), Examples : {string.Join(" ", Enumerable.Range(0, 4).Select(i => TextSprites.PiePercent(i, 4)))}");
builder.Spacer(spacing);
builder.AddFieldToggle(
@@ -333,7 +347,7 @@ AutoHotboxSpotter Update: decrease the random wait from 30 - 300 seconds to 15 -
public void ModTabDidClose()
{
- logger.Information("Nighttime...");
+ logger.Debug("Nighttime...");
this.moddingContext.SaveSettingsData(this.modDefinition.Id, settings ?? new());
}
}