Compare commits

..

5 Commits

6 changed files with 119 additions and 31 deletions

View File

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

View File

@@ -58,10 +58,10 @@ public static class Car_Extensions
public static bool CabooseInConsist(this IEnumerable<Car> input) => input.FirstOrDefault(c => c.IsCaboose()); public static bool CabooseInConsist(this IEnumerable<Car> input) => input.FirstOrDefault(c => c.IsCaboose());
public static Car? CabooseWithSufficientCrewHours(this Car car, float timeNeeded, bool decrement = false) public static Car? CabooseWithSufficientCrewHours(this Car car, float timeNeeded, HashSet<string> carIdsCheckedAlready, bool decrement = false)
{ {
Car? output = null; Car? output = null;
if (!car.IsCaboose()) return null; if (carIdsCheckedAlready.Contains(car.id) || !car.IsCaboose()) return null;
List<LoadSlot> loadSlots = car.Definition.LoadSlots; List<LoadSlot> loadSlots = car.Definition.LoadSlots;
for (int i = 0; i < loadSlots.Count; i++) for (int i = 0; i < loadSlots.Count; i++)
@@ -78,33 +78,44 @@ public static class Car_Extensions
return output; return output;
} }
public static Car? HuntingForCabeeseNearCar(this Car car, float timeNeeded, TrainController tc, bool decrement = false) public static Car? HuntingForCabeeseNearCar(this Car car, float timeNeeded, TrainController tc, HashSet<string> carIdsCheckedAlready, bool decrement = false)
{
List<(string carId, float distance)> source =
CarsNearCurrentCar(car, timeNeeded, tc, carIdsCheckedAlready, decrement);
Car output = FindNearestCabooseFromNearbyCars(tc, source);
if (output != null) output.CabooseWithSufficientCrewHours(timeNeeded, carIdsCheckedAlready, decrement);
return output;
}
private static Car FindNearestCabooseFromNearbyCars(TrainController tc, List<(string carId, float distance)> source) =>
(
from t in source
where t.distance < 21f //todo: add setting slider for catchment
orderby t.distance ascending
select tc.CarForId(t.carId)
).FirstOrDefault();
private static List<(string carId, float distance)> CarsNearCurrentCar(Car car, float timeNeeded, TrainController tc, HashSet<string> carIdsCheckedAlready, bool decrement)
{ {
Vector3 position = car.GetMotionSnapshot().Position; Vector3 position = car.GetMotionSnapshot().Position;
Vector3 center = WorldTransformer.WorldToGame(position); Vector3 center = WorldTransformer.WorldToGame(position);
Rect rect = new Rect(new Vector2(center.x - 30f, center.z - 30f), Vector2.one * 30f * 2f); Rect rect = new Rect(new Vector2(center.x - 30f, center.z - 30f), Vector2.one * 30f * 2f);
var cars = tc.CarIdsInRect(rect); var cars = tc.CarIdsInRect(rect);
Log.Information($"{nameof(HuntingForCabeeseNearCar)} => {cars.Count()}"); Log.Information($"{nameof(HuntingForCabeeseNearCar)} => {cars.Count()}");
bool decrementedAlready = false; List<(string carId, float distance)> source =
List<(string carId, float distance)> source = cars.Select(carId => cars
.Select(carId =>
{ {
Car car = tc.CarForId(carId); Car car = tc.CarForId(carId);
if (car == null || !car.CabooseWithSufficientCrewHours(timeNeeded, decrement && !decrementedAlready)) if (car == null || !car.CabooseWithSufficientCrewHours(timeNeeded, carIdsCheckedAlready))
{ {
return (carId: carId, distance: 1000f); return (carId: carId, distance: 1000f);
} }
decrementedAlready = true;
Vector3 a = WorldTransformer.WorldToGame(car.GetMotionSnapshot().Position); Vector3 a = WorldTransformer.WorldToGame(car.GetMotionSnapshot().Position);
return (carId: carId, distance: Vector3.Distance(a, center)); return (carId: carId, distance: Vector3.Distance(a, center));
}).ToList(); }).ToList();
return source;
Car? output =
(from t in source
where t.distance < 21f
orderby t.distance ascending
select tc.CarForId(t.carId)
).FirstOrDefault();
return output;
} }
} }

View File

