Retroactive design + plan documentation for Phase B.2 (PvP combat
detection plus six admin verb-dispatch insight classes), reconstructed
from chat history and git log. Mirrors the shape of the existing
Phase B.1 docs. Plan is as-built with checkboxes pre-checked and
commit SHAs referenced inline; Deviations section captures the
90c85a0 brace-fix interlude.
6.7 KiB
ProjectZomboid analyser design (Phase B.2)
Retroactive: written 2026-05-01.
Summary
Add Project Zomboid PvP combat detection (filtering zombie hits and zero-damage events) and admin verb-dispatch coverage of six action types, by registering seven new Information insight classes onto the existing PatternAnalyser. No custom Analyser subclasses are introduced in this phase — all dispatch fits within PatternAnalyser's per-entry pattern matching.
This document covers Phase B.2. Phase B.1 is in 2026-04-30-pz-analysers-design.md. Phase B.3 (cross-entry / threshold analysers requiring custom Analyser subclasses) is in 2026-04-30-pz-analysers-deferred-design.md.
Scope
- In scope:
PvpDamageInformation+PvpPattern::COMBAT_REALregex; sixAdmin<Verb>Informationclasses + sixAdminPattern::<VERB>_ENTRYregex constants; wiringProjectZomboidPvpLog::getDefaultAnalyser()andProjectZomboidAdminLog::getDefaultAnalyser(); end-to-end tests for both logs. - Out of scope (B.2): any cross-entry / threshold / pairing logic (deferred to B.3); the eight other PZ logs whose
getDefaultAnalyser()continues returning an emptyPatternAnalyserstub; the codex-sideRedactorutility (deferred — see2026-04-30-redactor-design.md).
Architectural decision: vanilla PatternAnalyser
Phase B.1 established that PatternAnalyser plus Insight::isEqual() coalescing covers single-entry pattern matching cleanly. Phase B.2's analysers (PvP damage rows, admin verb lines) all fit that mould — each interesting line is independent of the others, dispatch is per-entry, and counter-coalescing handles repeats. No Analyser subclassing required. (Phase B.3 will deviate from this when cross-entry logic enters the picture.)
Components
All under src/Analysis/ProjectZomboid/:
| Class | Type | Pattern | Coalescing |
|---|---|---|---|
PvpDamageInformation |
Information | PvpPattern::COMBAT_REAL |
Default Information::isEqual (label + value) — same attacker/victim/weapon coalesces |
AdminAddedItemInformation |
Information | AdminPattern::ADDED_ITEM_ENTRY |
Default — same admin/item/target coalesces |
AdminAddedXpInformation |
Information | AdminPattern::ADDED_XP_ENTRY |
Default — same admin/amount/skill/target coalesces |
AdminGrantedAccessInformation |
Information | AdminPattern::GRANTED_ACCESS_ENTRY |
Default — same admin/level/target coalesces |
AdminChangedOptionInformation |
Information | AdminPattern::CHANGED_OPTION_ENTRY |
Default — same admin/option/value coalesces |
AdminReloadedOptionsInformation |
Information | AdminPattern::RELOADED_OPTIONS_ENTRY |
Default — same admin coalesces |
AdminTeleportedInformation |
Information | AdminPattern::TELEPORTED_ENTRY |
Default — same admin/target/coords coalesces |
Patterns
Seven new constants total.
PvpPattern::COMBAT_REAL — combat regex with the noise filter baked in. The negative lookahead (?!zombie") rejects zombie weapon rows; the damage clause uses alternation to match only positive non-zero floats:
'/Combat: "(?<attacker>[^"]+)" \([^)]+\) hit "(?<victim>[^"]+)" \([^)]+\) weapon="(?<weapon>(?!zombie")[^"]+)" damage=(?<damage>0\.0*[1-9][0-9]*|[1-9][0-9]*\.[0-9]+)/'
The damage alternation explicitly rejects 0.000000 and any leading-minus value because both branches require either 0.<non-zero> or <non-zero>.<digits>.
AdminPattern::<VERB>_ENTRY — six entry-anchored variants of the existing body-only verb constants. Necessary because PatternAnalyser calls preg_match_all against the full Entry text (including the [time] prefix), so the Phase A verb constants anchored at ^<admin> would never match. The Phase A constants stay intact for direct-message use; new ones live alongside them on the same AdminPattern class.
Wiring
Two getDefaultAnalyser() overrides (was return new PatternAnalyser(); for both):
// ProjectZomboidPvpLog
return (new PatternAnalyser())
->addPossibleInsightClass(PvpDamageInformation::class);
// ProjectZomboidAdminLog
return (new PatternAnalyser())
->addPossibleInsightClass(AdminAddedItemInformation::class)
->addPossibleInsightClass(AdminAddedXpInformation::class)
->addPossibleInsightClass(AdminGrantedAccessInformation::class)
->addPossibleInsightClass(AdminChangedOptionInformation::class)
->addPossibleInsightClass(AdminReloadedOptionsInformation::class)
->addPossibleInsightClass(AdminTeleportedInformation::class);
Test plan
Unit tests under test/tests/Games/ProjectZomboid/Analysis/, one per Insight class — exercises getPatterns() shape, setMatches() extraction, and at least one filter-rejection case for PvpDamageInformation (zombie weapon and zero-damage rejection).
End-to-end tests under test/tests/Games/ProjectZomboid/Analyser/:
PvpLogAnalysisTestagainstpvp-minimal.txt: asserts exactly threePvpDamageInformationinsights (Bare Hands, Tire Iron (Worn), Hunting Knife). Zombie and vehicle rows must be filtered out by the regex.AdminLogAnalysisTestagainstadmin-minimal.txt: asserts 2 + 2 + 2 + 2 + 1 + 2 = 11 insights across the six admin classes, with the duplicate ShotgunShells row coalescing into a single insight atcounter == 2.
Fixture changes
None. The Phase A synthetic fixtures pvp-minimal.txt and admin-minimal.txt already cover every code path Phase B.2 exercises.
Commits (as-built, in order)
df62da1—pre-phase-B.2 checkpoint(--allow-empty)55f769c—Add PvpDamageInformation insight90c85a0—Add AdminAddedItemInformation insight⚠️ broken — see2026-04-30-pz-analysers-pvp-admin.md§Deviations0d85a05—Fix missing closing brace in AdminPattern(forward-fix for #3)a2faa55—Add AdminAddedXpInformation insightcaed04d—Add AdminGrantedAccessInformation insightb7b89ef—Add AdminChangedOptionInformation insight64641fa—Add AdminReloadedOptionsInformation insightd15fc81—Add AdminTeleportedInformation insight51eb2de—Wire ProjectZomboidPvpLog default analyserc57d646—Wire ProjectZomboidAdminLog default analyser
11 commits total, vs 10 originally planned. The brace-fix commit accounts for the discrepancy.
Open issues
None blocking. Phase A Q4 (admin verb scope) was settled before B.2 began. Phase B Q2 confirmed PvP fixtures contain real combat events worth analysing.
Pointers
- Phase B.1 (foundation):
2026-04-30-pz-analysers-design.mdand2026-04-30-pz-analysers.md. - Phase B.3 (deferred analysers requiring custom
Analysersubclasses):2026-04-30-pz-analysers-deferred-design.md. - Workflow conventions:
CLAUDE.md§ Workflow conventions and § Pitfalls.