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; } /// /// Advances VTank to the next waypoint in the current navigation route. /// /// /// 1 if the waypoint was advanced successfully; 0 on failure. /// public static double VtAdvanceWaypoint() { try { var externalInterface = vTank.Instance; // Basic validation if (externalInterface.NavNumPoints == 0) { return 0; // No waypoints } int currentWaypoint = externalInterface.NavCurrent; int totalWaypoints = externalInterface.NavNumPoints; // Check if we can advance if (currentWaypoint >= totalWaypoints - 1) { return 0; // Already at last waypoint } // Check navigation type var navType = (int)externalInterface.NavType; if (navType == 2 || navType == 4) // Target or Once { return 0; } // Access the cExternalInterfaceTrustedRelay and get the PC (PluginCore) reference // From decompiled code: external interface uses PC.NavCurrent which references dz.o.l var interfaceType = externalInterface.GetType(); // Look for any way to get to the PluginCore instance // The interface should have access to PC or some way to reach it // Try to get the underlying assembly and find the PC static field var assembly = interfaceType.Assembly; var pluginCoreType = assembly.GetType("uTank2.PluginCore"); if (pluginCoreType != null) { // Get the static PC field var pcField = pluginCoreType.GetField("PC", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); if (pcField != null) { var pluginCoreInstance = pcField.GetValue(null); if (pluginCoreInstance != null) { // Try to call the advance method 'i' on the PluginCore instance // Need to specify parameter types to avoid "Ambiguous match found" Type[] parameterTypes = new Type[] { typeof(object), assembly.GetType("MetaViewWrappers.MVControlEventArgs") }; var advanceMethod = pluginCoreType.GetMethod("i", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, parameterTypes, null); if (advanceMethod != null) { // Call with parameters matching: i(object A_0, MVControlEventArgs A_1) advanceMethod.Invoke(pluginCoreInstance, new object[] { null, null }); return 1; } } } // Fallback: try to access dz static field directly var dzField = pluginCoreType.GetField("dz", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); if (dzField != null) { var dzObject = dzField.GetValue(null); if (dzObject != null) { // Navigate the dz.o.l path var dzType = dzObject.GetType(); var oField = dzType.GetField("o", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (oField != null) { var oObject = oField.GetValue(dzObject); if (oObject != null) { var oType = oObject.GetType(); var lField = oType.GetField("l", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (lField != null) { // Get current value and increment it int current = (int)lField.GetValue(oObject); current++; if (current >= totalWaypoints) { current = totalWaypoints - 1; } lField.SetValue(oObject, current); return 1; } } } } } } return 0; } catch (System.Exception ex) { PluginCore.WriteToChat("VTank advance error: " + ex.Message); return 0; } } } }