Compare commits

..

9 Commits

7 changed files with 210 additions and 24 deletions

View File

@@ -12,7 +12,7 @@
<PropertyGroup Condition="'$(AssemblyVersion)' == '' OR '$(MajorVersion)' != '' OR '$(MinorVersion)' != ''">
<MajorVersion Condition="'$(MajorVersion)' == ''">0</MajorVersion>
<MinorVersion Condition="'$(MinorVersion)' == ''">1</MinorVersion>
<PatchVersion Condition="'$(PatchVersion)' == ''">6</PatchVersion>
<PatchVersion Condition="'$(PatchVersion)' == ''">8</PatchVersion>
<AssemblyVersion>$(MajorVersion).$(MinorVersion).$(PatchVersion)</AssemblyVersion>
<FileVersion>$(AssemblyVersion)</FileVersion>
<ProductVersion>$(AssemblyVersion)</ProductVersion>

View File

@@ -0,0 +1,93 @@
using Model.AI;
using System.Collections;
using UnityEngine;
namespace RMROC451.TweaksAndThings.Extensions
{
internal static class AutoEngineer_Extensions
{
private static float CabooseHalvedFloat(this float input, bool hasCaboose) =>
hasCaboose ? input / 2 : input;
private static float CabooseAutoOilerLimit(this bool hasCaboose) =>
hasCaboose ? 0.99f : AutoOiler.OilIfBelow;
public static IEnumerator MrocAutoOilerLoop(this AutoOiler oiler, Serilog.ILogger _log)
{
int originIndex = oiler.FindOriginIndex();
bool hasCaboose = oiler._cars.CabooseInConsist();
if (originIndex < 0)
{
_log.Error("Couldn't find origin car {car}", oiler._originCar);
oiler._coroutine = null;
yield break;
}
oiler._reverse = originIndex > oiler._cars.Count - originIndex;
_log.Information(
"AutoOiler {name} starting, rev = {reverse}, caboose halving adjustment = {hasCaboose}, oil limit = {limit}",
oiler.name,
oiler._reverse,
hasCaboose,
hasCaboose.CabooseAutoOilerLimit()
);
while (true)
{
yield return new WaitForSeconds(AutoOiler.StartDelay.CabooseHalvedFloat(hasCaboose));
int carIndex = originIndex;
float adjustedTimeToWalk = AutoOiler.TimeToWalkCar.CabooseHalvedFloat(hasCaboose);
do
{
if (oiler.TryGetCar(carIndex, out var car))
{
float num = 0f;
float origOil = car.Oiled;
if (car.NeedsOiling && car.Oiled < hasCaboose.CabooseAutoOilerLimit())
{
float num2 = 1f - car.Oiled;
car.OffsetOiled(num2);
float num3 = num2 * AutoOiler.TimeToFullyOil.CabooseHalvedFloat(hasCaboose);
num += num3;
oiler._pendingRunDuration += num3;
oiler._oiledCount++;
_log.Information("AutoOiler {name}: oiled {car} from {orig} => {new}", oiler.name, car, origOil, car.Oiled);
}
num += adjustedTimeToWalk;
oiler._pendingRunDuration += adjustedTimeToWalk;
yield return new WaitForSeconds(num);
}
carIndex = oiler.NextIndex(carIndex);
}
while (oiler.InBounds(carIndex));
oiler._reverse = !oiler._reverse;
oiler.PayWages();
}
}
public static IEnumerator MrocAutoHotboxSpotterLoop(this AutoHotboxSpotter spotter, Serilog.ILogger _log)
{
while (true)
{
bool hasCaboose = spotter._cars.CabooseInConsist();
if (!spotter.HasCars)
{
yield return new WaitForSeconds(1f);
continue;
}
_log.Information("AutoHotboxSpotter {name}: Hotbox Spotter Running, Has Caboose => {hasCaboose}; Has Cars {hasCars}", spotter.name, hasCaboose, spotter.HasCars);
spotter.CheckForHotbox();
while (spotter.HasCars)
{
int num = Random.Range(60, 300);
if (hasCaboose)
{
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}", spotter.name, numOrig, num);
}
yield return new WaitForSeconds(num);
spotter.CheckForHotbox();
}
}
}
}
}

View File

