feat(vtank): /mm prevwp — move VTank back to the previous waypoint

Mirrors /mm nextwp: invokes uTank2.PluginCore's own previous-waypoint
button handler 'j' (verified against the installed VTank binary — exact
mirror of the advance handler 'i': decrements dz.o.l, clamps at 0,
refreshes nav), with the same direct-field fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-09-15 21:34:14 +02:00
parent 4fdec3bbcd
commit 48cf13b06b
3 changed files with 118 additions and 0 deletions

View file

@ -1301,6 +1301,15 @@ namespace MosswartMassacre
WriteToChat("Failed to advance VTank waypoint. Is VTank running?"); WriteToChat("Failed to advance VTank waypoint. Is VTank running?");
}, "Advance VTank to next waypoint"); }, "Advance VTank to next waypoint");
_commandRouter.Register("prevwp", args =>
{
double result = VtankControl.VtPreviousWaypoint();
if (result == 1)
WriteToChat("Moved VTank back to previous waypoint.");
else
WriteToChat("Failed to move VTank waypoint back. Is VTank running?");
}, "Move VTank back to previous waypoint");
_commandRouter.Register("setchest", args => _commandRouter.Register("setchest", args =>
{ {
if (args.Length < 2) if (args.Length < 2)

View file

@ -224,5 +224,114 @@ namespace MosswartMassacre
return 0; return 0;
} }
} }
/// <summary>
/// Moves VTank back to the previous waypoint in the current navigation route.
/// </summary>
/// <returns>
/// 1 if the waypoint was moved back successfully; 0 on failure.
/// </returns>
public static double VtPreviousWaypoint()
{
try
{
var externalInterface = vTank.Instance;
// Basic validation
if (externalInterface.NavNumPoints == 0)
{
return 0; // No waypoints
}
int currentWaypoint = externalInterface.NavCurrent;
// Check if we can go back
if (currentWaypoint <= 0)
{
return 0; // Already at first waypoint
}
// Check navigation type
var navType = (int)externalInterface.NavType;
if (navType == 2 || navType == 4) // Target or Once
{
return 0;
}
var interfaceType = externalInterface.GetType();
var assembly = interfaceType.Assembly;
var pluginCoreType = assembly.GetType("uTank2.PluginCore");
if (pluginCoreType != null)
{
var pcField = pluginCoreType.GetField("PC", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
if (pcField != null)
{
var pluginCoreInstance = pcField.GetValue(null);
if (pluginCoreInstance != null)
{
// VTank's previous-waypoint button handler is 'j' — the exact
// mirror of the advance handler 'i' (decrements dz.o.l, clamps
// at 0, refreshes nav state via m()).
Type[] parameterTypes = new Type[] { typeof(object), assembly.GetType("MetaViewWrappers.MVControlEventArgs") };
var previousMethod = pluginCoreType.GetMethod("j",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance,
null, parameterTypes, null);
if (previousMethod != null)
{
previousMethod.Invoke(pluginCoreInstance, new object[] { null, null });
return 1;
}
}
}
// Fallback: decrement the current-waypoint field dz.o.l 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)
{
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)
{
int current = (int)lField.GetValue(oObject);
current--;
if (current < 0)
{
current = 0;
}
lField.SetValue(oObject, current);
return 1;
}
}
}
}
}
}
return 0;
}
catch (System.Exception ex)
{
PluginCore.WriteToChat("VTank previous-waypoint error: " + ex.Message);
return 0;
}
}
} }
} }