initial tinkerings

This commit is contained in:
2024-06-16 15:10:54 -05:00
parent a057626c0c
commit b1cb852cb1
14 changed files with 1193 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
{
"manifestVersion": 1,
"id": "RMROC451.TweaksAndThings",
"name": "RMROC451's Tweaks and Things",
"version": "$(AssemblyVersion)",
"requires": [
{
"id": "railloader",
"notBefore": "1.8.1"
}
],
"assemblies": [ "RMROC451.TweaksAndThings" ]
}

View File

@@ -0,0 +1,7 @@
namespace TweaksAndThings.Enums;
public enum MrocHelperType
{
Handbrake,
GladhandAndAnglecock
}

View File

@@ -0,0 +1,100 @@
using GalaSoft.MvvmLight.Messaging;
using Game;
using Game.Events;
using Game.Messages;
using Game.State;
using HarmonyLib;
using KeyValue.Runtime;
using Network;
using Network.Messages;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Railloader;
using Serilog;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using TweaksAndThings.Enums;
using UI.Builder;
using UI.CarInspector;
using WorldStreamer2;
using static Model.Car;
using static Unity.IO.LowLevel.Unsafe.AsyncReadManagerMetrics;
namespace TweaksAndThings.Patches;
[HarmonyPatch(typeof(CarInspector))]
[HarmonyPatch(nameof(CarInspector.PopulateCarPanel), typeof(UIPanelBuilder))]
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
public class CarInspector_PopulateCarPanel_Patch
{
private static IEnumerable<LogicalEnd> ends = Enum.GetValues(typeof(LogicalEnd)).Cast<LogicalEnd>();
/// <summary>
/// If a caboose inspector is opened, it will auto set Anglecocks, gladhands and handbrakes
/// </summary>
/// <param name="__instance"></param>
/// <param name="builder"></param>
/// <returns></returns>
private static bool Prefix(CarInspector __instance, UIPanelBuilder builder)
{
TweaksAndThings tweaksAndThings = SingletonPluginBase<TweaksAndThings>.Shared;
if (!tweaksAndThings.IsEnabled) return true;
builder.HStack(delegate (UIPanelBuilder hstack)
{
hstack.AddButtonCompact("Handbrakes", delegate
{
MrocConsistHelper(__instance._car, MrocHelperType.Handbrake);
}).Tooltip("Release Consist Handbrakes", "Iterates over each car in this consist and releases handbrakes.");
if (StateManager.IsHost || true)
{
hstack.AddButtonCompact("Air Lines", delegate
{
MrocConsistHelper(__instance._car, MrocHelperType.GladhandAndAnglecock);
}).Tooltip("Connect Consist Air Lines", "Iterates over each car in this consist and connects gladhands and opens anglecocks.");
}
});
return true;
}
public static void MrocConsistHelper(Model.Car car, MrocHelperType mrocHelperType)
{
IEnumerable<Model.Car> consist = car.EnumerateCoupled(LogicalEnd.A);
Log.Information($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
switch (mrocHelperType)
{
case MrocHelperType.Handbrake:
consist.Do(c => c.SetHandbrake(false));
break;
case MrocHelperType.GladhandAndAnglecock:
consist.Do(c =>
ends.Do(end =>
{
EndGear endGear = c[end];
StateManager.ApplyLocal(
new PropertyChange(
c.id,
KeyValueKeyFor(EndGearStateKey.Anglecock, c.LogicalToEnd(end)),
new FloatPropertyValue(endGear.IsCoupled ? 1f : 0f)
)
);
if (c.TryGetAdjacentCar(end, out Model.Car c2))
{
StateManager.ApplyLocal(new SetGladhandsConnected(c.id, c2.id, true));
}
})
);
break;
}
}
}

View File

@@ -0,0 +1,114 @@
using Game;
using Game.State;
using HarmonyLib;
using Helpers;
using Newtonsoft.Json;
using Railloader;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using Track.Signals.Panel;
using UI.Console;
namespace TweaksAndThings.Patches;
[HarmonyPatch(typeof(ExpandedConsole))]
[HarmonyPatch(nameof(ExpandedConsole.Add))]
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
public class ExpandedConsole_Add_Patch
{
private static void Prefix(ref UI.Console.Console.Entry entry)
{
entry.Text = $"{entry.Timestamp} : {entry.Text}";
entry.Timestamp = RealNow();
SendMs(ref entry);
}
static void SendMs(ref UI.Console.Console.Entry entry)
{
try
{
TweaksAndThings tweaksAndThings = SingletonPluginBase<TweaksAndThings>.Shared;
StateManager shared = StateManager.Shared;
GameStorage gameStorage = shared.Storage;
WebhookSettings settings = tweaksAndThings.settings.WebhookSettingsList.FirstOrDefault(ws => ws.RailroadMark == gameStorage.RailroadMark);
Log.Information(entry.Text);
if (
settings != null &&
settings.WebhookEnabled &&
!string.IsNullOrEmpty(settings.WebhookUrl) &&
settings.RailroadMark == gameStorage.RailroadMark
)
{
var t = new Regex("car:(.*)\"");
var carId = t.IsMatch(entry.Text) ? Regex.Match(entry.Text, "car:(.*?)\"").Groups[1].Captures[0].ToString() : string.Empty;
Model.Car? car = TrainController.Shared.CarForString(carId);
Log.Information($"|{carId}| {car?.IsLocomotive}");
bool engineInMessage = car?.IsLocomotive ?? false;
var image = engineInMessage ?
new
{
url = string.Empty
} :
null;
if (engineInMessage)
{
CTCPanelMarkerManager cTCPanelMarkerManager = UnityEngine.Object.FindObjectOfType<CTCPanelMarkerManager>();
CTCPanelMarker marker = cTCPanelMarkerManager?._markers?.Values?.FirstOrDefault(v => v.TooltipInfo.Text.Contains(car.Ident.RoadNumber));
string color = CTCPanelMarker.InferColorFromText(car?.DisplayName).HexString().Replace("#", string.Empty);
if (marker != null)
{
color = CTCPanelMarker.InferColorFromText(marker.TooltipInfo.Text).HexString().Replace("#", string.Empty);
}
image = new
{
url = $"https://img.shields.io/badge/{car.DisplayName.Replace(" ", "%20")}-%20-{color}.png"
};
}
var SuccessWebHook = new
{
username = $"[{gameStorage.RailroadMark}] {gameStorage.RailroadName}",
embeds = new List<object>
{
new
{
description= Regex.Replace(entry.Text, "<.*?>", "").Replace(": ", "\n"),
timestamp=DateTime.UtcNow,
image
},
}
};
string EndPoint = settings.WebhookUrl;
Log.Information(JsonConvert.SerializeObject(SuccessWebHook));
var content = new StringContent(JsonConvert.SerializeObject(SuccessWebHook), Encoding.UTF8, "application/json");
tweaksAndThings.Client.PostAsync(EndPoint, content).Wait();
}
}
catch (Exception ex)
{
Log.Error(ex, ex.Message);
entry.Text += ex.ToString();
}
}
public static GameDateTime RealNow()
{
var now = DateTime.Now;
return new GameDateTime(0, now.Hour + now.Minute / 60f);
}
}

View File

@@ -0,0 +1,85 @@
using HarmonyLib;
using JetBrains.Annotations;
using Model;
using Model.AI;
using Model.OpsNew;
using Railloader;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Track;
using TweaksAndThings;
using UI;
using UI.Builder;
using UI.CarInspector;
using UI.Tags;
using UnityEngine;
using static Model.Car;
using tat = TweaksAndThings.TweaksAndThings;
namespace TweaksAndThings.Patches;
[HarmonyPatch(typeof(TagController))]
[HarmonyPatch(nameof(TagController.UpdateTag), typeof(Car), typeof(TagCallout), typeof(OpsController))]
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
public class TagConroller_UpdateTag_Patch
{
private static void Postfix(Car car, TagCallout tagCallout)
{
TagController tagController = UnityEngine.Object.FindObjectOfType<TagController>();
TweaksAndThings tweaksAndThings = SingletonPluginBase<TweaksAndThings>.Shared;
tagCallout.callout.Title = $"<align=left>{car.DisplayName}<line-height=0>";
if (!tweaksAndThings.IsEnabled || !tweaksAndThings.settings.HandBrakeAndAirTagModifiers)
{
return;
}
tagCallout.gameObject.SetActive(
tagCallout.gameObject.activeSelf &&
(!GameInput.IsShiftDown || (GameInput.IsShiftDown && car.CarOrEndGearIssue()))
);
if (tagCallout.gameObject.activeSelf && GameInput.IsShiftDown && car.CarOrEndGearIssue()) {
tagController.ApplyImageColor(tagCallout, Color.black);
}
if (car.CarAndEndGearIssue())
{
tagCallout.callout.Title =
$"{tagCallout.callout.Title}\n<align=\"right\">{TextSprites.CycleWaybills}{TextSprites.HandbrakeWheel}";
}
else if (car.EndAirSystemIssue())
tagCallout.callout.Title =
$"{tagCallout.callout.Title}\n<align=\"right\">{TextSprites.CycleWaybills}";
else if (car.HandbrakeApplied())
tagCallout.callout.Title =
$"{tagCallout.callout.Title}\n<align=\"right\">{TextSprites.HandbrakeWheel}";
return;
}
}
public static class ModelCarExtensions
{
public static bool EndAirSystemIssue(this Model.Car car)
{
bool AEndAirSystemIssue = car[Car.LogicalEnd.A].IsCoupled && !car[Car.LogicalEnd.A].IsAirConnectedAndOpen;
bool BEndAirSystemIssue = car[Car.LogicalEnd.B].IsCoupled && !car[Car.LogicalEnd.B].IsAirConnectedAndOpen;
bool EndAirSystemIssue = AEndAirSystemIssue || BEndAirSystemIssue;
return EndAirSystemIssue;
}
public static bool HandbrakeApplied(this Model.Car car) =>
car.air.handbrakeApplied;
public static bool CarOrEndGearIssue(this Model.Car car) =>
car.EndAirSystemIssue() || car.HandbrakeApplied();
public static bool CarAndEndGearIssue(this Model.Car car) =>
car.EndAirSystemIssue() && car.HandbrakeApplied();
}

View File

@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Optionally, set a few things to your liking -->
<!-- <MajorVersion>1</MajorVersion> -->
<!-- <MinorVersion>0</MinorVersion> -->
</PropertyGroup>
<ItemGroup>
<GameAssembly Include="Assembly-CSharp" />
<GameAssembly Include="Railloader.Interchange" />
<GameAssembly Include="Serilog" />
<GameAssembly Include="0Harmony" />
<GameAssembly Include="KeyValue.Runtime" />
<GameAssembly Include="Definition" />
<GameAssembly Include="UnityEngine.CoreModule" />
<GameAssembly Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Krafs.Publicizer" Version="2.2.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<Publicize Include="Assembly-CSharp" />
</ItemGroup>
<ItemGroup>
<Reference Include="ForYourConvenience">
<HintPath>D:\SteamLibrary\steamapps\common\Railroader\Mods\ForYourConvenience\ForYourConvenience.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,53 @@
using Newtonsoft.Json;
using System.IO;
using System.Runtime;
using System;
using Serilog;
using System.Collections.Generic;
using System.Linq;
namespace TweaksAndThings;
public class Settings
{
public Settings()
{}
public Settings(
WebhookSettings webhookSettings,
List<WebhookSettings> webhookSettingsList,
bool handBrakeAndAirTagModifiers
)
{
this.WebhookSettingsList = webhookSettingsList;
this.HandBrakeAndAirTagModifiers = handBrakeAndAirTagModifiers;
}
public List<WebhookSettings> WebhookSettingsList;
public bool HandBrakeAndAirTagModifiers;
internal void AddAnotherRow()
{
//if (!string.IsNullOrEmpty(WebhookSettingsList.Last().WebhookUrl)) WebhookSettingsList.Add(new());
}
}
public class WebhookSettings
{
public WebhookSettings() { }
public WebhookSettings(
bool webhookEnabled,
string railroadMark,
string webhookUrl
)
{
this.WebhookEnabled = webhookEnabled;
this.RailroadMark = railroadMark;
this.WebhookUrl = webhookUrl;
}
public bool WebhookEnabled = false;
public string RailroadMark = string.Empty;
public string WebhookUrl = string.Empty;
}

View File

@@ -0,0 +1,166 @@
using GalaSoft.MvvmLight.Messaging;
using Game.Messages;
using Game.State;
using HarmonyLib;
using Newtonsoft.Json.Linq;
using Railloader;
using Serilog;
using Serilog.Debugging;
using System.Linq;
using System.Net.Http;
using TweaksAndThings.Commands;
using UI.Builder;
using UI.CarInspector;
namespace TweaksAndThings
{
public class TweaksAndThings : SingletonPluginBase<TweaksAndThings>, IUpdateHandler, IModTabHandler
{
private HttpClient client;
internal HttpClient Client
{
get
{
if (client == null)
client = new HttpClient();
return client;
}
}
internal Settings? settings { get; private set; } = null;
readonly ILogger logger = Log.ForContext<TweaksAndThings>();
IModdingContext moddingContext { get; set; }
IModDefinition modDefinition { get; set; }
static TweaksAndThings()
{
Log.Information("Hello! Static Constructor was called!");
}
public TweaksAndThings(IModdingContext moddingContext, IModDefinition self)
{
this.modDefinition = self;
this.moddingContext = moddingContext;
logger.Information("Hello! Constructor was called for {modId}/{modVersion}!", self.Id, self.Version);
//moddingContext.RegisterConsoleCommand(new EchoCommand());
settings = moddingContext.LoadSettingsData<Settings>(self.Id);
}
public override void OnEnable()
{
logger.Information("OnEnable() was called!");
var harmony = new Harmony(modDefinition.Id);
harmony.PatchCategory(modDefinition.Id.Replace(".",string.Empty));
}
public override void OnDisable()
{
var harmony = new Harmony(modDefinition.Id);
harmony.UnpatchAll(modDefinition.Id);
Messenger.Default.Unregister(this);
}
public void Update()
{
logger.Verbose("UPDATE()");
}
public void ModTabDidOpen(UIPanelBuilder builder)
{
logger.Information("Daytime!");
//WebhookUISection(ref builder);
//builder.AddExpandingVerticalSpacer();
WebhooksListUISection(ref builder);
builder.AddExpandingVerticalSpacer();
HandbrakesAndAnglecocksUISection(ref builder);
}
private void HandbrakesAndAnglecocksUISection(ref UIPanelBuilder builder)
{
builder.AddSection("Tag Callout Handbrake and Air System Helper", delegate (UIPanelBuilder builder)
{
builder.AddField(
"Enable Tag Updates",
builder.AddToggle(
() => settings?.HandBrakeAndAirTagModifiers ?? false,
delegate (bool enabled)
{
if (settings == null) settings = new() { WebhookSettingsList = new[] { new WebhookSettings() }.ToList() };
settings.HandBrakeAndAirTagModifiers = enabled;
builder.Rebuild();
}
)
).Tooltip("Enable Tag Updates", $"Will add {TextSprites.CycleWaybills} to the car tag title having Air System issues. Also prepends {TextSprites.HandbrakeWheel} if there is a handbrake set.\n\nHolding Shift while tags are displayed only shows tag titles that have issues.");
});
}
private void WebhooksListUISection(ref UIPanelBuilder builder)
{
builder.AddSection("Webhooks List", delegate (UIPanelBuilder builder)
{
for (int i = 1; i <= settings.WebhookSettingsList.Count; i++)
{
int z = i - 1;
builder.AddSection($"Webhook {i}", delegate (UIPanelBuilder builder)
{
builder.AddField(
"Webhook Enabled",
builder.AddToggle(
() => settings?.WebhookSettingsList[z]?.WebhookEnabled ?? false,
delegate (bool enabled)
{
if (settings == null) settings = new() { WebhookSettingsList = new[] { new WebhookSettings() }.ToList() };
settings.WebhookSettingsList[z].WebhookEnabled = enabled;
settings.AddAnotherRow();
builder.Rebuild();
}
)
).Tooltip("Webhook Enabled", "Will parse the console messages and transmit to a Discord webhook.");
builder.AddField(
"Reporting Mark",
builder.HStack(delegate (UIPanelBuilder field)
{
field.AddInputField(
settings?.WebhookSettingsList[z]?.RailroadMark,
delegate (string railroadMark)
{
if (settings == null) settings = new() { WebhookSettingsList = new[] { new WebhookSettings() }.ToList() };
settings.WebhookSettingsList[z].RailroadMark = railroadMark;
settings.AddAnotherRow();
builder.Rebuild();
}, characterLimit: GameStorage.ReportingMarkMaxLength).FlexibleWidth();
})
).Tooltip("Reporting Mark", "Reporting mark of the company this Discord webhook applies to..");
builder.AddField(
"Webhook Url",
builder.HStack(delegate (UIPanelBuilder field)
{
field.AddInputField(
settings?.WebhookSettingsList[z]?.WebhookUrl,
delegate (string webhookUrl)
{
if (settings == null) settings = new() { WebhookSettingsList = new[] { new WebhookSettings() }.ToList() };
settings.WebhookSettingsList[z].WebhookUrl = webhookUrl;
settings.AddAnotherRow();
builder.Rebuild();
}).FlexibleWidth();
})
).Tooltip("Webhook Url", "Url of Discord webhook to publish messages to.");
});
}
});
}
public void ModTabDidClose()
{
logger.Information("Nighttime...");
this.moddingContext.SaveSettingsData(this.modDefinition.Id, settings ?? new());
}
}
}