The first sweep matched a character class that swallowed the digit, so a bare B1 slipped through while B1-2 was caught. Searching the whole A-Z space instead of guessing prefixes turned up 130-odd more: B0 through B6, C2, C3, D1, H2, M6, P7, P8, T2, W2, plus GP-04, KB-01, OD-1, PM-1, PM-3, SEC-01, TR-4, TR-7, UI-11, UI-12, XC-8 and API-3. Kept deliberately: 41 B4 01 is a byte signature, "N0" a format string, #L119-L128 a source anchor, LS4/LS6 are linkshells, and A=FF B=0C G=41 R=C2 explains a colour-channel order. Those look like codes and are not. Also translated the eight German comments left in the theme files and ImGuiUtil. Seven of them described what a palette does to which channel, which is worth reading -- just not in a second language in an otherwise English codebase.
142 lines
5.0 KiB
C#
142 lines
5.0 KiB
C#
using Dalamud.Bindings.ImGui;
|
|
using Dalamud.Plugin.SelfTest;
|
|
using HellionChat.Code;
|
|
using HellionChat.GameFunctions.Types;
|
|
|
|
namespace HellionChat.SelfTests;
|
|
|
|
// Guided: interactive, fires NO synthetic probes. Shows the full measured
|
|
// state every frame so a result is observable, not a guess, and walks the user
|
|
// through the real switch-away-and-back flow. It verifies the PRIVACY-relevant
|
|
// effect, keyed on the tab type:
|
|
// - a NORMAL tab carrying a game-side tell must lose its RUNTIME target
|
|
// (CurrentChannel.TellTarget) on switch-away-and-back, so a
|
|
// typed line can't /tell the old partner;
|
|
// - a BOUND auto-tell tab keeps its partner by design (leg1) — its binding is
|
|
// Tab.TellTarget and is deliberately untouched by the strip.
|
|
// The channel label is intentionally NOT asserted: a tell tab re-derives back to
|
|
// Tell after the strip ; only the target matters for privacy.
|
|
internal sealed class CurrentTabGuidedStep : ISelfTestStep
|
|
{
|
|
private readonly Plugin _plugin;
|
|
|
|
// 0 = waiting for a tell; 1 = tell seen, waiting to switch AWAY; 2 = switched
|
|
// away, waiting to come BACK to the tracked tab.
|
|
private int _phase;
|
|
private Tab? _tellTab;
|
|
private bool _wasBound;
|
|
private string _seenPartner = "";
|
|
|
|
public CurrentTabGuidedStep(Plugin plugin)
|
|
{
|
|
_plugin = plugin;
|
|
}
|
|
|
|
public string Name => "Hellion Chat - Tell target cleared on tab switch (guided)";
|
|
|
|
public SelfTestStepResult RunStep()
|
|
{
|
|
var active = _plugin.CurrentTab;
|
|
var cc = active.CurrentChannel;
|
|
var bound = active.TellTarget?.IsSet() == true;
|
|
var runtime = cc.TellTarget?.IsSet() == true;
|
|
|
|
// Live diagnostics every frame — a result is never a guess.
|
|
ImGui.Text($"Active tab : {active.Name}");
|
|
ImGui.Text($"Channel : {cc.Channel}");
|
|
ImGui.Text($"Runtime target : {DescribeTarget(cc.TellTarget)}");
|
|
ImGui.Text($"Tab-bound (leg1): {(bound ? $"yes -> {active.TellTarget!.Name}" : "no")}");
|
|
if (_tellTab is not null)
|
|
ImGui.Text(
|
|
$"Tracking '{_tellTab.Name}' (bound: {_wasBound}, partner: {_seenPartner})"
|
|
);
|
|
ImGui.Separator();
|
|
|
|
if (ImGui.Button("Skip##guided-tellflow"))
|
|
{
|
|
ImGui.Text("Skipped by user — not verified.");
|
|
return SelfTestStepResult.Pass;
|
|
}
|
|
|
|
// Restart cleanly if the tracked tab is evicted mid-flow.
|
|
if (_tellTab is not null && !Plugin.Config.Tabs.Contains(_tellTab))
|
|
{
|
|
ImGui.Text(">> Tracked tab was removed; restarting.");
|
|
Reset();
|
|
}
|
|
|
|
if (_phase == 0)
|
|
{
|
|
ImGui.Text(">> Step 1: get a tab into Tell — /tell from a normal tab (stay on it),");
|
|
ImGui.Text(" or open an auto-tell tab. Watch the lines above update.");
|
|
if (cc.Channel == InputChannel.Tell && (runtime || bound))
|
|
{
|
|
_tellTab = active;
|
|
_wasBound = bound;
|
|
_seenPartner = bound ? active.TellTarget!.Name : cc.TellTarget!.Name;
|
|
_phase = 1;
|
|
}
|
|
|
|
return SelfTestStepResult.Waiting;
|
|
}
|
|
|
|
if (_phase == 1)
|
|
{
|
|
ImGui.Text(">> Step 2: now click AWAY to a different tab.");
|
|
if (!ReferenceEquals(active, _tellTab))
|
|
_phase = 2;
|
|
|
|
return SelfTestStepResult.Waiting;
|
|
}
|
|
|
|
// _phase == 2: switched away; wait to come BACK, then check the target.
|
|
ImGui.Text($">> Step 3: now click BACK onto '{_tellTab!.Name}'.");
|
|
if (!ReferenceEquals(active, _tellTab))
|
|
return SelfTestStepResult.Waiting;
|
|
|
|
if (_wasBound)
|
|
{
|
|
// leg1: the binding lives on Tab.TellTarget and must survive the strip.
|
|
if (_tellTab.TellTarget?.IsSet() == true)
|
|
{
|
|
ImGui.Text(
|
|
"PASS: bound auto-tell tab kept its partner (leg1 — the conversation stays)."
|
|
);
|
|
return SelfTestStepResult.Pass;
|
|
}
|
|
|
|
ImGui.Text(
|
|
$"FAIL: bound tab LOST partner '{_seenPartner}' — leg1 was wrongly stripped."
|
|
);
|
|
return SelfTestStepResult.Fail;
|
|
}
|
|
|
|
// non-bound: the stale RUNTIME target must be gone (the privacy strip).
|
|
if (_tellTab.CurrentChannel.TellTarget?.IsSet() != true)
|
|
{
|
|
ImGui.Text(
|
|
$"PASS: stale partner '{_seenPartner}' cleared — a typed line won't /tell them."
|
|
);
|
|
return SelfTestStepResult.Pass;
|
|
}
|
|
|
|
ImGui.Text(
|
|
"FAIL: stale runtime partner still bound after switch-away-and-back — privacy leak."
|
|
);
|
|
return SelfTestStepResult.Fail;
|
|
}
|
|
|
|
private static string DescribeTarget(TellTarget? t) =>
|
|
t?.IsSet() == true ? $"{t.Name} (World {t.World})" : "none";
|
|
|
|
private void Reset()
|
|
{
|
|
_phase = 0;
|
|
_tellTab = null;
|
|
_wasBound = false;
|
|
_seenPartner = "";
|
|
}
|
|
|
|
public void CleanUp() => Reset();
|
|
}
|