From 347cfe6423010f8a324cba0592554902ea03d6c0 Mon Sep 17 00:00:00 2001 From: erik Date: Tue, 29 Apr 2025 09:58:25 +0200 Subject: [PATCH] New vtank control --- MosswartMassacre/MosswartMassacre.csproj | 7 +- MosswartMassacre/PluginCore.cs | 12 ++- MosswartMassacre/Telemetry.cs | 4 +- MosswartMassacre/VtankControl.cs | 108 +++++++++++++++++++++ MosswartMassacre/vTank.cs | 116 +++++++++++++++++++++++ 5 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 MosswartMassacre/VtankControl.cs create mode 100644 MosswartMassacre/vTank.cs diff --git a/MosswartMassacre/MosswartMassacre.csproj b/MosswartMassacre/MosswartMassacre.csproj index 6bdba56..ab9bb54 100644 --- a/MosswartMassacre/MosswartMassacre.csproj +++ b/MosswartMassacre/MosswartMassacre.csproj @@ -10,7 +10,7 @@ MosswartMassacre MosswartMassacre v4.8 - 8.0 + 8.0 512 true @@ -38,6 +38,9 @@ lib\Decal.Adapter.dll False + + lib\utank2-i.dll + False False @@ -70,6 +73,8 @@ + + diff --git a/MosswartMassacre/PluginCore.cs b/MosswartMassacre/PluginCore.cs index 6d1b035..4bc0c14 100644 --- a/MosswartMassacre/PluginCore.cs +++ b/MosswartMassacre/PluginCore.cs @@ -34,7 +34,7 @@ namespace MosswartMassacre try { MyHost = Host; - + WriteToChat("Mosswart Massacre has started!"); // Subscribe to chat message event @@ -52,6 +52,8 @@ namespace MosswartMassacre // Enable TLS1.2 ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; + //Enable vTank interface + vTank.Enable(); } catch (Exception ex) { @@ -82,6 +84,9 @@ namespace MosswartMassacre // Clean up the view MainView.ViewDestroy(); + //Disable vtank interface + vTank.Disable(); + MyHost = null; } catch (Exception ex) @@ -409,6 +414,7 @@ namespace MosswartMassacre WriteToChat("/mm meta - Toggle rare meta state"); WriteToChat("/mm http - Local http-command server enable|disable"); WriteToChat("/mm remotecommand - Listen to allegiance !do/!dot enable|disable"); + WriteToChat("/mm getmetastate - Gets the current metastate"); break; case "report": @@ -416,6 +422,10 @@ namespace MosswartMassacre string reportMessage = $"Total Kills: {totalKills}, Kills per Hour: {killsPerHour:F2}, Elapsed Time: {elapsed:dd\\.hh\\:mm\\:ss}, Rares Found: {rareCount}"; WriteToChat(reportMessage); break; + case "getmetastate": + string metaState = VtankControl.VtGetMetaState(); + WriteToChat(metaState); + break; case "loc": Coordinates here = Coordinates.Me; diff --git a/MosswartMassacre/Telemetry.cs b/MosswartMassacre/Telemetry.cs index 7facf99..ce9bb79 100644 --- a/MosswartMassacre/Telemetry.cs +++ b/MosswartMassacre/Telemetry.cs @@ -83,10 +83,12 @@ namespace MosswartMassacre z = coords.Z, kills = PluginCore.totalKills, + onlinetime = (DateTime.Now - PluginCore.statsStartTime).ToString(@"dd\.hh\:mm\:ss"), + kills_per_hour = PluginCore.killsPerHour.ToString("F0"), deaths = 0, rares_found = PluginCore.rareCount, prismatic_taper_count = 0, - vt_state = "Unknown" + vt_state = VtankControl.VtGetMetaState(), }; string json = JsonConvert.SerializeObject(payload); diff --git a/MosswartMassacre/VtankControl.cs b/MosswartMassacre/VtankControl.cs new file mode 100644 index 0000000..686dcbb --- /dev/null +++ b/MosswartMassacre/VtankControl.cs @@ -0,0 +1,108 @@ +using System; + +namespace MosswartMassacre +{ + /// + /// Provides helper methods to control VTank from within your plugin. + /// + public static class VtankControl + { + /// + /// Sends a chat command to VTank to switch its current meta-state. + /// + /// + /// The name of the VTank meta-state to activate. + /// + /// Always returns 1 on sending the command. + public static double VtSetMetaState(string state) + { + // Dispatch a local chat command that VTank will interpret. + PluginCore.Decal_DispatchOnChatCommand($"/vt setmetastate {state}"); + return 1; + } + + /// + /// Queries VTank for its currently active meta-state. + /// + /// + /// The name of the current meta-state, or empty string if VTank isn’t initialized. + /// + public static string VtGetMetaState() + { + // Instance.CurrentMetaState is typed as object, so cast it: + return (vTank.Instance.CurrentMetaState as string) ?? string.Empty; + } + + /// + /// Attempts to set a VTank configuration value by name. + /// + /// + /// The VTank setting key (e.g. “EnableCombat”, “RingDistance”). + /// + /// + /// The string or numeric value to assign. Numeric strings will be parsed. + /// + /// + /// 1 if the setting was applied or possibly applied; 0 on known failure. + /// + public static double VtSetSetting(string setting, string value) + { + try + { + var settingType = vTank.Instance.GetSettingType(setting); + + if (settingType == typeof(string)) + { + vTank.Instance.SetSetting(setting, value); + } + else if (double.TryParse(value, out double number)) + { + if (settingType == typeof(bool)) + vTank.Instance.SetSetting(setting, number == 1); + else if (settingType == typeof(double)) + vTank.Instance.SetSetting(setting, number); + else if (settingType == typeof(int)) + vTank.Instance.SetSetting(setting, Convert.ToInt32(number)); + else if (settingType == typeof(float)) + vTank.Instance.SetSetting(setting, Convert.ToSingle(number)); + } + else + { + // Value wasn’t parseable—report failure + return 0; + } + } + catch + { + // Swallow any errors and signal failure + return 0; + } + + return 1; + } + + /// + /// Reads back a VTank configuration value as a string. + /// + /// The name of the setting to read. + /// + /// The raw string form of the setting, or empty string if undefined. + /// + public static string VtGetSetting(string setting) + { + var val = vTank.Instance.GetSetting(setting); + return (val as string) ?? string.Empty; + } + + /// + /// Checks whether the VTank macro engine is currently enabled. + /// + /// + /// true if macros are active; otherwise false. + /// + public static bool VtMacroEnabled() + { + return vTank.Instance.MacroEnabled; + } + } +} diff --git a/MosswartMassacre/vTank.cs b/MosswartMassacre/vTank.cs new file mode 100644 index 0000000..ac95253 --- /dev/null +++ b/MosswartMassacre/vTank.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using uTank2; +using static uTank2.PluginCore; + +namespace MosswartMassacre +{ + /// + /// Helper class for working with the VTank plugin + /// + public static unsafe class vTank + { + internal static IList ChatQueue = null; + internal static Type ChatType; + + /// + /// The TrustedRelay interface for VTank control + /// + public static cExternalInterfaceTrustedRelay Instance { get; internal set; } + + /// + /// Current VTank action locks. Key is lock type, Value is when the lock is set to expire. + /// + public static Dictionary locks = new Dictionary(); + + /// + /// Enables VTank helper functionality + /// + public static void Enable() + { + foreach (uTank2.ActionLockType ty in Enum.GetValues(typeof(uTank2.ActionLockType))) + locks[ty] = DateTime.MinValue; + + try + { + ConstructorInfo ctor = typeof(cExternalInterfaceTrustedRelay) + .GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0]; + Instance = (cExternalInterfaceTrustedRelay)ctor.Invoke(new object[] { eExternalsPermissionLevel.None }); + + FieldInfo fieldInfo = Instance.GetType() + .GetField("a", BindingFlags.NonPublic | BindingFlags.Instance); + fieldInfo.SetValue(Instance, 15); + + Type vTankChatHandler = typeof(uTank2.PluginCore).Assembly.GetType("a7"); + FieldInfo vTankChatList = vTankChatHandler + .GetField("a", BindingFlags.NonPublic | BindingFlags.Static); + ChatType = vTankChatHandler.GetNestedType("a"); + ChatQueue = (IList)(vTankChatList.GetValue(null)); + } + catch + { + Disable(); + } + } + + /// + /// Disables VTank helper functionality + /// + public static void Disable() + { + ChatType = null; + ChatQueue = null; + Instance = null; + } + + /// + /// Lock VTank from performing actions. Use Decision_UnLock to cancel. + /// + /// the type of action to put a lock on + /// time to lock vtank for + public static void Decision_Lock(uTank2.ActionLockType actionLockType, TimeSpan timeSpan) + { + Instance?.Decision_Lock(actionLockType, timeSpan); + DateTime newExp = DateTime.UtcNow + timeSpan; + if (locks[actionLockType] < newExp) locks[actionLockType] = newExp; + } + + /// + /// Cancel a VTank lock + /// + /// the type of action to unlock + public static void Decision_UnLock(uTank2.ActionLockType actionLockType) + { + Instance?.Decision_UnLock(actionLockType); + locks[actionLockType] = DateTime.MinValue; + } + + #region Tell(string message, int color = 0, int target = 0) + /// + /// Sends a chat message to VTank so that it will be capturable by metas. + /// + /// message to send + /// color of the chat text + /// chat window target + public static void Tell(string message, int color = 0, int target = 0) + { + if (ChatQueue != null) + { + object newA = Activator.CreateInstance(ChatType); + ChatType.GetField("a").SetValue(newA, message); // message + ChatType.GetField("b").SetValue(newA, color); // color + ChatType.GetField("c").SetValue(newA, target); // target + try + { + ChatQueue.Add(newA); + } + catch { } + } + } + #endregion + } +}