@@ -0,0 +1,26 @@
using HarmonyLib;
using Model.AI;
using Railloader;
using RMROC451.TweaksAndThings.Extensions;
using Serilog;
using System.Collections;
namespace RMROC451.TweaksAndThings.Patches;
[HarmonyPatch(typeof(AutoHotboxSpotter))]
[HarmonyPatch(nameof(AutoHotboxSpotter.SpotterLoop))]
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
internal class AutoHotboxSpotter_SpotterLoop_Patch
{
private static ILogger _log => Log.ForContext<AutoHotboxSpotter_SpotterLoop_Patch>();
public static bool Prefix(AutoHotboxSpotter __instance, ref IEnumerator __result)
{
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
if (!tweaksAndThings.IsEnabled) return true;
bool buttonsHaveCost = tweaksAndThings?.settings?.EndGearHelpersRequirePayment ?? false;
if (buttonsHaveCost) __result = __instance.MrocAutoHotboxSpotterLoop(_log);
return !buttonsHaveCost; //only hit this if !buttonsHaveCost, since Loop is a coroutine
}
}

View File

@@ -0,0 +1,26 @@
using HarmonyLib;
using Model.AI;
using Railloader;
using RMROC451.TweaksAndThings.Extensions;
using Serilog;
using System.Collections;
namespace RMROC451.TweaksAndThings.Patches;
[HarmonyPatch(typeof(AutoOiler))]
[HarmonyPatch(nameof(AutoOiler.Loop))]
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
internal class AutoOiler_Loop_Patch
{
private static ILogger _log => Log.ForContext<AutoOiler_Loop_Patch>();
public static bool Prefix(AutoOiler __instance, ref IEnumerator __result)
{
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
if (!tweaksAndThings.IsEnabled) return true;
bool buttonsHaveCost = tweaksAndThings?.settings?.EndGearHelpersRequirePayment ?? false;
if (buttonsHaveCost)__result = __instance.MrocAutoOilerLoop(_log);
return !buttonsHaveCost; //only hit this if !buttonsHaveCost, since Loop is a coroutine
}
}

View File

