Compare commits
12 Commits
v2.1.6-bet
...
documentat
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a21ec2e79 | |||
| 3a04405dad | |||
| ba94d80401 | |||
| d692567d95 | |||
| 32f3e8b2db | |||
| a7ae1d479c | |||
| b562424f8b | |||
| f1b68d2827 | |||
| b911ee6f6f | |||
| cc18579507 | |||
| 1dadb04cbe | |||
| 1032edb7ef |
@@ -2,6 +2,6 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<MajorVersion>2</MajorVersion>
|
<MajorVersion>2</MajorVersion>
|
||||||
<MinorVersion>1</MinorVersion>
|
<MinorVersion>1</MinorVersion>
|
||||||
<PatchVersion>6</PatchVersion>
|
<PatchVersion>8</PatchVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
BIN
TweaksAndThings/Images/BleedCar.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
TweaksAndThings/Images/BleedConsist.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
TweaksAndThings/Images/ConnectAir.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
TweaksAndThings/Images/ConsistReleaseBrake.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
TweaksAndThings/Images/ConsistSetBrake.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
TweaksAndThings/Images/Follow.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
TweaksAndThings/Images/Hourglass_icon.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
TweaksAndThings/Images/Map_pin_icon.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
TweaksAndThings/Images/OilCan.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
TweaksAndThings/Images/ReleaseBrake.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
TweaksAndThings/Images/SetBrake.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
TweaksAndThings/Images/Thumbs.db
Normal file
@@ -13,7 +13,7 @@ internal class AutoEngineerControlSetBase_UpdateStatusLabel_Patch
|
|||||||
static void Postfix(AutoEngineerControlSetBase __instance)
|
static void Postfix(AutoEngineerControlSetBase __instance)
|
||||||
{
|
{
|
||||||
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
if (!tweaksAndThings.IsEnabled() || !AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch.SafetyFirstGoverningApplies()) return;
|
if (!tweaksAndThings.IsEnabled() || !AutoEngineerPlanner_HandleCommand_Patch.SafetyFirstGoverningApplies(__instance.Locomotive)) return;
|
||||||
|
|
||||||
string orig = __instance.statusLabel.text;
|
string orig = __instance.statusLabel.text;
|
||||||
__instance.statusLabel.text = $"{orig}; <b>Safety</b>";
|
__instance.statusLabel.text = $"{orig}; <b>Safety</b>";
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using Helpers;
|
||||||
|
using Railloader;
|
||||||
|
using Serilog;
|
||||||
|
using System.Collections;
|
||||||
|
using Track;
|
||||||
|
using UI;
|
||||||
|
using UnityEngine;
|
||||||
|
using static UI.AutoEngineerDestinationPicker;
|
||||||
|
|
||||||
|
namespace RMROC451.TweaksAndThings.Patches;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(AutoEngineerDestinationPicker))]
|
||||||
|
[HarmonyPatch(nameof(AutoEngineerDestinationPicker.Loop))]
|
||||||
|
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||||
|
internal class AutoEngineerDestinationPicker_Loop_Patch
|
||||||
|
{
|
||||||
|
static bool Prefix(AutoEngineerDestinationPicker __instance, ref IEnumerator __result)
|
||||||
|
{
|
||||||
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
|
if (!tweaksAndThings.IsEnabled()) return true;
|
||||||
|
|
||||||
|
__result = Loop(__instance);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerator Loop(AutoEngineerDestinationPicker __instance)
|
||||||
|
{
|
||||||
|
Hit valueOrDefault;
|
||||||
|
Location location;
|
||||||
|
WaitForSecondsRealtime wait = new WaitForSecondsRealtime(1/60);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Location? currentOrdersGotoLocation = __instance.GetCurrentOrdersGotoLocation();
|
||||||
|
Hit? hit = __instance.HitLocation();
|
||||||
|
if (hit.HasValue)
|
||||||
|
{
|
||||||
|
valueOrDefault = hit.GetValueOrDefault();
|
||||||
|
location = valueOrDefault.Location;
|
||||||
|
Graph.PositionRotation positionRotation = __instance._graph.GetPositionRotation(location);
|
||||||
|
__instance.destinationMarker.position = WorldTransformer.GameToWorld(positionRotation.Position);
|
||||||
|
__instance.destinationMarker.rotation = positionRotation.Rotation;
|
||||||
|
__instance.destinationMarker.gameObject.SetActive(value: true);
|
||||||
|
if (!currentOrdersGotoLocation.Equals(location) && __instance.MouseClicked)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__instance.destinationMarker.gameObject.SetActive(value: false);
|
||||||
|
}
|
||||||
|
yield return wait;
|
||||||
|
}
|
||||||
|
Log.Debug("DestinationPicker Hit: {hit} {car} {end}", valueOrDefault.Location, valueOrDefault.CarInfo?.car, valueOrDefault.CarInfo?.end);
|
||||||
|
__instance._ordersHelper.SetWaypoint(location, valueOrDefault.CarInfo?.car.id);
|
||||||
|
__instance.StopLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
using Game.Messages;
|
|
||||||
using HarmonyLib;
|
|
||||||
using Model.AI;
|
|
||||||
using Model.Definition;
|
|
||||||
using Railloader;
|
|
||||||
using RMROC451.TweaksAndThings.Extensions;
|
|
||||||
using Serilog;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using UI.EngineControls;
|
|
||||||
|
|
||||||
namespace RMROC451.TweaksAndThings.Patches;
|
|
||||||
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(AutoEngineerOrdersHelper))]
|
|
||||||
[HarmonyPatch(nameof(AutoEngineerOrdersHelper.SendAutoEngineerCommand), typeof(AutoEngineerMode), typeof(bool), typeof(int), typeof(float), typeof(OrderWaypoint))]
|
|
||||||
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
|
||||||
internal class AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch
|
|
||||||
{
|
|
||||||
|
|
||||||
private static Serilog.ILogger _log => Log.ForContext<AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch>();
|
|
||||||
|
|
||||||
static bool Prefix(AutoEngineerMode mode, ref int maxSpeedMph)
|
|
||||||
{
|
|
||||||
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
|
||||||
if (!tweaksAndThings.IsEnabled() || !tweaksAndThings.SafetyFirst()) return true;
|
|
||||||
|
|
||||||
if (SafetyFirstGoverningApplies())
|
|
||||||
{
|
|
||||||
int orig = maxSpeedMph;
|
|
||||||
int limitedSpeed = Math.Min(maxSpeedMph, 20);
|
|
||||||
maxSpeedMph = mode switch
|
|
||||||
{
|
|
||||||
AutoEngineerMode.Road => limitedSpeed,
|
|
||||||
AutoEngineerMode.Waypoint => limitedSpeed,
|
|
||||||
_ => maxSpeedMph,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (orig != maxSpeedMph)
|
|
||||||
{
|
|
||||||
_log.Debug($"{Enum.GetName(typeof(AutoEngineerMode), mode)}[{TrainController.Shared.SelectedLocomotive.DisplayName}] {nameof(AutoEngineerOrdersExtensions.MaxSpeedMph)} limited to {limitedSpeed} from {orig}; No Caboose in Consist;");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static bool SafetyFirstGoverningApplies()
|
|
||||||
{
|
|
||||||
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<TweaksAndThingsPlugin>.Shared.RequireConsistCabooseForOilerAndHotboxSpotter();
|
|
||||||
string logMessage = $"\n{nameof(SafetyFirstGoverningApplies)}:{Enum.GetName(typeof(AutoEngineerMode), OrdersHelper.Mode)}[{TrainController.Shared.SelectedLocomotive.DisplayName}] ";
|
|
||||||
Func<bool> firstClass = () =>
|
|
||||||
{
|
|
||||||
var output = TrainController.Shared.SelectedEngineExpress();
|
|
||||||
logMessage += $"\nfirst class {output}";
|
|
||||||
return output;
|
|
||||||
};
|
|
||||||
|
|
||||||
Func<bool> FreightConsist = () =>
|
|
||||||
{
|
|
||||||
bool output = !TrainController.Shared.SelectedLocomotive.EnumerateCoupled().ConsistNoFreight();
|
|
||||||
logMessage += $"\nFreightConsist? {output}";
|
|
||||||
logMessage += " " + string.Join(" / ", TrainController.Shared.SelectedLocomotive.EnumerateCoupled().Where(c => !c.MotivePower()).Select(c => $"{c.id} {Enum.GetName(typeof(CarArchetype), c.Archetype)}"));
|
|
||||||
return output;
|
|
||||||
};
|
|
||||||
|
|
||||||
Func<bool> noCaboose = () =>
|
|
||||||
{
|
|
||||||
bool output = TrainController.Shared.SelectedLocomotive.FindMyCabooseSansLoadRequirement() == null;
|
|
||||||
logMessage += $"\ncaboose? {!output}";
|
|
||||||
return output;
|
|
||||||
};
|
|
||||||
|
|
||||||
logMessage += $"\nCaboose Required {cabooseReq}";
|
|
||||||
|
|
||||||
bool output =
|
|
||||||
cabooseReq &&
|
|
||||||
!firstClass() &&
|
|
||||||
FreightConsist() &&
|
|
||||||
noCaboose();
|
|
||||||
|
|
||||||
logMessage += $"\nGovern AE? {output}";
|
|
||||||
if (_log.IsEnabled(Serilog.Events.LogEventLevel.Verbose))
|
|
||||||
logMessage += $"\n{Environment.StackTrace}";
|
|
||||||
|
|
||||||
_log.Debug(logMessage);
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using Game.Notices;
|
|
||||||
using Game.State;
|
|
||||||
using HarmonyLib;
|
|
||||||
using Model;
|
|
||||||
using Network;
|
|
||||||
using Serilog;
|
|
||||||
using UI.EngineControls;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace RMROC451.TweaksAndThings.Patches;
|
|
||||||
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(AutoEngineerOrdersHelper))]
|
|
||||||
[HarmonyPatch(nameof(AutoEngineerOrdersHelper.SetWaypoint), typeof(Track.Location), typeof(string))]
|
|
||||||
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
|
||||||
internal class AutoEngineerOrdersHelper_SetWaypoint_patch
|
|
||||||
{
|
|
||||||
private static Serilog.ILogger _log => Log.ForContext<AutoEngineerOrdersHelper_SetWaypoint_patch>();
|
|
||||||
static void Postfix(AutoEngineerOrdersHelper __instance, Track.Location location, string coupleToCarId)
|
|
||||||
{
|
|
||||||
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"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
using Game;
|
||||||
|
using Game.Messages;
|
||||||
|
using Game.Notices;
|
||||||
|
using Game.State;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Model;
|
||||||
|
using Model.AI;
|
||||||
|
using Model.Definition;
|
||||||
|
using Network;
|
||||||
|
using Network.Messages;
|
||||||
|
using Railloader;
|
||||||
|
using RMROC451.TweaksAndThings.Extensions;
|
||||||
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Track;
|
||||||
|
using UI.EngineControls;
|
||||||
|
using UI.EngineRoster;
|
||||||
|
using UnityEngine;
|
||||||
|
using static Unity.IO.LowLevel.Unsafe.AsyncReadManagerMetrics;
|
||||||
|
using static UnityEngine.InputSystem.InputRemoting;
|
||||||
|
|
||||||
|
namespace RMROC451.TweaksAndThings.Patches;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(AutoEngineerPlanner))]
|
||||||
|
[HarmonyPatch(nameof(AutoEngineerPlanner.HandleCommand))]
|
||||||
|
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||||
|
internal class AutoEngineerPlanner_HandleCommand_Patch
|
||||||
|
{
|
||||||
|
private static Serilog.ILogger _log => Log.ForContext<AutoEngineerPlanner_HandleCommand_Patch>();
|
||||||
|
private static int governedSpeed = 20;
|
||||||
|
|
||||||
|
static bool Prefix(AutoEngineerPlanner __instance, ref AutoEngineerCommand command, ref IPlayer sender)
|
||||||
|
{
|
||||||
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
|
LocoNoticeWPSet(__instance, command, sender);
|
||||||
|
if (!tweaksAndThings.IsEnabled() || !tweaksAndThings.SafetyFirst() || (sender.IsRemote && !tweaksAndThings.SafetyFirstClientEnforce()) || command.MaxSpeedMph <= governedSpeed) return true;
|
||||||
|
BaseLocomotive loco = __instance._locomotive;
|
||||||
|
|
||||||
|
if (SafetyFirstGoverningApplies(loco))
|
||||||
|
{
|
||||||
|
int orig = command.MaxSpeedMph;
|
||||||
|
int limitedSpeed = Math.Min(command.MaxSpeedMph, governedSpeed);
|
||||||
|
command.MaxSpeedMph = command.Mode switch
|
||||||
|
{
|
||||||
|
AutoEngineerMode.Road => limitedSpeed,
|
||||||
|
AutoEngineerMode.Waypoint => limitedSpeed,
|
||||||
|
_ => command.MaxSpeedMph,
|
||||||
|
};
|
||||||
|
|
||||||
|
string message = $"{Enum.GetName(typeof(AutoEngineerMode), command.Mode)}[{loco.DisplayName}] governed{{0}}due to Safety First rules.";
|
||||||
|
if (orig != command.MaxSpeedMph)
|
||||||
|
{
|
||||||
|
message = string.Format(message, $" from {orig} to {command.MaxSpeedMph} MPH ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = string.Format(message, " ");
|
||||||
|
}
|
||||||
|
_log.Debug(message);
|
||||||
|
Multiplayer.SendError(sender, message, AlertLevel.Info);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LocoNoticeWPSet(AutoEngineerPlanner __instance, AutoEngineerCommand command, IPlayer sender)
|
||||||
|
{
|
||||||
|
OrderWaypoint? wp =
|
||||||
|
string.IsNullOrEmpty(command.WaypointLocationString) ?
|
||||||
|
null :
|
||||||
|
new OrderWaypoint?(new OrderWaypoint(command.WaypointLocationString, command.WaypointCoupleToCarId));
|
||||||
|
|
||||||
|
if (
|
||||||
|
wp.HasValue &&
|
||||||
|
!string.IsNullOrEmpty(wp.Value.LocationString) &&
|
||||||
|
!__instance._orders.Waypoint.Equals(wp)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_log.Debug($"start setWP");
|
||||||
|
Car selectedLoco = __instance._locomotive;
|
||||||
|
_log.Debug($"{selectedLoco?.DisplayName ?? ""} set WP");
|
||||||
|
if (LocationPositionFromString(wp.Value, out Vector3 gamePoint))
|
||||||
|
{
|
||||||
|
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 [{sender.Name}]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool LocationPositionFromString(OrderWaypoint waypoint, out Vector3 position)
|
||||||
|
{
|
||||||
|
Location location;
|
||||||
|
position = default;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
location = Graph.Shared.ResolveLocationString(waypoint.LocationString);
|
||||||
|
position = location.GetPosition();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Log.Error(exception, "Couldn't get location from waypoint: {locStr}", waypoint.LocationString);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool SafetyFirstGoverningApplies(BaseLocomotive loco)
|
||||||
|
{
|
||||||
|
var _persistence = new AutoEngineerPersistence(loco.KeyValueObject);
|
||||||
|
var OrdersHelper = new AutoEngineerOrdersHelper(loco, _persistence);
|
||||||
|
|
||||||
|
if (loco.EnumerateCoupled().All(c => c.IsCaboose() || c.MotivePower())) return false;
|
||||||
|
|
||||||
|
bool cabooseReq = SingletonPluginBase<TweaksAndThingsPlugin>.Shared.RequireConsistCabooseForOilerAndHotboxSpotter();
|
||||||
|
string logMessage = $"\n{nameof(SafetyFirstGoverningApplies)}:{Enum.GetName(typeof(AutoEngineerMode), OrdersHelper.Mode)}[{loco.DisplayName}] ";
|
||||||
|
Func<bool> firstClass = () =>
|
||||||
|
{
|
||||||
|
var output = TrainController.Shared.SelectedEngineExpress();
|
||||||
|
logMessage += $"\nfirst class {output}";
|
||||||
|
return output;
|
||||||
|
};
|
||||||
|
|
||||||
|
Func<bool> FreightConsist = () =>
|
||||||
|
{
|
||||||
|
bool output = !loco.EnumerateCoupled().ConsistNoFreight();
|
||||||
|
logMessage += $"\nFreightConsist? {output}";
|
||||||
|
logMessage += " " + string.Join(" / ", loco.EnumerateCoupled().Where(c => !c.MotivePower()).Select(c => $"{c.id} {Enum.GetName(typeof(CarArchetype), c.Archetype)}"));
|
||||||
|
return output;
|
||||||
|
};
|
||||||
|
|
||||||
|
Func<bool> noCaboose = () =>
|
||||||
|
{
|
||||||
|
bool output = loco.FindMyCabooseSansLoadRequirement() == null;
|
||||||
|
logMessage += $"\ncaboose? {!output}";
|
||||||
|
return output;
|
||||||
|
};
|
||||||
|
|
||||||
|
logMessage += $"\nCaboose Required {cabooseReq}";
|
||||||
|
|
||||||
|
bool output =
|
||||||
|
cabooseReq &&
|
||||||
|
!firstClass() &&
|
||||||
|
FreightConsist() &&
|
||||||
|
noCaboose();
|
||||||
|
|
||||||
|
logMessage += $"\nGovern AE? {output}";
|
||||||
|
if (_log.IsEnabled(Serilog.Events.LogEventLevel.Verbose))
|
||||||
|
logMessage += $"\n{Environment.StackTrace}";
|
||||||
|
|
||||||
|
_log.Debug(logMessage);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ internal class LocomotiveControlsUIAdapter_UpdateCarText_Postfix()
|
|||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (__instance._persistence.Orders.Mode != AutoEngineerMode.Waypoint) yield return wait;
|
if (__instance._persistence.Orders.Mode != AutoEngineerMode.Waypoint || ((AutoEngineerWaypointControls)__instance.aiWaypointControls).Locomotive == null) yield return wait;
|
||||||
|
|
||||||
PrepLocoUsage((AutoEngineerWaypointControls)__instance.aiWaypointControls, out BaseLocomotive selectedLoco, out int numberOfCars);
|
PrepLocoUsage((AutoEngineerWaypointControls)__instance.aiWaypointControls, out BaseLocomotive selectedLoco, out int numberOfCars);
|
||||||
HashSet<OpsCarPosition?> destinations = [];
|
HashSet<OpsCarPosition?> destinations = [];
|
||||||
@@ -117,14 +117,14 @@ internal class LocomotiveControlsUIAdapter_UpdateCarText_Postfix()
|
|||||||
//_log.Information($"{locoKey} --> [{locoConsistDestinations.Count}] -> Cache -> {string.Join(Environment.NewLine, locoConsistDestinations.Select(k => $"{locoKey}:{k.Value.DisplayName}"))}");
|
//_log.Information($"{locoKey} --> [{locoConsistDestinations.Count}] -> Cache -> {string.Join(Environment.NewLine, locoConsistDestinations.Select(k => $"{locoKey}:{k.Value.DisplayName}"))}");
|
||||||
|
|
||||||
output |= !locoConsistDestinations.SetEquals(destinations);
|
output |= !locoConsistDestinations.SetEquals(destinations);
|
||||||
_log.Information($"{locoKey} 1-> {output}");
|
//_log.Information($"{locoKey} 1-> {output}");
|
||||||
if (output) lastSeenIntegrationSetCount = default;
|
if (output) lastSeenIntegrationSetCount = default;
|
||||||
output |= lastSeenIntegrationSetCount != selectedLoco.set.NumberOfCars;
|
output |= lastSeenIntegrationSetCount != selectedLoco.set.NumberOfCars;
|
||||||
_log.Information($"{locoKey} 2-> {output}");
|
//_log.Information($"{locoKey} 2-> {output}");
|
||||||
//output |= __instance.optionsDropdown.scrollRect.content.childCount != (destinations.Count + timetableDestinations.Count + 1); //+1 for the default "JumpTo" entry)
|
//output |= __instance.optionsDropdown.scrollRect.content.childCount != (destinations.Count + timetableDestinations.Count + 1); //+1 for the default "JumpTo" entry)
|
||||||
//_log.Information($"{locoKey} 2.5-> {output} {__instance.optionsDropdown.scrollRect.content.childCount} {(destinations.Count)} {timetableDestinations.Count}");
|
//_log.Information($"{locoKey} 2.5-> {output} {__instance.optionsDropdown.scrollRect.content.childCount} {(destinations.Count)} {timetableDestinations.Count}");
|
||||||
output |= selectedLoco.TryGetTimetableTrain(out _) && TimetableController.Shared.CurrentDocument.Modified != timetableSaveTime;
|
output |= selectedLoco.TryGetTimetableTrain(out _) && TimetableController.Shared.CurrentDocument.Modified != timetableSaveTime;
|
||||||
_log.Information($"{locoKey} 3-> {output}");
|
//_log.Information($"{locoKey} 3-> {output}");
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ internal class LocomotiveControlsUIAdapter_UpdateCarText_Postfix()
|
|||||||
OptionsDropdownConfiguration __result;
|
OptionsDropdownConfiguration __result;
|
||||||
jumpTos = jumpTos?.OrderBy(c => c.sortDistance)?.ToList() ?? default;
|
jumpTos = jumpTos?.OrderBy(c => c.sortDistance)?.ToList() ?? default;
|
||||||
var localJumpTos = jumpTos.ToList();
|
var localJumpTos = jumpTos.ToList();
|
||||||
var safetyFirst = AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch.SafetyFirstGoverningApplies() && jumpTos.Any();
|
var safetyFirst = AutoEngineerPlanner_HandleCommand_Patch.SafetyFirstGoverningApplies(selectedLoco) && jumpTos.Any();
|
||||||
|
|
||||||
rowDatas.AddRange(jumpTos.Select(j =>
|
rowDatas.AddRange(jumpTos.Select(j =>
|
||||||
new DropdownMenu.RowData(
|
new DropdownMenu.RowData(
|
||||||
@@ -227,11 +227,11 @@ internal class LocomotiveControlsUIAdapter_UpdateCarText_Postfix()
|
|||||||
|
|
||||||
if (selectedLoco.TryGetTimetableTrain(out Timetable.Train t))
|
if (selectedLoco.TryGetTimetableTrain(out Timetable.Train t))
|
||||||
{
|
{
|
||||||
_log.Information($"{getDictKey(selectedLoco)} -> {t.DisplayStringLong}");
|
//_log.Information($"{getDictKey(selectedLoco)} -> {t.DisplayStringLong}");
|
||||||
foreach (var e in t.Entries)
|
foreach (var e in t.Entries)
|
||||||
{
|
{
|
||||||
var stp = TimetableController.Shared.GetAllStations().FirstOrDefault(ps => ps.code == e.Station);
|
var stp = TimetableController.Shared.GetAllStations().FirstOrDefault(ps => ps.code == e.Station);
|
||||||
_log.Information($"{getDictKey(selectedLoco)} -> {t.DisplayStringLong} -> {e.Station} {stp}");
|
//_log.Information($"{getDictKey(selectedLoco)} -> {t.DisplayStringLong} -> {e.Station} {stp}");
|
||||||
if (stp != null)
|
if (stp != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -315,8 +315,8 @@ internal class LocomotiveControlsUIAdapter_UpdateCarText_Postfix()
|
|||||||
{
|
{
|
||||||
//wire up that loco
|
//wire up that loco
|
||||||
selectedLoco = __instance.Locomotive;
|
selectedLoco = __instance.Locomotive;
|
||||||
numberOfCars = selectedLoco.set.NumberOfCars;
|
numberOfCars = selectedLoco?.set.NumberOfCars ?? -1;
|
||||||
_log.Debug($"{selectedLoco.id} --> HI BOB[{numberOfCars}]");
|
_log.Debug($"{selectedLoco?.id} --> HI BOB[{numberOfCars}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OpsCarPosition? GetCarDestinationIdentifier(Car c)
|
private static OpsCarPosition? GetCarDestinationIdentifier(Car c)
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ internal class CarInspector_PopulateCarPanel_Patch
|
|||||||
int consistLength = consist.Count();
|
int consistLength = consist.Count();
|
||||||
int tonnage = LocomotiveControlsHoverArea.CalculateTonnage(consist);
|
int tonnage = LocomotiveControlsHoverArea.CalculateTonnage(consist);
|
||||||
int lengthInMeters = UnityEngine.Mathf.CeilToInt(LocomotiveControlsHoverArea.CalculateLengthInMeters(consist.ToList()) * 3.28084f);
|
int lengthInMeters = UnityEngine.Mathf.CeilToInt(LocomotiveControlsHoverArea.CalculateLengthInMeters(consist.ToList()) * 3.28084f);
|
||||||
var newSubTitle = () => string.Format("{0}, {1:N0}T, {2:N0}ft, {3:0.0} mph", consistLength.Pluralize("car"), tonnage, lengthInMeters, __instance._car.VelocityMphAbs);
|
var newSubTitle = () => string.Format("{0}, {1:N0}T, {2:N0}ft, {3:N0} mph", consistLength.Pluralize("car"), tonnage, lengthInMeters, __instance._car.VelocityMphAbs);
|
||||||
|
|
||||||
field.AddLabel(() => newSubTitle(), UIPanelBuilder.Frequency.Fast)
|
field.AddLabel(() => newSubTitle(), UIPanelBuilder.Frequency.Fast)
|
||||||
.Tooltip("Consist Info", "Reflects info about consist.").FlexibleWidth();
|
.Tooltip("Consist Info", "Reflects info about consist.").FlexibleWidth();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using HarmonyLib;
|
using Game.State;
|
||||||
|
using HarmonyLib;
|
||||||
using Model;
|
using Model;
|
||||||
using Railloader;
|
using Railloader;
|
||||||
using RMROC451.TweaksAndThings.Enums;
|
using RMROC451.TweaksAndThings.Enums;
|
||||||
@@ -8,6 +9,8 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UI;
|
using UI;
|
||||||
using UI.ContextMenu;
|
using UI.ContextMenu;
|
||||||
|
using UnityEngine;
|
||||||
|
using ContextMenu = UI.ContextMenu.ContextMenu;
|
||||||
|
|
||||||
namespace RMROC451.TweaksAndThings.Patches;
|
namespace RMROC451.TweaksAndThings.Patches;
|
||||||
|
|
||||||
@@ -34,50 +37,79 @@ internal class CarPickable_HandleShowContextMenu_Patch
|
|||||||
{
|
{
|
||||||
trainController.SelectedCar = ((trainController.SelectedCar == car) ? null : car);
|
trainController.SelectedCar = ((trainController.SelectedCar == car) ? null : car);
|
||||||
});
|
});
|
||||||
if (GameInput.IsShiftDown)
|
|
||||||
|
bool shiftPagination = (tweaksAndThings.ShiftForPagination() && GameInput.IsShiftDown) || !tweaksAndThings.ShiftForPagination();
|
||||||
|
bool nonShiftShow = (tweaksAndThings.ShiftForPagination() && !GameInput.IsShiftDown) || !tweaksAndThings.ShiftForPagination();
|
||||||
|
|
||||||
|
if (shiftPagination && car.EnumerateCoupled().Any(c => c.SupportsBleed()))
|
||||||
{
|
{
|
||||||
if (!car.EnumerateCoupled().Any(c => !c.SupportsBleed()))
|
Sprite? bleedConsist = MapWindow_OnClick_Patch.LoadTexture("BleedConsist.png", "BleedConsist");
|
||||||
|
if (bleedConsist == null) bleedConsist = SpriteName.Bleed.Sprite();
|
||||||
|
shared.AddButton(ContextMenuQuadrant.Brakes, $"Bleed Consist", bleedConsist, delegate
|
||||||
{
|
{
|
||||||
shared.AddButton(ContextMenuQuadrant.Brakes, $"Bleed Consist", SpriteName.Bleed, delegate
|
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.BleedAirSystem, buttonsHaveCost);
|
||||||
{
|
|
||||||
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 (nonShiftShow && car.SupportsBleed())
|
||||||
|
{
|
||||||
|
Sprite? bleedCar = MapWindow_OnClick_Patch.LoadTexture("BleedCar.png", "BleedCar");
|
||||||
|
if (bleedCar == null) bleedCar = SpriteName.Bleed.Sprite();
|
||||||
|
shared.AddButton(ContextMenuQuadrant.Brakes, "Bleed", bleedCar, car.SetBleed);
|
||||||
|
}
|
||||||
|
|
||||||
if (car.EnumerateCoupled().Any(c => c.EndAirSystemIssue()))
|
if (shiftPagination)
|
||||||
{
|
{
|
||||||
shared.AddButton(ContextMenuQuadrant.General, $"Air Up Consist", SpriteName.Select, delegate
|
string text = car.EnumerateCoupled().Any(c => c.HandbrakeApplied()) ? "Release " : "Set ";
|
||||||
|
Sprite? consistBrakes = MapWindow_OnClick_Patch.LoadTexture($"Consist{text.Trim()}Brake.png", $"{text.Trim()}Consist");
|
||||||
|
if (consistBrakes == null) consistBrakes = SpriteName.Handbrake.Sprite();
|
||||||
|
shared.AddButton(ContextMenuQuadrant.Brakes, $"{text}Consist", consistBrakes, delegate
|
||||||
|
{
|
||||||
|
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Handbrake, buttonsHaveCost);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nonShiftShow)
|
||||||
|
{
|
||||||
|
string textCar = car.HandbrakeApplied() ? "Release " : "Set ";
|
||||||
|
Sprite? carBrakes = MapWindow_OnClick_Patch.LoadTexture($"{textCar.Trim()}Brake.png", $"{textCar.Trim()}Brake");
|
||||||
|
if (carBrakes == null) carBrakes = SpriteName.Handbrake.Sprite();
|
||||||
|
shared.AddButton(ContextMenuQuadrant.Brakes, $"{textCar}Handbrake", carBrakes, delegate
|
||||||
|
{
|
||||||
|
bool apply = !car.air.handbrakeApplied;
|
||||||
|
car.SetHandbrake(apply);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shiftPagination && car.EnumerateCoupled().Any(c => c.EndAirSystemIssue()))
|
||||||
|
{
|
||||||
|
Sprite? connectAir = MapWindow_OnClick_Patch.LoadTexture($"ConnectAir.png", "ConnectAir");
|
||||||
|
if (connectAir == null) connectAir = SpriteName.Select.Sprite();
|
||||||
|
shared.AddButton(ContextMenuQuadrant.General, $"Air Up Consist", connectAir, delegate
|
||||||
{
|
{
|
||||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.GladhandAndAnglecock, buttonsHaveCost);
|
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.GladhandAndAnglecock, buttonsHaveCost);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (StateManager.IsHost && shiftPagination && car.EnumerateCoupled().Any(c => c.NeedsOiling || c.HasHotbox))
|
||||||
{
|
{
|
||||||
if (car.SupportsBleed())
|
Sprite? oilCan = MapWindow_OnClick_Patch.LoadTexture("OilCan.png", "OilCan");
|
||||||
|
if (oilCan == null) oilCan = SpriteName.Select.Sprite();
|
||||||
|
shared.AddButton(ContextMenuQuadrant.General, $"Oil Consist", oilCan, delegate
|
||||||
{
|
{
|
||||||
shared.AddButton(ContextMenuQuadrant.Brakes, "Bleed", SpriteName.Bleed, car.SetBleed);
|
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Oil, buttonsHaveCost);
|
||||||
}
|
|
||||||
shared.AddButton(ContextMenuQuadrant.Brakes, car.air.handbrakeApplied ? "Release Handbrake" : "Apply Handbrake", SpriteName.Handbrake, delegate
|
|
||||||
{
|
|
||||||
bool apply = !car.air.handbrakeApplied;
|
|
||||||
car.SetHandbrake(apply);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
shared.AddButton(ContextMenuQuadrant.General, $"Follow", SpriteName.Inspect, delegate
|
Sprite? follow = MapWindow_OnClick_Patch.LoadTexture($"Follow.png", "ConnectAir");
|
||||||
|
if (follow == null) follow = SpriteName.Inspect.Sprite();
|
||||||
|
shared.AddButton(ContextMenuQuadrant.General, $"Follow", follow, delegate
|
||||||
{
|
{
|
||||||
CameraSelector.shared.FollowCar(car);
|
CameraSelector.shared.FollowCar(car);
|
||||||
});
|
});
|
||||||
|
|
||||||
string secondaryLine = car.Waybill.HasValue ? $"{Environment.NewLine}{car.Waybill.Value.Destination.DisplayName}" : string.Empty;
|
string secondaryLine = car.Waybill.HasValue ? $"{Environment.NewLine}{car.Waybill.Value.Destination.DisplayName}" : string.Empty;
|
||||||
secondaryLine = secondaryLine.Length > 10 + Environment.NewLine.Length ? $"{secondaryLine.Substring(0, 7+ Environment.NewLine.Length)}..." : secondaryLine;
|
secondaryLine = secondaryLine.Length > 10 + Environment.NewLine.Length ? $"{secondaryLine.Substring(0, 7 + Environment.NewLine.Length)}..." : secondaryLine;
|
||||||
shared.Show($"{car.DisplayName}{secondaryLine}");
|
shared.Show($"{car.EnumerateCoupled().Count()} Cars{Environment.NewLine}{car.DisplayName}{secondaryLine}");
|
||||||
shared.BuildItemAngles();
|
shared.BuildItemAngles();
|
||||||
shared.StartCoroutine(shared.AnimateButtonsShown());
|
shared.StartCoroutine(shared.AnimateButtonsShown());
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ internal class EngineRosterPanel_Populate_Patch
|
|||||||
__instance._window.Title = __instance._window.Title.Split(':')[0].Trim();
|
__instance._window.Title = __instance._window.Title.Split(':')[0].Trim();
|
||||||
if (!tweaksAndThings.IsEnabled()) return true;
|
if (!tweaksAndThings.IsEnabled()) return true;
|
||||||
|
|
||||||
var hiddenEntries = rows.Where(r => r.Engine.IsMuEnabled && !r.IsSelected && !r.IsFavorite).Select(r => r.Engine.id) ?? Enumerable.Empty<string>();
|
var hiddenEntries = rows.Where(r => r.Engine.locomotiveControl.air.IsCutOut && !r.IsSelected && !r.IsFavorite).Select(r => r.Engine.id) ?? Enumerable.Empty<string>();
|
||||||
|
|
||||||
if (hiddenEntries.Any()) __instance._window.Title =string.Format("{0} : {1}", __instance._window.Title, $"Hidden MU Count [{hiddenEntries.Count()}]");
|
if (hiddenEntries.Any()) __instance._window.Title =string.Format("{0} : {1}", __instance._window.Title, $"Hidden MU Count [{hiddenEntries.Count()}]");
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ using UI.EngineRoster;
|
|||||||
using UI.Tooltips;
|
using UI.Tooltips;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Game.State;
|
using Game.State;
|
||||||
|
using Game;
|
||||||
|
|
||||||
|
|
||||||
namespace RMROC451.TweaksAndThings.Patches;
|
namespace RMROC451.TweaksAndThings.Patches;
|
||||||
@@ -34,6 +35,8 @@ internal class EngineRosterRow_Refresh_Patch
|
|||||||
string fuelInfoText = string.Empty;
|
string fuelInfoText = string.Empty;
|
||||||
string fuelInfoTooltip = string.Empty;
|
string fuelInfoTooltip = string.Empty;
|
||||||
|
|
||||||
|
TweakyTweakTweakers(__instance);
|
||||||
|
|
||||||
if (tweaksAndThings == null ||
|
if (tweaksAndThings == null ||
|
||||||
rosterFuelColumnSettings == null ||
|
rosterFuelColumnSettings == null ||
|
||||||
!tweaksAndThings.IsEnabled() ||
|
!tweaksAndThings.IsEnabled() ||
|
||||||
@@ -52,7 +55,7 @@ internal class EngineRosterRow_Refresh_Patch
|
|||||||
bool cabooseRequirementFulfilled =
|
bool cabooseRequirementFulfilled =
|
||||||
!tweaksAndThings.RequireConsistCabooseForOilerAndHotboxSpotter()
|
!tweaksAndThings.RequireConsistCabooseForOilerAndHotboxSpotter()
|
||||||
|| consist.ConsistNoFreight()
|
|| consist.ConsistNoFreight()
|
||||||
|| (bool)engineOrTender.FindMyCabooseSansLoadRequirement();
|
|| (bool)engineOrTender.FindMyCabooseSansLoadRequirement();
|
||||||
float offendingPercentage = 100f;
|
float offendingPercentage = 100f;
|
||||||
|
|
||||||
foreach (Car loco in locos)
|
foreach (Car loco in locos)
|
||||||
@@ -131,13 +134,54 @@ internal class EngineRosterRow_Refresh_Patch
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (Exception ex)
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
rosterFuelColumnSettings.EngineRosterFuelStatusColumn = EngineRosterFuelDisplayColumn.None;
|
rosterFuelColumnSettings.EngineRosterFuelStatusColumn = EngineRosterFuelDisplayColumn.None;
|
||||||
Log.Error(ex, "Error Detecting fuel status for engine roster");
|
Log.Error(ex, "Error Detecting fuel status for engine roster");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void TweakyTweakTweakers(EngineRosterRow __instance)
|
||||||
|
{
|
||||||
|
var helperData = EngineTextHelper(__instance._engine);
|
||||||
|
|
||||||
|
if (helperData.HasValue)
|
||||||
|
{
|
||||||
|
__instance.nameLabel.text = helperData.Value.nameLabel;
|
||||||
|
__instance.nameTooltip.tooltipText += helperData.Value.nameTooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
__instance.crewLabel.text = string.Empty;
|
||||||
|
for (int i = __instance._crewComponents.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
string str = __instance._crewComponents[i];
|
||||||
|
if ((new[] { "MU", "AE" }).Contains(str))
|
||||||
|
str = $"<sup>{str} </sup>";
|
||||||
|
__instance.crewLabel.text = $"{str}{__instance.crewLabel.text}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static (string nameLabel, string nameTooltip, int selectedCount)? EngineTextHelper(Car loco, bool mapIcon = false)
|
||||||
|
{
|
||||||
|
(string nameLabel, string nameTooltip, int selectedCount)? output = null;
|
||||||
|
int selectedCount = 0;
|
||||||
|
Dictionary<PlayerId, IPlayer> dictionary = StateManager.Shared.PlayersManager.AllPlayers.ToDictionary((IPlayer p) => p.PlayerId, (IPlayer p) => p);
|
||||||
|
List<string> usersSelected = new();
|
||||||
|
foreach (var kvp in dictionary)
|
||||||
|
{
|
||||||
|
if (new PlayerProperties(PlayerPropertiesManager.Shared._object[kvp.Key.ToString()]).SelectedCarId == loco.id)
|
||||||
|
{
|
||||||
|
usersSelected.Add(kvp.Value.Name);
|
||||||
|
selectedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedCount > 0 && dictionary.Count > 1)
|
||||||
|
output = ($"{(mapIcon && loco is BaseLocomotive ? loco.Ident.RoadNumber : loco.DisplayName)}<sub>{selectedCount}</sub>", $"{Environment.NewLine}Selected by: {string.Join(", ", usersSelected)}", selectedCount);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
private static void SetLabelAndTooltip(ref TMP_Text label, ref UITooltipProvider tooltip, string fuelInfoText, string fuelInfoTooltip)
|
private static void SetLabelAndTooltip(ref TMP_Text label, ref UITooltipProvider tooltip, string fuelInfoText, string fuelInfoTooltip)
|
||||||
{
|
{
|
||||||
label.text = $" {fuelInfoText} {label.text}";
|
label.text = $" {fuelInfoText} {label.text}";
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ internal class MapWindow_OnClick_Patch
|
|||||||
public static Sprite? LoadTexture(string fileName, string name)
|
public static Sprite? LoadTexture(string fileName, string name)
|
||||||
{
|
{
|
||||||
string path = Path.Combine(SingletonPluginBase<TweaksAndThingsPlugin>.Shared.ModDirectory, fileName);
|
string path = Path.Combine(SingletonPluginBase<TweaksAndThingsPlugin>.Shared.ModDirectory, fileName);
|
||||||
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
|
_log.Debug($"Unable to find {name} icon at {path}!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Texture2D texture2D = new Texture2D(128, 128, TextureFormat.DXT5, mipChain: false);
|
Texture2D texture2D = new Texture2D(128, 128, TextureFormat.DXT5, mipChain: false);
|
||||||
texture2D.name = name;
|
texture2D.name = name;
|
||||||
texture2D.wrapMode = TextureWrapMode.Clamp;
|
texture2D.wrapMode = TextureWrapMode.Clamp;
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using Helpers;
|
||||||
|
using Model.Database;
|
||||||
|
using Model.Definition;
|
||||||
|
using Model.Definition.Data;
|
||||||
|
using Model.Ops;
|
||||||
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace RMROC451.TweaksAndThings.Patches;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(PrefabStoreExtensions))]
|
||||||
|
[HarmonyPatch(nameof(PrefabStoreExtensions.Random))]
|
||||||
|
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||||
|
internal static class PrefabStoreExtensions_Random_Patch
|
||||||
|
{
|
||||||
|
public static bool Prefix(IPrefabStore prefabStore, CarTypeFilter carTypeFilter, IndustryContext.CarSizePreference sizePreference, Random rnd, ref TypedContainerItem<CarDefinition> __result)
|
||||||
|
{
|
||||||
|
List<TypedContainerItem<CarDefinition>> list =
|
||||||
|
(from p in prefabStore.AllCarDefinitionInfos.ToList().FindAll((TypedContainerItem<CarDefinition> p) =>
|
||||||
|
carTypeFilter.Matches(p.Definition.CarType) && !p.Metadata.Tags.Any(t => t.Equals("deprecated")))
|
||||||
|
orderby p.Definition.WeightEmpty
|
||||||
|
select p).ToList();
|
||||||
|
if (list.Count == 0)
|
||||||
|
{
|
||||||
|
Log.Error($"Couldn't find car for condition: {carTypeFilter}");
|
||||||
|
__result = null;
|
||||||
|
}
|
||||||
|
__result = list.RandomElementUsingNormalDistribution(sizePreference switch
|
||||||
|
{
|
||||||
|
IndustryContext.CarSizePreference.Small => 0.2f,
|
||||||
|
IndustryContext.CarSizePreference.Medium => 0.4f,
|
||||||
|
IndustryContext.CarSizePreference.Large => 0.6f,
|
||||||
|
IndustryContext.CarSizePreference.ExtraLarge => 0.8f,
|
||||||
|
_ => 0.5f,
|
||||||
|
}, rnd);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,4 +55,8 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Publicize Include="Assembly-CSharp" />
|
<Publicize Include="Assembly-CSharp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="Images\**" CopyToOutputDirectory="Always"/>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -28,9 +28,11 @@ public class Settings
|
|||||||
bool cabooseRequiredForLocoTagOilIndication,
|
bool cabooseRequiredForLocoTagOilIndication,
|
||||||
bool servicingFundPenalty,
|
bool servicingFundPenalty,
|
||||||
bool safetyFirst,
|
bool safetyFirst,
|
||||||
|
bool safetyFirstClientEnforce,
|
||||||
CrewHourLoadMethod loadCrewHoursMethod,
|
CrewHourLoadMethod loadCrewHoursMethod,
|
||||||
float cabeeseSearchRadiusFtInMeters,
|
float cabeeseSearchRadiusFtInMeters,
|
||||||
bool trainBrakeDisplayShowsColorsInCalloutMode
|
bool trainBrakeDisplayShowsColorsInCalloutMode,
|
||||||
|
bool shiftPaginationOnContextMenu
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
WebhookSettingsList = webhookSettingsList;
|
WebhookSettingsList = webhookSettingsList;
|
||||||
@@ -42,9 +44,11 @@ public class Settings
|
|||||||
CabooseRequiredForLocoTagOilIndication = cabooseRequiredForLocoTagOilIndication;
|
CabooseRequiredForLocoTagOilIndication = cabooseRequiredForLocoTagOilIndication;
|
||||||
ServicingFundPenalty = servicingFundPenalty;
|
ServicingFundPenalty = servicingFundPenalty;
|
||||||
SafetyFirst = safetyFirst;
|
SafetyFirst = safetyFirst;
|
||||||
|
SafetyFirstClientEnforce = safetyFirstClientEnforce;
|
||||||
LoadCrewHoursMethod = loadCrewHoursMethod;
|
LoadCrewHoursMethod = loadCrewHoursMethod;
|
||||||
CabeeseSearchRadiusFtInMeters = cabeeseSearchRadiusFtInMeters;
|
CabeeseSearchRadiusFtInMeters = cabeeseSearchRadiusFtInMeters;
|
||||||
TrainBrakeDisplayShowsColorsInCalloutMode = trainBrakeDisplayShowsColorsInCalloutMode;
|
TrainBrakeDisplayShowsColorsInCalloutMode = trainBrakeDisplayShowsColorsInCalloutMode;
|
||||||
|
ShiftPaginationOnContextMenu = shiftPaginationOnContextMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly UIState<string> _selectedTabState = new UIState<string>(null);
|
public readonly UIState<string> _selectedTabState = new UIState<string>(null);
|
||||||
@@ -57,9 +61,11 @@ public class Settings
|
|||||||
public bool CabooseRequiredForLocoTagOilIndication;
|
public bool CabooseRequiredForLocoTagOilIndication;
|
||||||
public bool ServicingFundPenalty;
|
public bool ServicingFundPenalty;
|
||||||
public bool SafetyFirst;
|
public bool SafetyFirst;
|
||||||
|
public bool SafetyFirstClientEnforce;
|
||||||
public CrewHourLoadMethod LoadCrewHoursMethod;
|
public CrewHourLoadMethod LoadCrewHoursMethod;
|
||||||
public float CabeeseSearchRadiusFtInMeters;
|
public float CabeeseSearchRadiusFtInMeters;
|
||||||
public bool TrainBrakeDisplayShowsColorsInCalloutMode;
|
public bool TrainBrakeDisplayShowsColorsInCalloutMode;
|
||||||
|
public bool ShiftPaginationOnContextMenu;
|
||||||
|
|
||||||
internal void AddAnotherRow()
|
internal void AddAnotherRow()
|
||||||
{
|
{
|
||||||
@@ -136,9 +142,13 @@ public static class SettingsExtensions
|
|||||||
input?.settings?.ServicingFundPenalty ?? false;
|
input?.settings?.ServicingFundPenalty ?? false;
|
||||||
public static bool SafetyFirst(this TweaksAndThingsPlugin input) =>
|
public static bool SafetyFirst(this TweaksAndThingsPlugin input) =>
|
||||||
input?.settings?.SafetyFirst ?? false;
|
input?.settings?.SafetyFirst ?? false;
|
||||||
|
public static bool SafetyFirstClientEnforce(this TweaksAndThingsPlugin input) =>
|
||||||
|
input?.settings?.SafetyFirstClientEnforce ?? true;
|
||||||
public static bool DayLoadCrewHours(this TweaksAndThingsPlugin input) =>
|
public static bool DayLoadCrewHours(this TweaksAndThingsPlugin input) =>
|
||||||
(input?.settings?.LoadCrewHoursMethod ?? CrewHourLoadMethod.Tracks) == CrewHourLoadMethod.Daily;
|
(input?.settings?.LoadCrewHoursMethod ?? CrewHourLoadMethod.Tracks) == CrewHourLoadMethod.Daily;
|
||||||
public static bool TrainBrakeDisplayShowsColorsInCalloutMode(this TweaksAndThingsPlugin input) =>
|
public static bool TrainBrakeDisplayShowsColorsInCalloutMode(this TweaksAndThingsPlugin input) =>
|
||||||
input?.settings?.TrainBrakeDisplayShowsColorsInCalloutMode ?? false;
|
input?.settings?.TrainBrakeDisplayShowsColorsInCalloutMode ?? false;
|
||||||
|
public static bool ShiftForPagination(this TweaksAndThingsPlugin input) =>
|
||||||
|
input?.settings?.ShiftPaginationOnContextMenu ?? false;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -203,6 +203,23 @@ AutoHotboxSpotter Update: decrease the random wait from 30 - 300 seconds to 15 -
|
|||||||
).Tooltip("Safety First", $@"On non-express timetabled consists, a caboose is required in the consist increase AE max speed > 20 in {Enum.GetName(typeof(AutoEngineerMode), AutoEngineerMode.Road)}/{Enum.GetName(typeof(AutoEngineerMode), AutoEngineerMode.Waypoint)} mode.");
|
).Tooltip("Safety First", $@"On non-express timetabled consists, a caboose is required in the consist increase AE max speed > 20 in {Enum.GetName(typeof(AutoEngineerMode), AutoEngineerMode.Road)}/{Enum.GetName(typeof(AutoEngineerMode), AutoEngineerMode.Waypoint)} mode.");
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region SafetyFirstClient
|
||||||
|
if (settings?.SafetyFirst ?? false)
|
||||||
|
{
|
||||||
|
builder.Spacer(spacing);
|
||||||
|
builder.AddFieldToggle(
|
||||||
|
"Safety First! (Enforce Client Speed Restrictions)",
|
||||||
|
() => settings?.SafetyFirstClientEnforce ?? false,
|
||||||
|
delegate (bool enabled)
|
||||||
|
{
|
||||||
|
if (settings == null) settings = new();
|
||||||
|
settings.SafetyFirstClientEnforce = enabled;
|
||||||
|
builder.Rebuild();
|
||||||
|
}
|
||||||
|
).Tooltip("Safety First! (Enforce Client Speed Restrictions)", $@"Enforce cabeese dominance on clients; uncheck to allow clients to override the 20mph restriction.");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UiUpdates(UIPanelBuilder builder)
|
private void UiUpdates(UIPanelBuilder builder)
|
||||||
@@ -245,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.");
|
).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(
|
||||||
|
"Context Menu Shift Modifier",
|
||||||
|
() => this.ShiftForPagination(),
|
||||||
|
delegate (bool enabled)
|
||||||
|
{
|
||||||
|
if (settings == null) settings = new();
|
||||||
|
settings.ShiftPaginationOnContextMenu = enabled;
|
||||||
|
builder.Rebuild();
|
||||||
|
}
|
||||||
|
).Tooltip("Context Menu Shift Modifier", $@"When enabled/checked, utilizing `SHIFT` while initiating the context menu of a car will show consist level options, and without shows only car level. If this is unchecked, all car/consist options show up in a happy goulash!");
|
||||||
|
|
||||||
builder.Spacer(spacing);
|
builder.Spacer(spacing);
|
||||||
EngineRosterShowsFuelStatusUISection(builder);
|
EngineRosterShowsFuelStatusUISection(builder);
|
||||||
}
|
}
|
||||||
|
|||||||