From 00c17261a36a86f3e6f0b935b44dee51ef881f25 Mon Sep 17 00:00:00 2001 From: indifferentketchup Date: Thu, 30 Apr 2026 20:38:39 +0000 Subject: [PATCH] Add ProjectZomboidPerkLog (PerkLog.txt) Per-line skill snapshot log; each Login event is paired with a perks row containing comma-separated Skill=N tokens. PERK_PAIR regex extracts each pair via preg_match_all for analyser use. Detectors: filename match plus content signature on the unique '[Cooking=N, Fitness=N, Strength=N,' prefix of the perks-row bracket. --- .../ProjectZomboid/ProjectZomboidPerkLog.php | 44 ++++++++++++++ src/Pattern/ProjectZomboid/PerkPattern.php | 21 +++++++ .../ProjectZomboid/fixtures/perk-minimal.txt | 6 ++ .../Log/ProjectZomboidPerkLogTest.php | 59 +++++++++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 src/Log/ProjectZomboid/ProjectZomboidPerkLog.php create mode 100644 src/Pattern/ProjectZomboid/PerkPattern.php create mode 100644 test/src/Games/ProjectZomboid/fixtures/perk-minimal.txt create mode 100644 test/tests/Games/ProjectZomboid/Log/ProjectZomboidPerkLogTest.php diff --git a/src/Log/ProjectZomboid/ProjectZomboidPerkLog.php b/src/Log/ProjectZomboid/ProjectZomboidPerkLog.php new file mode 100644 index 0000000..54d19bd --- /dev/null +++ b/src/Log/ProjectZomboid/ProjectZomboidPerkLog.php @@ -0,0 +1,44 @@ +setPattern('/_PerkLog\.txt$/') + ->setWeight(0.95), + (new WeightedSinglePatternDetector()) + ->setPattern('/\[Cooking=\d+, Fitness=\d+, Strength=\d+,/') + ->setWeight(0.95), + ]; + } + + public function getTitle(): string + { + return "Project Zomboid Perk Log"; + } +} diff --git a/src/Pattern/ProjectZomboid/PerkPattern.php b/src/Pattern/ProjectZomboid/PerkPattern.php new file mode 100644 index 0000000..eeb8876 --- /dev/null +++ b/src/Pattern/ProjectZomboid/PerkPattern.php @@ -0,0 +1,21 @@ +\d{17})\]\[(?[^\]]+)\]\[(?\d+),(?\d+),(?\d+)\]\[(?[^\]]+)\]\[Hours Survived: (?\d+)\]\.$/'; + + public const string PERK_PAIR = '/(?[A-Za-z_]+)=(?\d+)/'; +} diff --git a/test/src/Games/ProjectZomboid/fixtures/perk-minimal.txt b/test/src/Games/ProjectZomboid/fixtures/perk-minimal.txt new file mode 100644 index 0000000..5b24042 --- /dev/null +++ b/test/src/Games/ProjectZomboid/fixtures/perk-minimal.txt @@ -0,0 +1,6 @@ +[16-04-26 18:29:08.171] [76561198000000001][Player1][1000,2000,1][Login][Hours Survived: 100]. +[16-04-26 18:29:08.171] [76561198000000001][Player1][1000,2000,1][Cooking=5, Fitness=6, Strength=7, Blunt=7, Axe=0, Lightfoot=0, Nimble=3, Sprinting=5, Sneak=3, Woodwork=10, Aiming=1, Reloading=1, Farming=1, Fishing=1, Trapping=0, PlantScavenging=1, Doctor=1, Electricity=5, Blacksmith=6, MetalWelding=3, Mechanics=6, Spear=0, Maintenance=7, SmallBlade=0, LongBlade=0, SmallBlunt=3, Tailoring=10, Tracking=0, Husbandry=10, FlintKnapping=0, Masonry=6, Pottery=4, Carving=10, Butchering=6, Glassmaking=2, Side_L=0, Side_R=0, ProstFamiliarity=0][Hours Survived: 100]. +[16-04-26 18:29:15.822] [76561198000000002][Player2][1010,2010,0][Login][Hours Survived: 50]. +[16-04-26 18:29:15.823] [76561198000000002][Player2][1010,2010,0][Cooking=2, Fitness=10, Strength=10, Blunt=10, Axe=0, Lightfoot=4, Nimble=4, Sprinting=7, Sneak=2, Woodwork=6, Aiming=5, Reloading=4, Farming=0, Fishing=0, Trapping=0, PlantScavenging=0, Doctor=2, Electricity=5, Blacksmith=8, MetalWelding=10, Mechanics=10, Spear=0, Maintenance=7, SmallBlade=0, LongBlade=0, SmallBlunt=0, Tailoring=0, Tracking=0, Husbandry=0, FlintKnapping=0, Masonry=0, Pottery=0, Carving=0, Butchering=0, Glassmaking=0, Side_L=0, Side_R=0, ProstFamiliarity=0][Hours Survived: 50]. +[16-04-26 18:30:02.500] [76561198000000003][AdminUser][1020,2020,0][Logout][Hours Survived: 75]. +[16-04-26 19:15:00.000] [76561198000000001][Player1][1003,2003,1][LevelUp][Hours Survived: 101]. diff --git a/test/tests/Games/ProjectZomboid/Log/ProjectZomboidPerkLogTest.php b/test/tests/Games/ProjectZomboid/Log/ProjectZomboidPerkLogTest.php new file mode 100644 index 0000000..4db676c --- /dev/null +++ b/test/tests/Games/ProjectZomboid/Log/ProjectZomboidPerkLogTest.php @@ -0,0 +1,59 @@ +setLogFile(new PathLogFile($this->fixturePath())); + $log->parse(); + + $this->assertCount(6, $log->getEntries()); + } + + public function testFieldsRegexHandlesEventRow(): void + { + $line = '[16-04-26 18:29:08.171] [76561198000000001][Player1][1000,2000,1][Login][Hours Survived: 100].'; + $this->assertSame(1, preg_match(PerkPattern::FIELDS, $line, $m)); + $this->assertSame('Player1', $m['player']); + $this->assertSame('Login', $m['event']); + $this->assertSame('100', $m['hours']); + } + + public function testFieldsRegexHandlesPerksRow(): void + { + $line = '[16-04-26 18:30:02.500] [76561198000000003][AdminUser][1020,2020,0][Logout][Hours Survived: 75].'; + $this->assertSame(1, preg_match(PerkPattern::FIELDS, $line, $m)); + $this->assertSame('Logout', $m['event']); + } + + public function testPerkPairRegexExtractsSkillsFromBracketedList(): void + { + $bracket = 'Cooking=5, Fitness=6, Strength=7'; + $count = preg_match_all(PerkPattern::PERK_PAIR, $bracket, $matches, PREG_SET_ORDER); + $this->assertSame(3, $count); + $this->assertSame('Cooking', $matches[0]['skill']); + $this->assertSame('5', $matches[0]['level']); + } + + public function testDetectiveDispatchesByContent(): void + { + $detective = (new Detective()) + ->setLogFile(new PathLogFile($this->fixturePath())) + ->addPossibleLogClass(ProjectZomboidPerkLog::class); + + $this->assertInstanceOf(ProjectZomboidPerkLog::class, $detective->detect()); + } +}