added chest looter

This commit is contained in:
erik 2025-12-09 21:23:51 +01:00
parent 2eb9a7773e
commit c90a11fc29
4 changed files with 1603 additions and 4 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,122 @@
using System;
namespace MosswartMassacre
{
/// <summary>
/// Settings for the Chest Looter feature
/// These settings are persisted per-character via PluginSettings
/// </summary>
public class ChestLooterSettings
{
// Target configuration
public string ChestName { get; set; } = "";
public string KeyName { get; set; } = "";
// Feature toggles
public bool Enabled { get; set; } = false;
public bool EnableChests { get; set; } = true;
public bool AutoSalvageAfterLooting { get; set; } = false;
public bool JumpWhenLooting { get; set; } = false;
public bool BlockVtankMelee { get; set; } = false;
public bool TestMode { get; set; } = false;
public bool VerboseLogging { get; set; } = false;
// Timing and retry settings
public int DelaySpeed { get; set; } = 1000; // Delay for unlock/open/close in ms
public int OverallSpeed { get; set; } = 100; // Overall looter tick rate in ms
public int MaxUnlockAttempts { get; set; } = 10; // Max attempts to unlock chest
public int MaxOpenAttempts { get; set; } = 10; // Max attempts to open chest
public int AttemptsBeforeBlacklisting { get; set; } = 500; // Item loot attempts before giving up
// Jump looting settings
public int JumpHeight { get; set; } = 100; // Jump height (full bar is 1000)
// UI state
public bool ShowChestLooterTab { get; set; } = true;
/// <summary>
/// Constructor with default values
/// </summary>
public ChestLooterSettings()
{
// All defaults set via property initializers above
}
/// <summary>
/// Validate settings and apply constraints
/// </summary>
public void Validate()
{
// Ensure OverallSpeed isn't too fast (can cause issues)
if (OverallSpeed < 100)
OverallSpeed = 100;
// Ensure delays are reasonable
if (DelaySpeed < 500)
DelaySpeed = 500;
// Ensure attempt limits are positive
if (MaxUnlockAttempts < 1)
MaxUnlockAttempts = 1;
if (MaxOpenAttempts < 1)
MaxOpenAttempts = 1;
if (AttemptsBeforeBlacklisting < 1)
AttemptsBeforeBlacklisting = 1;
// Clamp jump height to reasonable range
if (JumpHeight < 0)
JumpHeight = 0;
if (JumpHeight > 1000)
JumpHeight = 1000;
}
/// <summary>
/// Reset all settings to default values
/// </summary>
public void Reset()
{
ChestName = "";
KeyName = "";
Enabled = false;
EnableChests = true;
AutoSalvageAfterLooting = false;
JumpWhenLooting = false;
BlockVtankMelee = false;
TestMode = false;
VerboseLogging = false;
DelaySpeed = 1000;
OverallSpeed = 100;
MaxUnlockAttempts = 10;
MaxOpenAttempts = 10;
AttemptsBeforeBlacklisting = 500;
JumpHeight = 100;
ShowChestLooterTab = true;
}
/// <summary>
/// Create a copy of these settings
/// </summary>
public ChestLooterSettings Clone()
{
return new ChestLooterSettings
{
ChestName = this.ChestName,
KeyName = this.KeyName,
Enabled = this.Enabled,
EnableChests = this.EnableChests,
AutoSalvageAfterLooting = this.AutoSalvageAfterLooting,
JumpWhenLooting = this.JumpWhenLooting,
BlockVtankMelee = this.BlockVtankMelee,
TestMode = this.TestMode,
VerboseLogging = this.VerboseLogging,
DelaySpeed = this.DelaySpeed,
OverallSpeed = this.OverallSpeed,
MaxUnlockAttempts = this.MaxUnlockAttempts,
MaxOpenAttempts = this.MaxOpenAttempts,
AttemptsBeforeBlacklisting = this.AttemptsBeforeBlacklisting,
JumpHeight = this.JumpHeight,
ShowChestLooterTab = this.ShowChestLooterTab
};
}
}
}

View file

