You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
v0.1.10: skip imports + pre-existing fights + Import/Merge zone
Two reported bugs:
1. Importing a log file made the plugin auto-upload the historical
fights it brought in. New rule: skip any encounter whose StartTime
is more than InstanceStartGraceSeconds (= 5 min) before the
plugin's own startup. Catches three scenarios with one check:
* user enabled the plugin mid-session (pre-existing fights)
* user imported a log file after enabling
* ACT auto-loaded logs at startup before plugin init
5-minute grace accommodates an in-progress fight that started just
before plugin-enable. The manual right-click upload path
intentionally does NOT enforce this — it's the escape hatch for
"yes actually, please upload that older one".
2. Merged/edited encounters in ACT's "Import/Merge" zone were
uploadable. New rule: never upload from Import/Merge — in the auto
path it's skipped with a visible reason, in the right-click menu
it's greyed out, and Plugin.OnManualUploadRequested re-checks
defensively in case a fast click races the Opening handler.
Merged parses are user-customised (combining two real fights into
an aggregate that doesn't correspond to any single in-game event)
and would pollute the leaderboard with parses that didn't happen
as shown.
Implementation:
* New src/Core/EncounterZone.cs with IsImportOrMerge(zoneName) —
same pure-Core-testable-without-ACT pattern as EncounterTitle.
* EncounterCapture.Poll: two new skip branches above the existing
placeholder-title one. All three now share a tiny
MarkProcessedNoCapture helper so the lock+queue+cap eviction
isn't duplicated.
* ActMenuExtension.OnMenuOpening: greys out the menu item for
Import/Merge in addition to the existing "no real encounter
selected" condition.
* Plugin.OnManualUploadRequested: defensive Import/Merge re-check
surfaced as "manual upload skipped (Import/Merge zone — ...)".
CLAUDE.md updated: the manual-upload gate matrix now lists both new
gates explicitly, and EncounterCapture's Key files entry calls out
all three skip reasons. 13 new tests in EncounterZoneTests pinning
the synthetic-zone string. Total 144/144.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CLAUDE.md
+4-1Lines changed: 4 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,9 +25,10 @@ The split also unlocks GitHub Actions CI: the workflow at `.github/workflows/ci.
25
25
|---|---|
26
26
|`src/Plugin.cs`|`IActPluginV1` entry point. ACT calls `InitPlugin`/`DeInitPlugin`. Resolves the config path via `ActHelpers.GetConfigPath()` and passes it to `PluginConfig.Load`/`Save`. Owns lifecycles of `PluginConfig`, `SettingsPanel`, `EncounterCapture`, `UploadClient`. |
27
27
|`src/SettingsPanel.cs`| WinForms settings UI hosted in ACT's plugin tab. Dark-theme card layout (`T` static class holds every colour). Three cards: Configuration / Logging As / Last Captured. Persistence happens via the `_onSave` callback so the panel stays path-free. |
28
-
|`src/EncounterCapture.cs`| 2 s polling timer over `ActGlobals.oFormActMain.ActiveZone`. Detects "settled" encounters (no `EndTime` update for `SettleSeconds=15`), converts to `EncounterSnapshot` via the public static `CaptureSnapshot` (reused by the manual-upload path), then calls `PayloadBuilder.BuildPayload` → `SanitizePayload` → `SerializeJson`. Defers placeholder-titled encounters via `EncounterTitle.IsPlaceholder` for up to `MaxPlaceholderWaitSeconds=60` (then raises `OnSkipped` with a user-visible reason). |
28
+
|`src/EncounterCapture.cs`| 2 s polling timer over `ActGlobals.oFormActMain.ActiveZone`. Detects "settled" encounters (no `EndTime` update for `SettleSeconds=15`), converts to `EncounterSnapshot` via the public static `CaptureSnapshot` (reused by the manual-upload path), then calls `PayloadBuilder.BuildPayload` → `SanitizePayload` → `SerializeJson`. Skip reasons (all raise `OnSkipped` with a user-visible message): Import/Merge zone, encounter started before `_instanceStartedAt - InstanceStartGraceSeconds` (= log imports + pre-existing fights), placeholder title that didn't resolve within `MaxPlaceholderWaitSeconds`. The three skip branches share `MarkProcessedNoCapture` so the encid eviction logic isn't duplicated. |
29
29
|`src/ActMenuExtension.cs`| Adds "Upload to EQ2 Lexicon" to ACT's right-click encounter menu. See "ACT UI extension" below for the (undocumented) wiring details. |
30
30
|`src/Core/EncounterTitle.cs`|`IsPlaceholder(title)` — the shared predicate used by both the polling and manual-upload paths to reject encounters ACT hasn't named yet ("Encounter", "Unknown", empty/whitespace). Lives in Core so it's testable without ACT. |
31
+
|`src/Core/EncounterZone.cs`|`IsImportOrMerge(zoneName)` — the shared predicate used by the polling path, the right-click menu's Opening handler (greys out the item), and Plugin's manual-upload handler (defensive re-check). The Import/Merge bucket holds imported logs and merged/edited encounters that we must never upload. |
31
32
|`src/ActHelpers.cs`| Reads the logging character name by parsing the active log file path (`eq2log_<name>.txt`). `ActGlobals.charName` returns `"YOU"` in EQ2 so it can't be used. Also owns `GetConfigPath()` — the `%APPDATA%\Advanced Combat Tracker\Config\` resolver kept here so `PluginConfig` stays ACT-free. |
32
33
|`src/Core/PayloadBuilder.cs`| Pure transform: `EncounterSnapshot` → ingest-JSON dict shape. Owns `OutgoingGroupToSwingType`, `FormatTime` (emits ISO-8601 + Z), `SanitizePayload` (replaces NaN/∞ with 0), and `SerializeJson` (JavaScriptSerializer with an 8 MB ceiling). |
33
34
|`src/Core/Snapshots.cs`| Plain DTOs (`EncounterSnapshot`, `CombatantSnapshot`, `DamageTypeAggregate`, `AttackTypeSnapshot`) that mirror the slice of ACT's data model the payload builder reads. |
@@ -161,6 +162,8 @@ Different from the polling path — bypasses user opt-in gates because the click
0 commit comments