feat(vitalsharing): verbose logging toggle for VTank feed tracing

Adds a Verbose Logging checkbox on the Settings tab (backed by the
existing PluginSettings.VerboseLogging flag) plus trace lines in
VitalSharingTracker so you can verify cross-PC coordination is actually
reaching VTank.

When enabled, chat logs will include:
  [VitalShare] SEND share_cast_attempt ...
  [VitalShare] SEND share_cast_success ...
  [VitalShare→VTank] HelperPlayerUpdate <name> HP=.../... S=.../... M=.../...
  [VitalShare→VTank] LogCastAttempt from <name>: spell=X target=0xY
  [VitalShare→VTank] LogSpellCast from <name>: spell=X target=0xY duration=Zms
  [VitalShare→VTank] SKIP ... (with reason when vTank.Instance is null
  or the target isn't a valid local object)

No overhead when the toggle is off — VerboseLog() short-circuits before
formatting the message arguments, matching the existing log-gating
pattern in the codebase.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-11 15:09:55 +02:00
parent 62a9067125
commit 2b6e3cc4fc
4 changed files with 70 additions and 5 deletions

View file

@ -42,6 +42,9 @@
<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"/>
<!-- Verbose logging -->
<control progid="DecalControls.Checkbox" name="chkVerboseLogging" left="20" top="230" width="300" height="20" text="Verbose logging (vital sharing / VTank feed)" checked="false"/>
<!-- Character tag setting -->
<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"/>

View file

@ -34,6 +34,7 @@ namespace MosswartMassacre.Views
private HudCheckBox chkAutoUpdateEnabled;
private HudCheckBox chkVitalSharingEnabled;
private HudButton btnVitalSharingOverlay;
private HudCheckBox chkVerboseLogging;
private HudTextBox txtCharTag;
private HudTextBox txtVTankPath;
#endregion
@ -233,6 +234,7 @@ namespace MosswartMassacre.Views
chkAutoUpdateEnabled = GetControl<HudCheckBox>("chkAutoUpdateEnabled");
chkVitalSharingEnabled = GetControl<HudCheckBox>("chkVitalSharingEnabled");
btnVitalSharingOverlay = GetControl<HudButton>("btnVitalSharingOverlay");
chkVerboseLogging = GetControl<HudCheckBox>("chkVerboseLogging");
txtCharTag = GetControl<HudTextBox>("txtCharTag");
txtVTankPath = GetControl<HudTextBox>("txtVTankPath");
@ -247,6 +249,8 @@ namespace MosswartMassacre.Views
chkVitalSharingEnabled.Change += OnVitalSharingSettingChanged;
if (btnVitalSharingOverlay != null)
btnVitalSharingOverlay.Hit += OnVitalSharingOverlayClicked;
if (chkVerboseLogging != null)
chkVerboseLogging.Change += OnVerboseLoggingSettingChanged;
if (txtCharTag != null)
txtCharTag.Change += OnCharTagChanged;
if (txtVTankPath != null)
@ -496,6 +500,19 @@ namespace MosswartMassacre.Views
}
}
private void OnVerboseLoggingSettingChanged(object sender, EventArgs e)
{
try
{
PluginSettings.Instance.VerboseLogging = chkVerboseLogging.Checked;
PluginCore.WriteToChat($"Verbose logging {(chkVerboseLogging.Checked ? "ENABLED" : "DISABLED")}.");
}
catch (Exception ex)
{
PluginCore.WriteToChat($"Error in verbose logging setting change: {ex.Message}");
}
}
private void OnVTankPathChanged(object sender, EventArgs e)
{
try
@ -651,6 +668,8 @@ namespace MosswartMassacre.Views
{
if (chkVitalSharingEnabled != null)
chkVitalSharingEnabled.Checked = PluginSettings.Instance.VitalSharingEnabled;
if (chkVerboseLogging != null)
chkVerboseLogging.Checked = PluginSettings.Instance.VerboseLogging;
if (chkRareMetaEnabled != null)
chkRareMetaEnabled.Checked = PluginSettings.Instance.RareMetaEnabled;
if (chkWebSocketEnabled != null)

View file

@ -259,7 +259,11 @@ namespace MosswartMassacre
{
try
{
if (vTank.Instance == null) return;
if (vTank.Instance == null)
{
VerboseLog($"[VitalShare→VTank] SKIP HelperPlayerUpdate ({fromChar}): vTank.Instance is null");
return;
}
var info = new sPlayerInfoUpdate
{
PlayerID = playerId,
@ -274,6 +278,7 @@ namespace MosswartMassacre
maxStam = maxS,
};
vTank.Instance.HelperPlayerUpdate(info);
VerboseLog($"[VitalShare→VTank] HelperPlayerUpdate {fromChar} (0x{playerId:X8}) HP={curH}/{maxH} S={curS}/{maxS} M={curM}/{maxM}");
}
catch (Exception ex) { _logger?.Log($"[VitalShare] HelperPlayerUpdate error: {ex.Message}"); }
});
@ -320,9 +325,18 @@ namespace MosswartMassacre
{
try
{
if (vTank.Instance == null) return;
if (!CoreManager.Current.Actions.IsValidObject(target)) return;
if (vTank.Instance == null)
{
VerboseLog($"[VitalShare→VTank] SKIP LogCastAttempt (from {fromChar}): vTank.Instance is null");
return;
}
if (!CoreManager.Current.Actions.IsValidObject(target))
{
VerboseLog($"[VitalShare→VTank] SKIP LogCastAttempt (from {fromChar}): target 0x{target:X8} not a valid object locally");
return;
}
vTank.Instance.LogCastAttempt(spellId, target, (int)skill);
VerboseLog($"[VitalShare→VTank] LogCastAttempt from {fromChar}: spell={spellId} target=0x{target:X8} skill={(int)skill}");
}
catch (Exception ex) { _logger?.Log($"[VitalShare] LogCastAttempt error: {ex.Message}"); }
});
@ -343,9 +357,18 @@ namespace MosswartMassacre
{
try
{
if (vTank.Instance == null) return;
if (!CoreManager.Current.Actions.IsValidObject(target)) return;
if (vTank.Instance == null)
{
VerboseLog($"[VitalShare→VTank] SKIP LogSpellCast (from {fromChar}): vTank.Instance is null");
return;
}
if (!CoreManager.Current.Actions.IsValidObject(target))
{
VerboseLog($"[VitalShare→VTank] SKIP LogSpellCast (from {fromChar}): target 0x{target:X8} not a valid object locally");
return;
}
vTank.Instance.LogSpellCast(target, spellId, duration);
VerboseLog($"[VitalShare→VTank] LogSpellCast from {fromChar}: spell={spellId} target=0x{target:X8} duration={duration}ms");
}
catch (Exception ex) { _logger?.Log($"[VitalShare] LogSpellCast error: {ex.Message}"); }
});
@ -542,6 +565,7 @@ namespace MosswartMassacre
skill = skill,
};
_ = WebSocket.SendVitalShareAsync(payload);
VerboseLog($"[VitalShare] SEND share_cast_attempt spell={spellId} target=0x{target:X8} skill={(int)skill}");
}
catch (Exception ex)
{
@ -603,6 +627,7 @@ namespace MosswartMassacre
duration_ms = durationMs,
};
_ = WebSocket.SendVitalShareAsync(payload);
VerboseLog($"[VitalShare] SEND share_cast_success spell={spellId} target=0x{target:X8} duration={durationMs}ms");
}
catch (Exception ex)
{
@ -715,6 +740,24 @@ namespace MosswartMassacre
// --- Helpers ---
/// <summary>
/// Logs a message routed to the plugin chat window, but ONLY when
/// PluginSettings.VerboseLogging is true. Used to trace every
/// VTank feeding event (HelperPlayerUpdate / LogCastAttempt /
/// LogSpellCast) so the user can verify cross-PC coordination is
/// actually reaching VTank.
/// </summary>
private void VerboseLog(string message)
{
try
{
if (!PluginSettings.IsInitialized) return;
if (!PluginSettings.Instance.VerboseLogging) return;
PluginCore.WriteToChat(message);
}
catch { }
}
private string SafeCharacterName()
{
try { return CoreManager.Current.CharacterFilter.Name ?? ""; }