feat(vitalsharing): settings UI, in-game overlay, reuse CharTag
- Settings tab: new "Vital Sharing (cross-PC)" checkbox + "Open Overlay" button, plus help text clarifying CharTag is used as the sharing group. - Drop separate VitalSharingTags list — reuse PluginSettings.CharTag as the single tag value sent with every share_* payload. - New VitalSharingOverlayView (HudList of peers with coloured HP/STA/MANA percentages) modeled after UB's NetworkUI. Colours match the web sidebar palette (#ff4444 / #ffaa00 / #4488ff). - VitalSharingTracker now caches a peer snapshot on every inbound share_vital_update so the overlay can render without re-polling. - PluginCore.SetVitalSharingEnabled static helper so the settings checkbox can toggle without poking at private fields. - /mm vitalsharing command simplified to on|off|status|overlay. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b87412e8f9
commit
29a54b720f
9 changed files with 304 additions and 81 deletions
|
|
@ -350,6 +350,7 @@
|
|||
<Compile Include="Views\FlagTrackerView.cs" />
|
||||
<Compile Include="Views\VVSBaseView.cs" />
|
||||
<Compile Include="Views\VVSTabbedMainView.cs" />
|
||||
<Compile Include="Views\VitalSharingOverlayView.cs" />
|
||||
<Compile Include="CharacterStats.cs" />
|
||||
<Compile Include="DungeonMapReader.cs" />
|
||||
<Compile Include="NearbyObjectsTracker.cs" />
|
||||
|
|
@ -366,6 +367,7 @@
|
|||
<EmbeddedResource Include="ViewXML\flagTracker.xml" />
|
||||
<EmbeddedResource Include="ViewXML\mainView.xml" />
|
||||
<EmbeddedResource Include="ViewXML\mainViewTabbed.xml" />
|
||||
<EmbeddedResource Include="ViewXML\vitalSharingOverlay.xml" />
|
||||
<EmbeddedResource Include="..\Shared\Spells\Spells.csv">
|
||||
<Link>Shared\Spells\Spells.csv</Link>
|
||||
</EmbeddedResource>
|
||||
|
|
|
|||
|
|
@ -148,11 +148,38 @@ namespace MosswartMassacre
|
|||
private EquipmentCantripStateTracker _equipmentCantripStateTracker;
|
||||
private NearbyObjectsTracker _nearbyObjectsTracker;
|
||||
private VitalSharingTracker _vitalSharingTracker;
|
||||
private static PluginCore _instance;
|
||||
public static VitalSharingTracker VitalSharingTracker => _instance?._vitalSharingTracker;
|
||||
|
||||
public static void SetVitalSharingEnabled(bool enabled)
|
||||
{
|
||||
try
|
||||
{
|
||||
PluginSettings.Instance.VitalSharingEnabled = enabled;
|
||||
var tracker = _instance?._vitalSharingTracker;
|
||||
if (tracker == null) return;
|
||||
if (enabled)
|
||||
{
|
||||
tracker.Start();
|
||||
WriteToChat("[VitalShare] ENABLED");
|
||||
}
|
||||
else
|
||||
{
|
||||
tracker.Stop();
|
||||
WriteToChat("[VitalShare] DISABLED");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteToChat($"[VitalShare] Toggle error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
try
|
||||
{
|
||||
_instance = this;
|
||||
// Set MyHost - for hot reload scenarios, Host might be null
|
||||
if (Host != null)
|
||||
{
|
||||
|
|
@ -1149,7 +1176,7 @@ namespace MosswartMassacre
|
|||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
WriteToChat("Usage: /mm vitalsharing <on|off|status|tag add <name>|tag remove <name>|tags>");
|
||||
WriteToChat("Usage: /mm vitalsharing <on|off|status|overlay>");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1162,82 +1189,26 @@ namespace MosswartMassacre
|
|||
WriteToChat("[VitalShare] WebSocket must be enabled first. Run /mm ws enable");
|
||||
return;
|
||||
}
|
||||
PluginSettings.Instance.VitalSharingEnabled = true;
|
||||
_vitalSharingTracker?.Start();
|
||||
WriteToChat("[VitalShare] ENABLED (will stream to Overlord)");
|
||||
SetVitalSharingEnabled(true);
|
||||
}
|
||||
else if (sub == "off")
|
||||
{
|
||||
PluginSettings.Instance.VitalSharingEnabled = false;
|
||||
_vitalSharingTracker?.Stop();
|
||||
WriteToChat("[VitalShare] DISABLED");
|
||||
SetVitalSharingEnabled(false);
|
||||
}
|
||||
else if (sub == "status")
|
||||
{
|
||||
var enabled = PluginSettings.Instance.VitalSharingEnabled;
|
||||
var active = _vitalSharingTracker?.IsActive == true;
|
||||
var tags = PluginSettings.Instance.VitalSharingTags;
|
||||
var tagStr = (tags == null || tags.Count == 0) ? "(none)" : string.Join(", ", tags);
|
||||
WriteToChat($"[VitalShare] enabled={enabled} active={active} tags={tagStr}");
|
||||
var tag = PluginSettings.Instance.CharTag ?? "";
|
||||
WriteToChat($"[VitalShare] enabled={enabled} active={active} tag='{tag}'");
|
||||
}
|
||||
else if (sub == "tags")
|
||||
else if (sub == "overlay")
|
||||
{
|
||||
var tags = PluginSettings.Instance.VitalSharingTags;
|
||||
if (tags == null || tags.Count == 0)
|
||||
WriteToChat("[VitalShare] No tags set");
|
||||
else
|
||||
WriteToChat("[VitalShare] Tags: " + string.Join(", ", tags));
|
||||
}
|
||||
else if (sub == "tag")
|
||||
{
|
||||
if (args.Length < 4)
|
||||
{
|
||||
WriteToChat("Usage: /mm vitalsharing tag <add|remove> <name>");
|
||||
return;
|
||||
}
|
||||
var action = args[2].ToLowerInvariant();
|
||||
var name = args[3].Trim();
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
WriteToChat("Tag name cannot be empty");
|
||||
return;
|
||||
}
|
||||
var tags = PluginSettings.Instance.VitalSharingTags ?? new System.Collections.Generic.List<string>();
|
||||
if (action == "add")
|
||||
{
|
||||
if (!tags.Contains(name, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
tags.Add(name);
|
||||
PluginSettings.Instance.VitalSharingTags = tags;
|
||||
WriteToChat($"[VitalShare] Added tag: {name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteToChat($"[VitalShare] Tag already set: {name}");
|
||||
}
|
||||
}
|
||||
else if (action == "remove")
|
||||
{
|
||||
var match = tags.Find(t => t.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
if (match != null)
|
||||
{
|
||||
tags.Remove(match);
|
||||
PluginSettings.Instance.VitalSharingTags = tags;
|
||||
WriteToChat($"[VitalShare] Removed tag: {name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteToChat($"[VitalShare] Tag not found: {name}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteToChat("Usage: /mm vitalsharing tag <add|remove> <name>");
|
||||
}
|
||||
Views.VitalSharingOverlayView.ToggleWindow();
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteToChat("Usage: /mm vitalsharing <on|off|status|tag add <name>|tag remove <name>|tags>");
|
||||
WriteToChat("Usage: /mm vitalsharing <on|off|status|overlay>");
|
||||
}
|
||||
}, "Enable/disable vital sharing with other MosswartOverlord clients");
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ namespace MosswartMassacre
|
|||
private bool _verboseLogging = false;
|
||||
private bool _autoUpdateEnabled = true;
|
||||
private bool _vitalSharingEnabled = false;
|
||||
private List<string> _vitalSharingTags = new List<string>();
|
||||
private ChestLooterSettings _chestLooterSettings = new ChestLooterSettings();
|
||||
|
||||
public static PluginSettings Instance => _instance
|
||||
|
|
@ -205,16 +204,6 @@ namespace MosswartMassacre
|
|||
set { _vitalSharingEnabled = value; Save(); }
|
||||
}
|
||||
|
||||
public List<string> VitalSharingTags
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_vitalSharingTags == null) _vitalSharingTags = new List<string>();
|
||||
return _vitalSharingTags;
|
||||
}
|
||||
set { _vitalSharingTags = value ?? new List<string>(); Save(); }
|
||||
}
|
||||
|
||||
public ChestLooterSettings ChestLooterSettings
|
||||
{
|
||||
get
|
||||
|
|
|
|||
|
|
@ -38,10 +38,15 @@
|
|||
<!-- Auto-update setting -->
|
||||
<control progid="DecalControls.Checkbox" name="chkAutoUpdateEnabled" left="20" top="85" width="300" height="20" text="Auto install plugin updates" checked="true"/>
|
||||
|
||||
<!-- Vital sharing setting -->
|
||||
<control progid="DecalControls.Checkbox" name="chkVitalSharingEnabled" left="20" top="110" width="200" height="20" text="Vital Sharing (cross-PC)" checked="false"/>
|
||||
<control progid="DecalControls.PushButton" name="btnVitalSharingOverlay" left="220" top="108" width="100" height="22" text="Open Overlay"/>
|
||||
|
||||
<!-- Character tag setting -->
|
||||
<control progid="DecalControls.StaticText" name="lblCharTag" left="20" top="115" width="100" height="16" text="Character Tag:"/>
|
||||
<control progid="DecalControls.Edit" name="txtCharTag" left="125" top="113" width="150" height="20" text="default"/>
|
||||
|
||||
<control progid="DecalControls.StaticText" name="lblCharTag" left="20" top="140" width="100" height="16" text="Character Tag:"/>
|
||||
<control progid="DecalControls.Edit" name="txtCharTag" left="125" top="138" width="150" height="20" text="default"/>
|
||||
<control progid="DecalControls.StaticText" name="lblCharTagHelp" left="20" top="160" width="350" height="16" text="Used for telemetry and vital sharing groups."/>
|
||||
|
||||
<!-- VTank profiles path setting -->
|
||||
<control progid="DecalControls.StaticText" name="lblVTankPath" left="20" top="190" width="100" height="16" text="VTank Profiles:"/>
|
||||
<control progid="DecalControls.Edit" name="txtVTankPath" left="125" top="188" width="200" height="20" text=""/>
|
||||
|
|
|
|||
11
MosswartMassacre/ViewXML/vitalSharingOverlay.xml
Normal file
11
MosswartMassacre/ViewXML/vitalSharingOverlay.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0"?>
|
||||
<view icon="7735" title="Vital Sharing" width="360" height="260">
|
||||
<control progid="DecalControls.FixedLayout" clipped="">
|
||||
<control progid="DecalControls.StaticText" name="lblHeader" left="8" top="6" width="340" height="16" text="Vital Sharing Peers" style="FontBold"/>
|
||||
<control progid="DecalControls.StaticText" name="lblCol0" left="8" top="24" width="160" height="14" text="Character"/>
|
||||
<control progid="DecalControls.StaticText" name="lblCol1" left="170" top="24" width="55" height="14" text="HP"/>
|
||||
<control progid="DecalControls.StaticText" name="lblCol2" left="227" top="24" width="55" height="14" text="Stam"/>
|
||||
<control progid="DecalControls.StaticText" name="lblCol3" left="284" top="24" width="55" height="14" text="Mana"/>
|
||||
<control progid="DecalControls.List" name="lstPeers" left="6" top="42" width="340" height="200"/>
|
||||
</control>
|
||||
</view>
|
||||
|
|
@ -32,6 +32,8 @@ namespace MosswartMassacre.Views
|
|||
private HudCheckBox chkRareMetaEnabled;
|
||||
private HudCheckBox chkWebSocketEnabled;
|
||||
private HudCheckBox chkAutoUpdateEnabled;
|
||||
private HudCheckBox chkVitalSharingEnabled;
|
||||
private HudButton btnVitalSharingOverlay;
|
||||
private HudTextBox txtCharTag;
|
||||
private HudTextBox txtVTankPath;
|
||||
#endregion
|
||||
|
|
@ -229,9 +231,11 @@ namespace MosswartMassacre.Views
|
|||
chkRareMetaEnabled = GetControl<HudCheckBox>("chkRareMetaEnabled");
|
||||
chkWebSocketEnabled = GetControl<HudCheckBox>("chkWebSocketEnabled");
|
||||
chkAutoUpdateEnabled = GetControl<HudCheckBox>("chkAutoUpdateEnabled");
|
||||
chkVitalSharingEnabled = GetControl<HudCheckBox>("chkVitalSharingEnabled");
|
||||
btnVitalSharingOverlay = GetControl<HudButton>("btnVitalSharingOverlay");
|
||||
txtCharTag = GetControl<HudTextBox>("txtCharTag");
|
||||
txtVTankPath = GetControl<HudTextBox>("txtVTankPath");
|
||||
|
||||
|
||||
// Hook up settings events
|
||||
if (chkRareMetaEnabled != null)
|
||||
chkRareMetaEnabled.Change += OnRareMetaSettingChanged;
|
||||
|
|
@ -239,6 +243,10 @@ namespace MosswartMassacre.Views
|
|||
chkWebSocketEnabled.Change += OnWebSocketSettingChanged;
|
||||
if (chkAutoUpdateEnabled != null)
|
||||
chkAutoUpdateEnabled.Change += OnAutoUpdateSettingChanged;
|
||||
if (chkVitalSharingEnabled != null)
|
||||
chkVitalSharingEnabled.Change += OnVitalSharingSettingChanged;
|
||||
if (btnVitalSharingOverlay != null)
|
||||
btnVitalSharingOverlay.Hit += OnVitalSharingOverlayClicked;
|
||||
if (txtCharTag != null)
|
||||
txtCharTag.Change += OnCharTagChanged;
|
||||
if (txtVTankPath != null)
|
||||
|
|
@ -464,6 +472,30 @@ namespace MosswartMassacre.Views
|
|||
}
|
||||
}
|
||||
|
||||
private void OnVitalSharingSettingChanged(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
PluginCore.SetVitalSharingEnabled(chkVitalSharingEnabled.Checked);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error in vital sharing setting change: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnVitalSharingOverlayClicked(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
VitalSharingOverlayView.ToggleWindow();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"Error opening vital sharing overlay: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnVTankPathChanged(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
|
|
@ -617,6 +649,8 @@ namespace MosswartMassacre.Views
|
|||
{
|
||||
if (PluginSettings.IsInitialized)
|
||||
{
|
||||
if (chkVitalSharingEnabled != null)
|
||||
chkVitalSharingEnabled.Checked = PluginSettings.Instance.VitalSharingEnabled;
|
||||
if (chkRareMetaEnabled != null)
|
||||
chkRareMetaEnabled.Checked = PluginSettings.Instance.RareMetaEnabled;
|
||||
if (chkWebSocketEnabled != null)
|
||||
|
|
|
|||
171
MosswartMassacre/Views/VitalSharingOverlayView.cs
Normal file
171
MosswartMassacre/Views/VitalSharingOverlayView.cs
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using VirindiViewService;
|
||||
using VirindiViewService.Controls;
|
||||
|
||||
namespace MosswartMassacre.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// In-game overlay window showing live vitals for every character that has
|
||||
/// opted-in to vital sharing via MosswartOverlord. Modeled after UB's
|
||||
/// NetworkUI — one row per peer with HP/Stamina/Mana percentages coloured
|
||||
/// to match the web sidebar palette.
|
||||
/// </summary>
|
||||
internal class VitalSharingOverlayView : VVSBaseView
|
||||
{
|
||||
private static VitalSharingOverlayView _instance;
|
||||
|
||||
private HudList _peerList;
|
||||
private System.Timers.Timer _refreshTimer;
|
||||
|
||||
// Colors matched to MosswartOverlord player sidebar
|
||||
// health: #ff4444, stamina: #ffaa00, mana: #4488ff
|
||||
private static readonly Color COLOR_HP = Color.FromArgb(255, 68, 68);
|
||||
private static readonly Color COLOR_STA = Color.FromArgb(255, 170, 0);
|
||||
private static readonly Color COLOR_MANA = Color.FromArgb(68, 136, 255);
|
||||
private static readonly Color COLOR_NAME = Color.White;
|
||||
|
||||
private VitalSharingOverlayView() : base(null)
|
||||
{
|
||||
CreateFromXMLResource("MosswartMassacre.ViewXML.vitalSharingOverlay.xml");
|
||||
Init();
|
||||
}
|
||||
|
||||
public static void ToggleWindow()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new VitalSharingOverlayView();
|
||||
_instance.Show();
|
||||
}
|
||||
else if (_instance.IsVisible)
|
||||
{
|
||||
_instance.Hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
_instance.Show();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"[VitalShare] Overlay toggle error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForceClose()
|
||||
{
|
||||
try
|
||||
{
|
||||
_instance?.Dispose();
|
||||
_instance = null;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
try
|
||||
{
|
||||
_peerList = GetControl<HudList>("lstPeers");
|
||||
if (_peerList != null)
|
||||
{
|
||||
// columns: name, hp%, sta%, mana%
|
||||
_peerList.AddColumn(typeof(HudStaticText), 160, null);
|
||||
_peerList.AddColumn(typeof(HudStaticText), 55, null);
|
||||
_peerList.AddColumn(typeof(HudStaticText), 55, null);
|
||||
_peerList.AddColumn(typeof(HudStaticText), 55, null);
|
||||
}
|
||||
|
||||
_refreshTimer = new System.Timers.Timer(500);
|
||||
_refreshTimer.AutoReset = true;
|
||||
_refreshTimer.Elapsed += (s, e) =>
|
||||
{
|
||||
try { RefreshPeers(); }
|
||||
catch (Exception ex) { PluginCore.WriteToChat($"[VitalShare] Overlay refresh error: {ex.Message}"); }
|
||||
};
|
||||
_refreshTimer.Start();
|
||||
|
||||
RefreshPeers();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.WriteToChat($"[VitalShare] Overlay init error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshPeers()
|
||||
{
|
||||
if (_peerList == null) return;
|
||||
|
||||
var snaps = VitalSharingTracker.GetPeerSnapshots();
|
||||
|
||||
_peerList.ClearRows();
|
||||
|
||||
if (snaps == null || snaps.Length == 0)
|
||||
{
|
||||
var row = _peerList.AddRow();
|
||||
((HudStaticText)row[0]).Text = "(no peers)";
|
||||
((HudStaticText)row[0]).TextColor = Color.Gray;
|
||||
((HudStaticText)row[1]).Text = "";
|
||||
((HudStaticText)row[2]).Text = "";
|
||||
((HudStaticText)row[3]).Text = "";
|
||||
return;
|
||||
}
|
||||
|
||||
Array.Sort(snaps, (a, b) =>
|
||||
string.Compare(a.CharacterName, b.CharacterName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
foreach (var p in snaps)
|
||||
{
|
||||
var row = _peerList.AddRow();
|
||||
|
||||
var name = (HudStaticText)row[0];
|
||||
name.Text = p.CharacterName;
|
||||
name.TextColor = COLOR_NAME;
|
||||
|
||||
var hp = (HudStaticText)row[1];
|
||||
hp.Text = FormatPct(p.CurrentHealth, p.MaxHealth);
|
||||
hp.TextColor = COLOR_HP;
|
||||
|
||||
var sta = (HudStaticText)row[2];
|
||||
sta.Text = FormatPct(p.CurrentStamina, p.MaxStamina);
|
||||
sta.TextColor = COLOR_STA;
|
||||
|
||||
var mana = (HudStaticText)row[3];
|
||||
mana.Text = FormatPct(p.CurrentMana, p.MaxMana);
|
||||
mana.TextColor = COLOR_MANA;
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatPct(int cur, int max)
|
||||
{
|
||||
if (max <= 0) return "--";
|
||||
int pct = (int)Math.Round(100.0 * cur / max);
|
||||
if (pct < 0) pct = 0;
|
||||
if (pct > 100) pct = 100;
|
||||
return pct + "%";
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_refreshTimer != null)
|
||||
{
|
||||
_refreshTimer.Stop();
|
||||
_refreshTimer.Dispose();
|
||||
_refreshTimer = null;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
if (_instance == this) _instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -61,6 +61,30 @@ namespace MosswartMassacre
|
|||
|
||||
public bool IsActive => _active;
|
||||
|
||||
// ── Peer snapshot state (used by the in-game overlay) ──
|
||||
public class PeerSnapshot
|
||||
{
|
||||
public string CharacterName;
|
||||
public int CurrentHealth, MaxHealth;
|
||||
public int CurrentStamina, MaxStamina;
|
||||
public int CurrentMana, MaxMana;
|
||||
public DateTime LastUpdate;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, PeerSnapshot> _peers =
|
||||
new Dictionary<string, PeerSnapshot>(StringComparer.OrdinalIgnoreCase);
|
||||
private static readonly object _peersLock = new object();
|
||||
|
||||
public static PeerSnapshot[] GetPeerSnapshots()
|
||||
{
|
||||
lock (_peersLock)
|
||||
{
|
||||
var arr = new PeerSnapshot[_peers.Count];
|
||||
_peers.Values.CopyTo(arr, 0);
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
|
||||
public VitalSharingTracker(IPluginLogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
|
|
@ -187,6 +211,20 @@ namespace MosswartMassacre
|
|||
int maxM = (int?)root["max_mana"] ?? 0;
|
||||
if (playerId == 0 || maxH == 0) return;
|
||||
|
||||
// Cache for overlay view
|
||||
lock (_peersLock)
|
||||
{
|
||||
if (!_peers.TryGetValue(fromChar, out var snap))
|
||||
{
|
||||
snap = new PeerSnapshot { CharacterName = fromChar };
|
||||
_peers[fromChar] = snap;
|
||||
}
|
||||
snap.CurrentHealth = curH; snap.MaxHealth = maxH;
|
||||
snap.CurrentStamina = curS; snap.MaxStamina = maxS;
|
||||
snap.CurrentMana = curM; snap.MaxMana = maxM;
|
||||
snap.LastUpdate = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
Enqueue(() =>
|
||||
{
|
||||
try
|
||||
|
|
@ -637,8 +675,10 @@ namespace MosswartMassacre
|
|||
{
|
||||
try
|
||||
{
|
||||
var tags = PluginSettings.Instance.VitalSharingTags;
|
||||
return tags != null ? tags.ToArray() : new string[0];
|
||||
// Reuse the existing CharTag setting as a single-value tag
|
||||
var tag = PluginSettings.Instance.CharTag;
|
||||
if (string.IsNullOrWhiteSpace(tag)) return new string[0];
|
||||
return new[] { tag };
|
||||
}
|
||||
catch { return new string[0]; }
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue