New vtank control

This commit is contained in:
erik 2025-04-29 09:58:25 +02:00
parent de1b72aae5
commit 347cfe6423
5 changed files with 244 additions and 3 deletions

View file

@ -10,7 +10,7 @@
<RootNamespace>MosswartMassacre</RootNamespace> <RootNamespace>MosswartMassacre</RootNamespace>
<AssemblyName>MosswartMassacre</AssemblyName> <AssemblyName>MosswartMassacre</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion> <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<LangVersion>8.0</LangVersion> <LangVersion>8.0</LangVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic> <Deterministic>true</Deterministic>
</PropertyGroup> </PropertyGroup>
@ -38,6 +38,9 @@
<HintPath>lib\Decal.Adapter.dll</HintPath> <HintPath>lib\Decal.Adapter.dll</HintPath>
<EmbedInteropTypes>False</EmbedInteropTypes> <EmbedInteropTypes>False</EmbedInteropTypes>
</Reference> </Reference>
<Reference Include="uTank2">
<HintPath>lib\utank2-i.dll</HintPath>
</Reference>
<Reference Include="Decal.Interop.Core, Version=2.9.8.3, Culture=neutral, PublicKeyToken=481f17d392f1fb65, processorArchitecture=MSIL"> <Reference Include="Decal.Interop.Core, Version=2.9.8.3, Culture=neutral, PublicKeyToken=481f17d392f1fb65, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<EmbedInteropTypes>False</EmbedInteropTypes> <EmbedInteropTypes>False</EmbedInteropTypes>
@ -70,6 +73,8 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="vTank.cs" />
<Compile Include="VtankControl.cs" />
<Compile Include="Telemetry.cs" /> <Compile Include="Telemetry.cs" />
<Compile Include="Coordinates.cs" /> <Compile Include="Coordinates.cs" />
<Compile Include="Geometry.cs" /> <Compile Include="Geometry.cs" />

View file

@ -52,6 +52,8 @@ namespace MosswartMassacre
// Enable TLS1.2 // Enable TLS1.2
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
//Enable vTank interface
vTank.Enable();
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -82,6 +84,9 @@ namespace MosswartMassacre
// Clean up the view // Clean up the view
MainView.ViewDestroy(); MainView.ViewDestroy();
//Disable vtank interface
vTank.Disable();
MyHost = null; MyHost = null;
} }
catch (Exception ex) catch (Exception ex)
@ -409,6 +414,7 @@ namespace MosswartMassacre
WriteToChat("/mm meta - Toggle rare meta state"); WriteToChat("/mm meta - Toggle rare meta state");
WriteToChat("/mm http - Local http-command server enable|disable"); WriteToChat("/mm http - Local http-command server enable|disable");
WriteToChat("/mm remotecommand - Listen to allegiance !do/!dot enable|disable"); WriteToChat("/mm remotecommand - Listen to allegiance !do/!dot enable|disable");
WriteToChat("/mm getmetastate - Gets the current metastate");
break; break;
case "report": 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}"; string reportMessage = $"Total Kills: {totalKills}, Kills per Hour: {killsPerHour:F2}, Elapsed Time: {elapsed:dd\\.hh\\:mm\\:ss}, Rares Found: {rareCount}";
WriteToChat(reportMessage); WriteToChat(reportMessage);
break; break;
case "getmetastate":
string metaState = VtankControl.VtGetMetaState();
WriteToChat(metaState);
break;
case "loc": case "loc":
Coordinates here = Coordinates.Me; Coordinates here = Coordinates.Me;

View file

@ -83,10 +83,12 @@ namespace MosswartMassacre
z = coords.Z, z = coords.Z,
kills = PluginCore.totalKills, kills = PluginCore.totalKills,
onlinetime = (DateTime.Now - PluginCore.statsStartTime).ToString(@"dd\.hh\:mm\:ss"),
kills_per_hour = PluginCore.killsPerHour.ToString("F0"),
deaths = 0, deaths = 0,
rares_found = PluginCore.rareCount, rares_found = PluginCore.rareCount,
prismatic_taper_count = 0, prismatic_taper_count = 0,
vt_state = "Unknown" vt_state = VtankControl.VtGetMetaState(),
}; };
string json = JsonConvert.SerializeObject(payload); string json = JsonConvert.SerializeObject(payload);