@ -119,7 +119,8 @@ namespace MosswartMassacre
public static bool AggressiveChatStreamingEnabled { get; set; } = true; public static bool AggressiveChatStreamingEnabled { get; set; } = true;
private MossyInventory _inventoryLogger; private MossyInventory _inventoryLogger;
public static NavVisualization navVisualization; public static NavVisualization navVisualization;
public static ChestLooter chestLooter;
// Quest Management for always-on quest streaming // Quest Management for always-on quest streaming
public static QuestManager questManager; public static QuestManager questManager;
private static Timer questStreamingTimer; private static Timer questStreamingTimer;
@ -215,6 +216,8 @@ namespace MosswartMassacre
// Initialize navigation visualization system // Initialize navigation visualization system
navVisualization = new NavVisualization(); navVisualization = new NavVisualization();
// Note: ChestLooter is initialized in LoginComplete after PluginSettings.Initialize()
// Note: DECAL Harmony patches will be initialized in LoginComplete event // Note: DECAL Harmony patches will be initialized in LoginComplete event
// where the chat system is available for error messages // where the chat system is available for error messages
@ -329,6 +332,21 @@ namespace MosswartMassacre
PluginSettings.Initialize(); // Safe to call now PluginSettings.Initialize(); // Safe to call now
// Initialize chest looter system (needs PluginSettings to be ready)
try
{
chestLooter = new ChestLooter(CoreManager.Current, PluginSettings.Instance.ChestLooterSettings);
chestLooter.Initialize();
chestLooter.StatusChanged += (sender, status) =>
{
VVSTabbedMainView.UpdateChestLooterStatus(status);
};
}
catch (Exception ex)
{
WriteToChat($"[ChestLooter] Initialization failed: {ex.Message}");
}
// Apply the values // Apply the values
RareMetaEnabled = PluginSettings.Instance.RareMetaEnabled; RareMetaEnabled = PluginSettings.Instance.RareMetaEnabled;
WebSocketEnabled = PluginSettings.Instance.WebSocketEnabled; WebSocketEnabled = PluginSettings.Instance.WebSocketEnabled;
@ -494,6 +512,21 @@ namespace MosswartMassacre
// 1. Initialize settings - CRITICAL first step // 1. Initialize settings - CRITICAL first step
PluginSettings.Initialize(); PluginSettings.Initialize();
// 1b. Initialize chest looter system (needs PluginSettings to be ready)
try
{
chestLooter = new ChestLooter(CoreManager.Current, PluginSettings.Instance.ChestLooterSettings);
chestLooter.Initialize();
chestLooter.StatusChanged += (sender, status) =>
{
VVSTabbedMainView.UpdateChestLooterStatus(status);
};
}
catch (Exception ex)
{
WriteToChat($"[ChestLooter] Initialization failed: {ex.Message}");
}
// 2. Apply the values from settings // 2. Apply the values from settings
RareMetaEnabled = PluginSettings.Instance.RareMetaEnabled; RareMetaEnabled = PluginSettings.Instance.RareMetaEnabled;
WebSocketEnabled = PluginSettings.Instance.WebSocketEnabled; WebSocketEnabled = PluginSettings.Instance.WebSocketEnabled;
@ -1216,7 +1249,7 @@ namespace MosswartMassacre
} }
else else
{ {
// Hot reload fallback - use CoreManager directly like the original template // Hot reload fallback1 - use CoreManager directly like the original template
CoreManager.Current.Actions.AddChatText("[Mosswart Massacre] " + message, 1); CoreManager.Current.Actions.AddChatText("[Mosswart Massacre] " + message, 1);
} }
} }
@ -1277,7 +1310,7 @@ namespace MosswartMassacre
} }
private void HandleMmCommand(string text) private void HandleMmCommand(string text)
{ {
// Remove the /mm prefix and trim extra whitespace // Remove the /mm prefix and trim extra whitespace test
string[] args = text.Substring(3).Trim().Split(' '); string[] args = text.Substring(3).Trim().Split(' ');
if (args.Length == 0 || string.IsNullOrEmpty(args[0])) if (args.Length == 0 || string.IsNullOrEmpty(args[0]))
@ -1356,6 +1389,10 @@ namespace MosswartMassacre
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"); WriteToChat("/mm getmetastate - Gets the current metastate");
WriteToChat("/mm setchest <name> - Set chest name for looter");
WriteToChat("/mm setkey <name> - Set key name for looter");
WriteToChat("/mm lootchest - Start chest looting");
WriteToChat("/mm stoploot - Stop chest looting");
WriteToChat("/mm nextwp - Advance VTank to next waypoint"); WriteToChat("/mm nextwp - Advance VTank to next waypoint");
WriteToChat("/mm decalstatus - Check Harmony patch status (UtilityBelt version)"); WriteToChat("/mm decalstatus - Check Harmony patch status (UtilityBelt version)");
WriteToChat("/mm decaldebug - Enable/disable plugin message debug output + WebSocket streaming"); WriteToChat("/mm decaldebug - Enable/disable plugin message debug output + WebSocket streaming");
@ -1460,6 +1497,69 @@ namespace MosswartMassacre
} }
break; break;
case "setchest":
if (args.Length < 2)
{
WriteToChat("[ChestLooter] Usage: /mm setchest <chest name>");
return;
}
string chestName = string.Join(" ", args.Skip(1));
if (chestLooter != null)
{
chestLooter.SetChestName(chestName);
if (PluginSettings.Instance?.ChestLooterSettings != null)
{
PluginSettings.Instance.ChestLooterSettings.ChestName = chestName;
PluginSettings.Save();
}
Views.VVSTabbedMainView.RefreshChestLooterUI();
}
break;
case "setkey":
if (args.Length < 2)
{
WriteToChat("[ChestLooter] Usage: /mm setkey <key name>");
return;
}
string keyName = string.Join(" ", args.Skip(1));
if (chestLooter != null)
{
chestLooter.SetKeyName(keyName);
if (PluginSettings.Instance?.ChestLooterSettings != null)
{
PluginSettings.Instance.ChestLooterSettings.KeyName = keyName;
PluginSettings.Save();
}
Views.VVSTabbedMainView.RefreshChestLooterUI();
}
break;
case "lootchest":
if (chestLooter != null)
{
if (!chestLooter.StartByName())
{
WriteToChat("[ChestLooter] Failed to start. Check chest/key names are set.");
}
}
else
{
WriteToChat("[ChestLooter] Chest looter not initialized");
}
break;
case "stoploot":
if (chestLooter != null)
{
chestLooter.Stop();
}
else
{
WriteToChat("[ChestLooter] Chest looter not initialized");
}
break;
case "vtanktest": case "vtanktest":
try try
{ {

View file

@ -123,6 +123,37 @@
<control progid="DecalControls.PushButton" name="btnOpenFlagTracker" left="10" top="10" width="150" height="30" text="Open Mossy Tracker"/> <control progid="DecalControls.PushButton" name="btnOpenFlagTracker" left="10" top="10" width="150" height="30" text="Open Mossy Tracker"/>
</control> </control>
</page> </page>
<page label="Chest Looter">
<control progid="DecalControls.FixedLayout" clipped="">
<!-- Header -->
<control progid="DecalControls.StaticText" name="lblChestLooterHeader" left="10" top="10" width="250" height="20" text="Automated Chest Looting" style="FontBold"/>
<!-- Chest Name Configuration -->
<control progid="DecalControls.StaticText" name="lblChestNameLabel" left="20" top="40" width="100" height="16" text="Chest Name:"/>
<control progid="DecalControls.Edit" name="txtChestName" left="125" top="38" width="180" height="20" text=""/>
<control progid="DecalControls.PushButton" name="btnSetChest" left="310" top="37" width="100" height="22" text="Set from Selection"/>
<!-- Key Name Configuration -->
<control progid="DecalControls.StaticText" name="lblKeyNameLabel" left="20" top="70" width="100" height="16" text="Key Name:"/>
<control progid="DecalControls.Edit" name="txtKeyName" left="125" top="68" width="180" height="20" text=""/>
<control progid="DecalControls.PushButton" name="btnSetKey" left="310" top="67" width="100" height="22" text="Set from Selection"/>
<!-- Control Buttons -->
<control progid="DecalControls.PushButton" name="btnStartLooter" left="20" top="105" width="120" height="30" text="Start Looting"/>
<control progid="DecalControls.PushButton" name="btnStopLooter" left="145" top="105" width="120" height="30" text="Stop"/>
<!-- Settings -->
<control progid="DecalControls.StaticText" name="lblLooterSettingsHeader" left="10" top="145" width="200" height="16" text="Options" style="FontBold"/>
<control progid="DecalControls.Checkbox" name="chkEnableChests" left="20" top="165" width="200" height="20" text="Enable Chest Looting" checked="true"/>
<!-- Status Display -->
<control progid="DecalControls.StaticText" name="lblLooterStatus" left="10" top="195" width="380" height="20" text="Status: Ready"/>
<!-- Instructions -->
<control progid="DecalControls.StaticText" name="lblLooterInstructions" left="10" top="220" width="380" height="30" text="Set chest/key names, then click Start. Uses VTank loot profile. Commands: /mm setchest, /mm setkey, /mm lootchest"/>
</control>
</page>
</control> </control>
</view> </view>