@@ -8,12 +8,14 @@ using Network;
using Railloader; using Railloader;
using RMROC451.TweaksAndThings.Enums; using RMROC451.TweaksAndThings.Enums;
using RMROC451.TweaksAndThings.Extensions; using RMROC451.TweaksAndThings.Extensions;
using RollingStock;
using Serilog; using Serilog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UI.Builder; using UI.Builder;
using UI.CarInspector; using UI.CarInspector;
using UI.ContextMenu;
using UI.Tags; using UI.Tags;
using static Model.Car; using static Model.Car;
@@ -70,7 +72,7 @@ internal class CarInspector_PopulateCarPanel_Patch
private static UIPanelBuilder AddCarConsistRebuildObservers(UIPanelBuilder builder, IEnumerable<Model.Car> consist) private static UIPanelBuilder AddCarConsistRebuildObservers(UIPanelBuilder builder, IEnumerable<Model.Car> consist)
{ {
TagController tagController = UnityEngine.Object.FindFirstObjectByType<TagController>(); 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); builder = AddObserver(builder, car, PropertyChange.KeyForControl(PropertyChange.Control.Handbrake), tagController);
foreach (LogicalEnd logicalEnd in ends) foreach (LogicalEnd logicalEnd in ends)
@@ -93,7 +95,8 @@ internal class CarInspector_PopulateCarPanel_Patch
{ {
try try
{ {
tagController.UpdateTag(car, car.TagCallout, OpsController.Shared); if (car.TagCallout != null) tagController.UpdateTag(car, car.TagCallout, OpsController.Shared);
if (ContextMenu.IsShown && ContextMenu.Shared.centerLabel.text == car.DisplayName) CarPickable.HandleShowContextMenu(car);
builder.Rebuild(); builder.Rebuild();
} }
catch(Exception ex) catch(Exception ex)
@@ -195,20 +198,24 @@ internal class CarInspector_PopulateCarPanel_Patch
public static Car? NearbyCabooseWithAvailableCrew(Car car, float timeNeeded, bool decrement = false) public static Car? NearbyCabooseWithAvailableCrew(Car car, float timeNeeded, bool decrement = false)
{ {
HashSet<string> carIdsCheckedAlready = new();
//check current car. //check current car.
Car? output = car.CabooseWithSufficientCrewHours(timeNeeded, decrement); Car? output = car.CabooseWithSufficientCrewHours(timeNeeded, carIdsCheckedAlready, decrement);
if (output != null) return output; //short out if we are good if (output != null) return output; //short out if we are good
carIdsCheckedAlready.Add(car.id);
//check consist, for cabeese //check consist, for cabeese
IEnumerable<Car> consist = car.EnumerateCoupled(LogicalEnd.A); IEnumerable<Car> consist = car.EnumerateCoupled(LogicalEnd.A);
output = consist.FirstOrDefault(c => c.CabooseWithSufficientCrewHours(timeNeeded, decrement)); output = consist.FirstOrDefault(c => c.CabooseWithSufficientCrewHours(timeNeeded, carIdsCheckedAlready, decrement));
if (output != null) return output; //short out if we are good if (output != null) return output; //short out if we are good
carIdsCheckedAlready.UnionWith(consist.Select(c => c.id));
//then check near consist cars for cabeese //then check near consist cars for cabeese
TrainController tc = UnityEngine.Object.FindObjectOfType<TrainController>(); TrainController tc = UnityEngine.Object.FindObjectOfType<TrainController>();
foreach (var c in consist) foreach (var c in consist)
{ {
output = c.HuntingForCabeeseNearCar(timeNeeded, tc, decrement); output = c.HuntingForCabeeseNearCar(timeNeeded, tc, carIdsCheckedAlready, decrement);
if (output != null) return output; //short out if we are good if (output != null) return output; //short out if we are good
} }

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

@@ -34,7 +34,7 @@ public class Settings
internal void AddAnotherRow() internal void AddAnotherRow()
{ {
WebhookSettingsList = !WebhookSettingsList?.Any() ?? false ? new[] { new WebhookSettings() }.ToList() : new List<WebhookSettings>(); WebhookSettingsList ??= new[] { new WebhookSettings() }.ToList();
if (!string.IsNullOrEmpty(WebhookSettingsList.OrderByDescending(wsl => wsl.WebhookUrl).Last().WebhookUrl)) if (!string.IsNullOrEmpty(WebhookSettingsList.OrderByDescending(wsl => wsl.WebhookUrl).Last().WebhookUrl))
{ {
WebhookSettingsList.Add(new()); WebhookSettingsList.Add(new());
@@ -77,3 +77,18 @@ public class RosterFuelColumnSettings
public bool EngineRosterShowsFuelStatusAlways; public bool EngineRosterShowsFuelStatusAlways;
public EngineRosterFuelDisplayColumn EngineRosterFuelStatusColumn; public EngineRosterFuelDisplayColumn EngineRosterFuelStatusColumn;
} }
public static class SettingsExtensions
{
public static List<WebhookSettings> SanitizeEmptySettings(this IEnumerable<WebhookSettings>? settings)
{
List<WebhookSettings> output =
settings?.Where(s => !string.IsNullOrEmpty(s.WebhookUrl))?.ToList() ??
new();
output.Add(new());
return output;
}
}

View File

@@ -78,6 +78,10 @@ public class TweaksAndThingsPlugin : SingletonPluginBase<TweaksAndThingsPlugin>,
if (!settings?.WebhookSettingsList?.Any() ?? true) settings.WebhookSettingsList = new[] { new WebhookSettings() }.ToList(); if (!settings?.WebhookSettingsList?.Any() ?? true) settings.WebhookSettingsList = new[] { new WebhookSettings() }.ToList();
if (settings?.EngineRosterFuelColumnSettings == null) settings.EngineRosterFuelColumnSettings = new(); if (settings?.EngineRosterFuelColumnSettings == null) settings.EngineRosterFuelColumnSettings = new();
settings.WebhookSettingsList =
settings?.WebhookSettingsList.SanitizeEmptySettings();
//WebhookUISection(ref builder); //WebhookUISection(ref builder);
//builder.AddExpandingVerticalSpacer(); //builder.AddExpandingVerticalSpacer();
WebhooksListUISection(ref builder); WebhooksListUISection(ref builder);