Added /mm sendinventory
This commit is contained in:
parent
ab425a04cc
commit
e9a113abdd
8 changed files with 443 additions and 2 deletions
|
|
@ -179,6 +179,7 @@
|
|||
<Compile Include="DelayedCommandManager.cs" />
|
||||
<Compile Include="PluginCore.cs" />
|
||||
<Compile Include="QuestNames.cs" />
|
||||
<Compile Include="UpdateManager.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ namespace MosswartMassacre
|
|||
{
|
||||
return; // Settings not ready, skip silently
|
||||
}
|
||||
DumpInventoryToFile();
|
||||
DumpInventoryToFile(true); // Request IDs if missing to ensure complete data
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -293,5 +293,44 @@ namespace MosswartMassacre
|
|||
|| (oc == ObjectClass.Gem && !string.IsNullOrEmpty(name) && name.Contains("Aetheria"))
|
||||
|| (oc == ObjectClass.Misc && !string.IsNullOrEmpty(name) && name.Contains("Essence"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces an inventory upload with ID requests - guarantees complete data
|
||||
/// </summary>
|
||||
public void ForceInventoryUpload()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Check if inventory logging is enabled
|
||||
try
|
||||
{
|
||||
if (!PluginSettings.Instance.InventoryLog)
|
||||
{
|
||||
PluginCore.WriteToChat("[INV] Inventory logging is disabled");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
PluginCore.WriteToChat("[INV] Settings not ready");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if WebSocket is enabled
|
||||
if (!PluginCore.WebSocketEnabled)
|
||||
{
|
||||
PluginCore.WriteToChat("[INV] WebSocket streaming is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
PluginCore.WriteToChat("[INV] Forcing inventory upload with ID requests...");
|
||||
DumpInventoryToFile(true); // Request IDs if missing
|
||||
PluginCore.WriteToChat("[INV] Inventory upload completed");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"[INV] Force upload failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,11 @@ namespace MosswartMassacre
|
|||
{
|
||||
Views.VVSTabbedMainView.RefreshSettingsFromConfig();
|
||||
}
|
||||
|
||||
public static void RefreshUpdateStatus()
|
||||
{
|
||||
Views.VVSTabbedMainView.RefreshUpdateStatus();
|
||||
}
|
||||
}
|
||||
public static bool RemoteCommandsEnabled { get; set; } = false;
|
||||
public static bool HttpServerEnabled { get; set; } = false;
|
||||
|
|
@ -227,7 +232,9 @@ namespace MosswartMassacre
|
|||
PluginSettings.Save();
|
||||
if (TelemetryEnabled)
|
||||
Telemetry.Stop(); // ensure no dangling timer / HttpClient
|
||||
WriteToChat("Mosswart Massacre is shutting down!!!!!");
|
||||
WriteToChat("Mosswart Massacre is shutting down. Bye!");
|
||||
|
||||
|
||||
|
||||
// Unsubscribe from chat message event
|
||||
CoreManager.Current.ChatBoxMessage -= new EventHandler<ChatTextInterceptEventArgs>(OnChatText);
|
||||
|
|
@ -1278,6 +1285,10 @@ namespace MosswartMassacre
|
|||
WriteToChat("/mm testtaper - Test cached Prismatic Taper tracking");
|
||||
WriteToChat("/mm debugtaper - Show detailed taper tracking debug info");
|
||||
WriteToChat("/mm gui - Manually initialize/reinitialize GUI!!!");
|
||||
WriteToChat("/mm checkforupdate - Check for plugin updates");
|
||||
WriteToChat("/mm update - Download and install update (if available)");
|
||||
WriteToChat("/mm debugupdate - Debug update UI controls");
|
||||
WriteToChat("/mm sendinventory - Force inventory upload with ID requests");
|
||||
break;
|
||||
case "report":
|
||||
TimeSpan elapsed = DateTime.Now - statsStartTime;
|
||||
|
|
@ -1655,6 +1666,46 @@ namespace MosswartMassacre
|
|||
}
|
||||
break;
|
||||
|
||||
case "checkforupdate":
|
||||
// Run the update check asynchronously
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await UpdateManager.CheckForUpdateAsync();
|
||||
// Update UI if available
|
||||
try
|
||||
{
|
||||
ViewManager.RefreshUpdateStatus();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteToChat($"Error refreshing UI: {ex.Message}");
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case "update":
|
||||
// Run the update installation asynchronously
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await UpdateManager.DownloadAndInstallUpdateAsync();
|
||||
});
|
||||
break;
|
||||
|
||||
case "debugupdate":
|
||||
Views.VVSTabbedMainView.DebugUpdateControls();
|
||||
break;
|
||||
|
||||
case "sendinventory":
|
||||
// Force inventory upload with ID requests
|
||||
if (_inventoryLogger != null)
|
||||
{
|
||||
_inventoryLogger.ForceInventoryUpload();
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteToChat("[INV] Inventory system not initialized");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WriteToChat($"Unknown /mm command: {subCommand}. Try /mm help");
|
||||
|
|
|
|||
198
MosswartMassacre/UpdateManager.cs
Normal file
198
MosswartMassacre/UpdateManager.cs
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MosswartMassacre
|
||||
{
|
||||
public static class UpdateManager
|
||||
{
|
||||
private const string UPDATE_URL = "https://git.snakedesert.se/SawatoMosswartsEnjoyersClub/MosswartMassacre/raw/branch/spawn-detection/MosswartMassacre/bin/Release/MosswartMassacre.dll";
|
||||
|
||||
private static bool updateAvailable = false;
|
||||
private static long remoteFileSize = 0;
|
||||
private static long localFileSize = 0;
|
||||
private static DateTime lastCheckTime = DateTime.MinValue;
|
||||
|
||||
public static bool IsUpdateAvailable => updateAvailable;
|
||||
public static DateTime LastCheckTime => lastCheckTime;
|
||||
|
||||
public static async Task<bool> CheckForUpdateAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
PluginCore.WriteToChat("[Update] Checking for updates...");
|
||||
|
||||
// Get local file size
|
||||
string localPath = GetLocalDllPath();
|
||||
if (!File.Exists(localPath))
|
||||
{
|
||||
PluginCore.WriteToChat("[Update] Error: Could not find local DLL file");
|
||||
return false;
|
||||
}
|
||||
|
||||
localFileSize = new FileInfo(localPath).Length;
|
||||
|
||||
// Check remote file size
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
client.Timeout = TimeSpan.FromSeconds(10);
|
||||
|
||||
var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, UPDATE_URL));
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
remoteFileSize = response.Content.Headers.ContentLength ?? 0;
|
||||
|
||||
if (remoteFileSize == 0)
|
||||
{
|
||||
PluginCore.WriteToChat("[Update] Error: Could not determine remote file size");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Compare sizes
|
||||
updateAvailable = (remoteFileSize != localFileSize);
|
||||
lastCheckTime = DateTime.Now;
|
||||
|
||||
if (updateAvailable)
|
||||
{
|
||||
PluginCore.WriteToChat($"[Update] Update available! Local: {localFileSize} bytes, Remote: {remoteFileSize} bytes");
|
||||
}
|
||||
else
|
||||
{
|
||||
PluginCore.WriteToChat("[Update] Up to date");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"[Update] Network error: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
PluginCore.WriteToChat("[Update] Request timed out");
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"[Update] Check failed: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<bool> DownloadAndInstallUpdateAsync()
|
||||
{
|
||||
if (!updateAvailable)
|
||||
{
|
||||
PluginCore.WriteToChat("[Update] No update available. Run /mm checkforupdate first.");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
PluginCore.WriteToChat("[Update] Downloading update...");
|
||||
|
||||
string localPath = GetLocalDllPath();
|
||||
string tempPath = localPath + ".tmp";
|
||||
string backupPath = localPath + ".bak";
|
||||
|
||||
// Download to temp file
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
client.Timeout = TimeSpan.FromSeconds(30);
|
||||
|
||||
var response = await client.GetAsync(UPDATE_URL);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
using (var fileStream = File.Create(tempPath))
|
||||
{
|
||||
await response.Content.CopyToAsync(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate downloaded file
|
||||
var downloadedSize = new FileInfo(tempPath).Length;
|
||||
if (downloadedSize != remoteFileSize)
|
||||
{
|
||||
File.Delete(tempPath);
|
||||
PluginCore.WriteToChat($"[Update] Download validation failed. Expected {remoteFileSize} bytes, got {downloadedSize} bytes");
|
||||
return false;
|
||||
}
|
||||
|
||||
PluginCore.WriteToChat("[Update] Download complete, installing...");
|
||||
|
||||
// Atomically replace current file with new version (creates backup automatically)
|
||||
File.Replace(tempPath, localPath, backupPath);
|
||||
|
||||
// Clear update flag
|
||||
updateAvailable = false;
|
||||
|
||||
PluginCore.WriteToChat("[Update] Update installed successfully!");
|
||||
PluginCore.WriteToChat("[Update] Previous version backed up as MosswartMassacre.dll.bak");
|
||||
|
||||
// Wait a moment for file system to settle, then trigger hot reload
|
||||
await System.Threading.Tasks.Task.Delay(1000);
|
||||
|
||||
try
|
||||
{
|
||||
// Touch the file to ensure FileSystemWatcher detects the change
|
||||
File.SetLastWriteTime(localPath, DateTime.Now);
|
||||
PluginCore.WriteToChat("[Update] Triggering hot reload...");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"[Update] Could not trigger hot reload: {ex.Message}");
|
||||
PluginCore.WriteToChat("[Update] Please use /mm gui to reload manually");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"[Update] Download error: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
PluginCore.WriteToChat("[Update] Download timed out");
|
||||
return false;
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
PluginCore.WriteToChat("[Update] File access denied. Make sure the plugin directory is writable.");
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"[Update] Install failed: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetLocalDllPath()
|
||||
{
|
||||
// Get the path to the current DLL
|
||||
string assemblyPath = typeof(PluginCore).Assembly.Location;
|
||||
|
||||
// If empty (hot reload scenario), use AssemblyDirectory + filename
|
||||
if (string.IsNullOrEmpty(assemblyPath))
|
||||
{
|
||||
return Path.Combine(PluginCore.AssemblyDirectory, "MosswartMassacre.dll");
|
||||
}
|
||||
|
||||
return assemblyPath;
|
||||
}
|
||||
|
||||
public static string GetUpdateStatus()
|
||||
{
|
||||
if (lastCheckTime == DateTime.MinValue)
|
||||
{
|
||||
return "Update Status: Not checked";
|
||||
}
|
||||
|
||||
return updateAvailable ? "Update Status: Update available" : "Update Status: Up to date";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,11 @@
|
|||
<!-- Enhanced status display -->
|
||||
<control progid="DecalControls.StaticText" name="lblStatus" left="10" top="145" width="380" height="20" text="Status: Ready"/>
|
||||
<control progid="DecalControls.StaticText" name="lblWebSocketStatus" left="10" top="165" width="380" height="20" text="WebSocket: [DISCONNECTED]"/>
|
||||
|
||||
<!-- Update controls on Main tab -->
|
||||
<control progid="DecalControls.PushButton" name="btnCheckUpdate" left="10" top="190" width="120" height="25" text="Check for Updates"/>
|
||||
<control progid="DecalControls.PushButton" name="btnInstallUpdate" left="140" top="190" width="120" height="25" text="Install Update"/>
|
||||
<control progid="DecalControls.StaticText" name="lblUpdateStatus" left="10" top="220" width="250" height="20" text=""/>
|
||||
</control>
|
||||
</page>
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ namespace MosswartMassacre.Views
|
|||
private HudStaticText lblAutoLootRare;
|
||||
private HudStaticText lblStatus;
|
||||
private HudStaticText lblWebSocketStatus;
|
||||
private HudButton btnCheckUpdate;
|
||||
private HudButton btnInstallUpdate;
|
||||
private HudStaticText lblUpdateStatus;
|
||||
#endregion
|
||||
|
||||
#region Settings Tab Controls
|
||||
|
|
@ -169,11 +172,21 @@ namespace MosswartMassacre.Views
|
|||
lblAutoLootRare = GetControl<HudStaticText>("lblAutoLootRare");
|
||||
lblStatus = GetControl<HudStaticText>("lblStatus");
|
||||
lblWebSocketStatus = GetControl<HudStaticText>("lblWebSocketStatus");
|
||||
btnCheckUpdate = GetControl<HudButton>("btnCheckUpdate");
|
||||
btnInstallUpdate = GetControl<HudButton>("btnInstallUpdate");
|
||||
lblUpdateStatus = GetControl<HudStaticText>("lblUpdateStatus");
|
||||
|
||||
// Hook up update button events
|
||||
if (btnCheckUpdate != null)
|
||||
btnCheckUpdate.Hit += OnCheckUpdateClicked;
|
||||
if (btnInstallUpdate != null)
|
||||
btnInstallUpdate.Hit += OnInstallUpdateClicked;
|
||||
|
||||
// Update status displays immediately
|
||||
UpdateStatus();
|
||||
UpdateAutoLootRareIndicator();
|
||||
UpdateWebSocketStatus();
|
||||
RefreshUpdateStatus();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -407,6 +420,134 @@ namespace MosswartMassacre.Views
|
|||
}
|
||||
}
|
||||
|
||||
private void OnCheckUpdateClicked(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Run update check asynchronously
|
||||
System.Threading.Tasks.Task.Run(async () =>
|
||||
{
|
||||
await UpdateManager.CheckForUpdateAsync();
|
||||
// Update UI (VVS controls are thread-safe for simple property updates)
|
||||
try
|
||||
{
|
||||
RefreshUpdateStatus();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error updating UI after check: {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error checking for updates: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInstallUpdateClicked(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Check if update check was performed first
|
||||
if (UpdateManager.LastCheckTime == DateTime.MinValue)
|
||||
{
|
||||
PluginCore.WriteToChat("[Update] Check for updates first");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!UpdateManager.IsUpdateAvailable)
|
||||
{
|
||||
PluginCore.WriteToChat("[Update] No update available");
|
||||
return;
|
||||
}
|
||||
|
||||
// Run update installation asynchronously
|
||||
System.Threading.Tasks.Task.Run(async () =>
|
||||
{
|
||||
await UpdateManager.DownloadAndInstallUpdateAsync();
|
||||
// Update UI (VVS controls are thread-safe for simple property updates)
|
||||
try
|
||||
{
|
||||
RefreshUpdateStatus();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error updating UI after install: {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error installing update: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void RefreshUpdateStatus()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (instance?.lblUpdateStatus != null)
|
||||
{
|
||||
if (UpdateManager.LastCheckTime == DateTime.MinValue)
|
||||
{
|
||||
// Not checked yet
|
||||
instance.lblUpdateStatus.Text = "";
|
||||
}
|
||||
else if (UpdateManager.IsUpdateAvailable)
|
||||
{
|
||||
// Update available
|
||||
instance.lblUpdateStatus.Text = "Update available";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Up to date
|
||||
instance.lblUpdateStatus.Text = "Up to date";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error refreshing update status: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshUpdateStatusInstance()
|
||||
{
|
||||
RefreshUpdateStatus();
|
||||
}
|
||||
|
||||
public static void DebugUpdateControls()
|
||||
{
|
||||
try
|
||||
{
|
||||
PluginCore.WriteToChat("=== Update UI Debug (Main Tab) ===");
|
||||
PluginCore.WriteToChat($"Instance exists: {instance != null}");
|
||||
if (instance != null)
|
||||
{
|
||||
PluginCore.WriteToChat($"btnCheckUpdate: {instance.btnCheckUpdate != null}");
|
||||
PluginCore.WriteToChat($"btnInstallUpdate: {instance.btnInstallUpdate != null}");
|
||||
PluginCore.WriteToChat($"lblUpdateStatus: {instance.lblUpdateStatus != null}");
|
||||
|
||||
if (instance.lblUpdateStatus != null)
|
||||
{
|
||||
PluginCore.WriteToChat($"Current status text: '{instance.lblUpdateStatus.Text}'");
|
||||
}
|
||||
|
||||
PluginCore.WriteToChat($"UpdateManager.LastCheckTime: {UpdateManager.LastCheckTime}");
|
||||
PluginCore.WriteToChat($"UpdateManager.IsUpdateAvailable: {UpdateManager.IsUpdateAvailable}");
|
||||
|
||||
// Try to force refresh
|
||||
RefreshUpdateStatus();
|
||||
PluginCore.WriteToChat("Forced refresh completed");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Debug error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadCurrentSettings()
|
||||
{
|
||||
try
|
||||
|
|
@ -875,6 +1016,10 @@ namespace MosswartMassacre.Views
|
|||
txtCharTag.Change -= OnCharTagChanged;
|
||||
if (txtVTankPath != null)
|
||||
txtVTankPath.Change -= OnVTankPathChanged;
|
||||
if (btnCheckUpdate != null)
|
||||
btnCheckUpdate.Hit -= OnCheckUpdateClicked;
|
||||
if (btnInstallUpdate != null)
|
||||
btnInstallUpdate.Hit -= OnInstallUpdateClicked;
|
||||
|
||||
// Statistics tab event cleanup
|
||||
if (btnResetStats != null)
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,5 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Costura.Fody" version="5.7.0" targetFramework="net48" />
|
||||
<package id="Fody" version="6.8.0" targetFramework="net48" />
|
||||
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net48" />
|
||||
<package id="YamlDotNet" version="16.3.0" targetFramework="net48" />
|
||||
</packages>
|
||||
Loading…
Add table
Add a link
Reference in a new issue