View file

@ -0,0 +1,108 @@
using System;
namespace MosswartMassacre
{
/// <summary>
/// Provides helper methods to control VTank from within your plugin.
/// </summary>
public static class VtankControl
{
/// <summary>
/// Sends a chat command to VTank to switch its current meta-state.
/// </summary>
/// <param name="state">
/// The name of the VTank meta-state to activate.
/// </param>
/// <returns>Always returns 1 on sending the command.</returns>
public static double VtSetMetaState(string state)
{
// Dispatch a local chat command that VTank will interpret.
PluginCore.Decal_DispatchOnChatCommand($"/vt setmetastate {state}");
return 1;
}
/// <summary>
/// Queries VTank for its currently active meta-state.
/// </summary>
/// <returns>
/// The name of the current meta-state, or empty string if VTank isnt initialized.
/// </returns>
public static string VtGetMetaState()
{
// Instance.CurrentMetaState is typed as object, so cast it:
return (vTank.Instance.CurrentMetaState as string) ?? string.Empty;
}
/// <summary>
/// Attempts to set a VTank configuration value by name.
/// </summary>
/// <param name="setting">
/// The VTank setting key (e.g. “EnableCombat”, “RingDistance”).
/// </param>
/// <param name="value">
/// The string or numeric value to assign. Numeric strings will be parsed.
/// </param>
/// <returns>
/// 1 if the setting was applied or possibly applied; 0 on known failure.
/// </returns>
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 wasnt parseable—report failure
return 0;
}
}
catch
{
// Swallow any errors and signal failure
return 0;
}
return 1;
}
/// <summary>
/// Reads back a VTank configuration value as a string.
/// </summary>
/// <param name="setting">The name of the setting to read.</param>
/// <returns>
/// The raw string form of the setting, or empty string if undefined.
/// </returns>
public static string VtGetSetting(string setting)
{
var val = vTank.Instance.GetSetting(setting);
return (val as string) ?? string.Empty;
}
/// <summary>
/// Checks whether the VTank macro engine is currently enabled.
/// </summary>
/// <returns>
/// <c>true</c> if macros are active; otherwise <c>false</c>.
/// </returns>
public static bool VtMacroEnabled()
{
return vTank.Instance.MacroEnabled;
}
}
}

116
MosswartMassacre/vTank.cs Normal file
View file

@ -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
{
/// <summary>
/// Helper class for working with the VTank plugin
/// </summary>
public static unsafe class vTank
{
internal static IList ChatQueue = null;
internal static Type ChatType;
/// <summary>
/// The TrustedRelay interface for VTank control
/// </summary>
public static cExternalInterfaceTrustedRelay Instance { get; internal set; }
/// <summary>
/// Current VTank action locks. Key is lock type, Value is when the lock is set to expire.
/// </summary>
public static Dictionary<uTank2.ActionLockType, DateTime> locks = new Dictionary<uTank2.ActionLockType, DateTime>();
/// <summary>
/// Enables VTank helper functionality
/// </summary>
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();
}
}
/// <summary>
/// Disables VTank helper functionality
/// </summary>
public static void Disable()
{
ChatType = null;
ChatQueue = null;
Instance = null;
}
/// <summary>
/// Lock VTank from performing actions. Use Decision_UnLock to cancel.
/// </summary>
/// <param name="actionLockType">the type of action to put a lock on</param>
/// <param name="timeSpan">time to lock vtank for</param>
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;
}
/// <summary>
/// Cancel a VTank lock
/// </summary>
/// <param name="actionLockType">the type of action to unlock</param>
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)
/// <summary>
/// Sends a chat message to VTank so that it will be capturable by metas.
/// </summary>
/// <param name="message">message to send</param>
/// <param name="color">color of the chat text</param>
/// <param name="target">chat window target</param>
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
}
}