@@ -8,12 +8,14 @@ using Network;
using Railloader;
using RMROC451.TweaksAndThings.Enums;
using RMROC451.TweaksAndThings.Extensions;
using RollingStock;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using UI.Builder;
using UI.CarInspector;
using UI.ContextMenu;
using UI.Tags;
using static Model.Car;
@@ -24,6 +26,7 @@ namespace RMROC451.TweaksAndThings.Patches;
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
internal class CarInspector_PopulateCarPanel_Patch
{
private static ILogger _log => Log.ForContext<CarInspector_PopulateCarPanel_Patch>();
private static IEnumerable<LogicalEnd> ends = Enum.GetValues(typeof(LogicalEnd)).Cast<LogicalEnd>();
/// <summary>
@@ -70,7 +73,7 @@ internal class CarInspector_PopulateCarPanel_Patch
private static UIPanelBuilder AddCarConsistRebuildObservers(UIPanelBuilder builder, IEnumerable<Model.Car> consist)
{
TagController tagController = UnityEngine.Object.FindFirstObjectByType<TagController>();
foreach (Model.Car car in consist)
foreach (Model.Car car in consist.Where(c => c.Archetype != Model.Definition.CarArchetype.Tender))
{
builder = AddObserver(builder, car, PropertyChange.KeyForControl(PropertyChange.Control.Handbrake), tagController);
foreach (LogicalEnd logicalEnd in ends)
@@ -93,12 +96,13 @@ internal class CarInspector_PopulateCarPanel_Patch
{
try
{
tagController.UpdateTag(car, car.TagCallout, OpsController.Shared);
builder.Rebuild();
if (car.TagCallout != null) tagController.UpdateTags(CameraSelector.shared._currentCamera.GroundPosition, true); //tagController.UpdateTag(car, car.TagCallout, OpsController.Shared);
if (ContextMenu.IsShown && ContextMenu.Shared.centerLabel.text == car.DisplayName) CarPickable.HandleShowContextMenu(car);
}
catch(Exception ex)
{
Log.Warning(ex, $"{nameof(AddObserver)} {car} Exception logged for {key}");
_log.ForContext("car", car).Warning(ex, $"{nameof(AddObserver)} {car} Exception logged for {key}");
}
},
false
@@ -122,7 +126,7 @@ internal class CarInspector_PopulateCarPanel_Patch
{
TrainController tc = UnityEngine.Object.FindObjectOfType<TrainController>();
IEnumerable<Model.Car> consist = car.EnumerateCoupled(LogicalEnd.A);
//Log.Information($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
_log.ForContext("car", car).Verbose($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
CalculateCostIfEnabled(car, mrocHelperType, buttonsHaveCost, consist);
@@ -136,7 +140,6 @@ internal class CarInspector_PopulateCarPanel_Patch
else
{
consist = consist.Where(c => c is not BaseLocomotive && c.Archetype != Model.Definition.CarArchetype.Tender);
Log.Information($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
//when ApplyHandbrakesAsNeeded is called, and the consist contains an engine, it stops applying brakes.
tc.ApplyHandbrakesAsNeeded(consist.ToList(), PlaceTrainHandbrakes.Automatic);
}
@@ -163,7 +166,7 @@ internal class CarInspector_PopulateCarPanel_Patch
case MrocHelperType.BleedAirSystem:
consist = consist.Where(c => c.NotMotivePower());
Log.Information($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
_log.ForContext("car", car).Information($"{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));
@@ -184,12 +187,12 @@ internal class CarInspector_PopulateCarPanel_Patch
if (cabooseWithAvailCrew == null) timeCost *= 1.5f;
var cabooseFoundDisplay = cabooseWithAvailCrew?.DisplayName ?? "No caboose";
Log.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).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)");
Multiplayer.SendError(StateManager.Shared._playersManager.LocalPlayer, $"{(cabooseWithAvailCrew != null ? $"{cabooseWithAvailCrew.DisplayName} Hours Adjusted: ({tsString})\n" : string.Empty)}Wages: ~(${Math.Ceiling((decimal)(timeCost / 3600) * 5)})");
if (buttonsHaveCost) StateManager_OnDayDidChange_Patch.UnbilledAutoBrakeCrewRunDuration += timeCost;
StateManager_OnDayDidChange_Patch.UnbilledAutoBrakeCrewRunDuration += timeCost;
}
}

View File

@@ -0,0 +1,51 @@
using HarmonyLib;
using Model;
using Railloader;
using RMROC451.TweaksAndThings.Enums;
using RMROC451.TweaksAndThings.Extensions;
using RollingStock;
using System.Linq;
using UI;
using UI.ContextMenu;
using static Model.Car;
namespace RMROC451.TweaksAndThings.Patches;
[HarmonyPatch(typeof(CarPickable))]
[HarmonyPatch(nameof(CarPickable.HandleShowContextMenu), typeof(Car))]
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
internal class CarPickable_HandleShowContextMenu_Patch
{
private static void Postfix(Car car)
{
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
if (!tweaksAndThings.IsEnabled) return;
bool buttonsHaveCost = tweaksAndThings?.settings?.EndGearHelpersRequirePayment ?? false;
ContextMenu shared = ContextMenu.Shared;
var consist = car.EnumerateCoupled(LogicalEnd.A);
shared.AddButton(ContextMenuQuadrant.Unused2, $"{(consist.Any(c => c.HandbrakeApplied()) ? "Release " : "Set ")} Consist", SpriteName.Handbrake, delegate
{
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Handbrake, buttonsHaveCost);
});
if (consist.Any(c => c.EndAirSystemIssue()))
{
shared.AddButton(ContextMenuQuadrant.Unused2, $"Air Up Consist", SpriteName.Select, delegate
{
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.GladhandAndAnglecock, buttonsHaveCost);
});
}
if (consist.Any(c => c.SupportsBleed()))
{
shared.AddButton(ContextMenuQuadrant.Unused2, $"Bleed Consist", SpriteName.Bleed, delegate
{
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.BleedAirSystem, buttonsHaveCost);
});
}
shared.BuildItemAngles();
shared.StartCoroutine(shared.AnimateButtonsShown());
}
}

View File

@@ -3,9 +3,7 @@ using Model;
using Model.OpsNew;
using Railloader;
using RMROC451.TweaksAndThings.Extensions;
using UI;
using UI.Tags;
using UnityEngine;
namespace RMROC451.TweaksAndThings.Patches;
@@ -19,7 +17,6 @@ internal class TagController_UpdateTag_Patch
private static void Postfix(Car car, TagCallout tagCallout)
{
TagController tagController = UnityEngine.Object.FindObjectOfType<TagController>();
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
if (!tweaksAndThings.IsEnabled || !tweaksAndThings.settings.HandBrakeAndAirTagModifiers)
@@ -27,24 +24,14 @@ internal class TagController_UpdateTag_Patch
return;
}
ProceedWithPostFix(car, tagCallout, tagController);
ProceedWithPostFix(car, tagCallout);
return;
}
private static void ProceedWithPostFix(Car car, TagCallout tagCallout, TagController tagController)
private static void ProceedWithPostFix(Car car, TagCallout tagCallout)
{
bool isAltDownWithCarIssue = GameInput.IsAltDown && car.CarOrEndGearIssue();
tagCallout.callout.Title = string.Format(tagTitleFormat, "{0}", car.DisplayName);
tagCallout.gameObject.SetActive(
tagCallout.gameObject.activeSelf &&
(!GameInput.IsAltDown || isAltDownWithCarIssue)
);
if (tagCallout.gameObject.activeSelf && isAltDownWithCarIssue)
{
tagController.ApplyImageColor(tagCallout, Color.black);
}
tagCallout.callout.Title =
(car.CarAndEndGearIssue(), car.EndAirSystemIssue(), car.HandbrakeApplied()) switch