Compare commits

11 Commits

Author SHA1 Message Date
c57d646229 Wire ProjectZomboidAdminLog default analyser
Some checks failed
Tests / Run tests on PHP v8.4 (push) Failing after 1s
Tests / Run tests on PHP v8.5 (push) Failing after 1s
2026-04-30 21:48:31 +00:00
51eb2de282 Wire ProjectZomboidPvpLog default analyser 2026-04-30 21:47:51 +00:00
d15fc81f9f Add AdminTeleportedInformation insight 2026-04-30 21:47:14 +00:00
64641fa8e8 Add AdminReloadedOptionsInformation insight 2026-04-30 21:46:47 +00:00
b7b89ef24e Add AdminChangedOptionInformation insight 2026-04-30 21:46:13 +00:00
caed04db10 Add AdminGrantedAccessInformation insight 2026-04-30 21:45:34 +00:00
a2faa551a1 Add AdminAddedXpInformation insight 2026-04-30 21:45:12 +00:00
0d85a05df3 Fix missing closing brace in AdminPattern
The previous commit's Edit replaced the TELEPORTED constant including its
trailing closing brace and forgot to add the brace back. Tests went red
with a ParseError. Restoring the brace.
2026-04-30 21:44:34 +00:00
90c85a052f Add AdminAddedItemInformation insight 2026-04-30 21:44:08 +00:00
55f769ca1e Add PvpDamageInformation insight 2026-04-30 21:43:24 +00:00
df62da1d6e pre-phase-B.2 checkpoint 2026-04-30 21:42:51 +00:00
20 changed files with 589 additions and 2 deletions

View File

@@ -0,0 +1,26 @@
<?php
namespace IndifferentKetchup\Codex\Analysis\ProjectZomboid;
use IndifferentKetchup\Codex\Analysis\Information;
use IndifferentKetchup\Codex\Analysis\PatternInsightInterface;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
class AdminAddedItemInformation extends Information implements PatternInsightInterface
{
public static function getPatterns(): array
{
return [AdminPattern::ADDED_ITEM_ENTRY];
}
public function setMatches(array $matches, mixed $patternKey): void
{
$this->setLabel('Admin added item');
$this->setValue(sprintf(
'%s added %s to %s',
$matches['admin'],
$matches['item'],
$matches['target']
));
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace IndifferentKetchup\Codex\Analysis\ProjectZomboid;
use IndifferentKetchup\Codex\Analysis\Information;
use IndifferentKetchup\Codex\Analysis\PatternInsightInterface;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
class AdminAddedXpInformation extends Information implements PatternInsightInterface
{
public static function getPatterns(): array
{
return [AdminPattern::ADDED_XP_ENTRY];
}
public function setMatches(array $matches, mixed $patternKey): void
{
$this->setLabel('Admin added xp');
$this->setValue(sprintf(
'%s added %s %s xp to %s',
$matches['admin'],
$matches['amount'],
$matches['skill'],
$matches['target']
));
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace IndifferentKetchup\Codex\Analysis\ProjectZomboid;
use IndifferentKetchup\Codex\Analysis\Information;
use IndifferentKetchup\Codex\Analysis\PatternInsightInterface;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
class AdminChangedOptionInformation extends Information implements PatternInsightInterface
{
public static function getPatterns(): array
{
return [AdminPattern::CHANGED_OPTION_ENTRY];
}
public function setMatches(array $matches, mixed $patternKey): void
{
$this->setLabel('Admin changed option');
$this->setValue(sprintf(
'%s set %s=%s',
$matches['admin'],
$matches['option'],
$matches['value']
));
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace IndifferentKetchup\Codex\Analysis\ProjectZomboid;
use IndifferentKetchup\Codex\Analysis\Information;
use IndifferentKetchup\Codex\Analysis\PatternInsightInterface;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
class AdminGrantedAccessInformation extends Information implements PatternInsightInterface
{
public static function getPatterns(): array
{
return [AdminPattern::GRANTED_ACCESS_ENTRY];
}
public function setMatches(array $matches, mixed $patternKey): void
{
$this->setLabel('Admin granted access');
$this->setValue(sprintf(
'%s granted %s to %s',
$matches['admin'],
$matches['level'],
$matches['target']
));
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace IndifferentKetchup\Codex\Analysis\ProjectZomboid;
use IndifferentKetchup\Codex\Analysis\Information;
use IndifferentKetchup\Codex\Analysis\PatternInsightInterface;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
class AdminReloadedOptionsInformation extends Information implements PatternInsightInterface
{
public static function getPatterns(): array
{
return [AdminPattern::RELOADED_OPTIONS_ENTRY];
}
public function setMatches(array $matches, mixed $patternKey): void
{
$this->setLabel('Admin reloaded options');
$this->setValue($matches['admin']);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace IndifferentKetchup\Codex\Analysis\ProjectZomboid;
use IndifferentKetchup\Codex\Analysis\Information;
use IndifferentKetchup\Codex\Analysis\PatternInsightInterface;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
class AdminTeleportedInformation extends Information implements PatternInsightInterface
{
public static function getPatterns(): array
{
return [AdminPattern::TELEPORTED_ENTRY];
}
public function setMatches(array $matches, mixed $patternKey): void
{
$this->setLabel('Admin teleported');
$this->setValue(sprintf(
'%s teleported %s to %s,%s,%s',
$matches['admin'],
$matches['target'],
$matches['x'],
$matches['y'],
$matches['z']
));
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace IndifferentKetchup\Codex\Analysis\ProjectZomboid;
use IndifferentKetchup\Codex\Analysis\Information;
use IndifferentKetchup\Codex\Analysis\PatternInsightInterface;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\PvpPattern;
class PvpDamageInformation extends Information implements PatternInsightInterface
{
public static function getPatterns(): array
{
return [PvpPattern::COMBAT_REAL];
}
public function setMatches(array $matches, mixed $patternKey): void
{
$this->setLabel('PvP combat');
$this->setValue(sprintf(
'%s hit %s with %s',
$matches['attacker'],
$matches['victim'],
$matches['weapon']
));
}
}

View File

@@ -4,6 +4,12 @@ namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface; use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser; use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminAddedItemInformation;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminAddedXpInformation;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminChangedOptionInformation;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminGrantedAccessInformation;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminReloadedOptionsInformation;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminTeleportedInformation;
use IndifferentKetchup\Codex\Detective\FilenameDetector; use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector; use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface; use IndifferentKetchup\Codex\Parser\ParserInterface;
@@ -22,7 +28,13 @@ class ProjectZomboidAdminLog extends ProjectZomboidEventLog
public static function getDefaultAnalyser(): AnalyserInterface public static function getDefaultAnalyser(): AnalyserInterface
{ {
return new PatternAnalyser(); return (new PatternAnalyser())
->addPossibleInsightClass(AdminAddedItemInformation::class)
->addPossibleInsightClass(AdminAddedXpInformation::class)
->addPossibleInsightClass(AdminGrantedAccessInformation::class)
->addPossibleInsightClass(AdminChangedOptionInformation::class)
->addPossibleInsightClass(AdminReloadedOptionsInformation::class)
->addPossibleInsightClass(AdminTeleportedInformation::class);
} }
public static function getDetectors(): array public static function getDetectors(): array

View File

@@ -4,6 +4,7 @@ namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface; use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser; use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\PvpDamageInformation;
use IndifferentKetchup\Codex\Detective\FilenameDetector; use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector; use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface; use IndifferentKetchup\Codex\Parser\ParserInterface;
@@ -22,7 +23,8 @@ class ProjectZomboidPvpLog extends ProjectZomboidEventLog
public static function getDefaultAnalyser(): AnalyserInterface public static function getDefaultAnalyser(): AnalyserInterface
{ {
return new PatternAnalyser(); return (new PatternAnalyser())
->addPossibleInsightClass(PvpDamageInformation::class);
} }
public static function getDetectors(): array public static function getDetectors(): array

View File

@@ -25,4 +25,23 @@ class AdminPattern
public const string RELOADED_OPTIONS = '/^(?<admin>.+?) reloaded options$/'; public const string RELOADED_OPTIONS = '/^(?<admin>.+?) reloaded options$/';
public const string TELEPORTED = '/^(?<admin>.+?) teleported (?<target>.+?) to (?<x>\d+),(?<y>\d+),(?<z>-?\d+)$/'; public const string TELEPORTED = '/^(?<admin>.+?) teleported (?<target>.+?) to (?<x>\d+),(?<y>\d+),(?<z>-?\d+)$/';
/**
* Entry-anchored variants for analyser use. PatternAnalyser passes the
* full Entry text (including the [time] prefix) to preg_match_all, so
* these include the timestamp prefix and are anchored at start/end of
* the line. The body-only constants above are kept for direct-message
* matching.
*/
public const string ADDED_ITEM_ENTRY = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] (?<admin>.+?) added item (?<item>Base\.\S+) in (?<target>.+?)\'s inventory\.?$/';
public const string ADDED_XP_ENTRY = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] (?<admin>.+?) added (?<amount>[\d.]+) (?<skill>\S+) xp\'s to (?<target>.+?)\.?$/';
public const string GRANTED_ACCESS_ENTRY = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] (?<admin>.+?) granted (?<level>\w+) access level on (?<target>.+?)\.?$/';
public const string CHANGED_OPTION_ENTRY = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] (?<admin>.+?) changed option (?<option>\S+?)=(?<value>.+?)\.?$/';
public const string RELOADED_OPTIONS_ENTRY = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] (?<admin>.+?) reloaded options\.?$/';
public const string TELEPORTED_ENTRY = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] (?<admin>.+?) teleported (?<target>.+?) to (?<x>\d+),(?<y>\d+),(?<z>-?\d+)\.?$/';
} }

View File

@@ -24,4 +24,12 @@ class PvpPattern
public const string COMBAT = '/^Combat: "(?<attacker>[^"]+)" \((?<ax>\d+),(?<ay>\d+),(?<az>-?\d+)\) hit "(?<victim>[^"]+)" \((?<vx>\d+),(?<vy>\d+),(?<vz>-?\d+)\) weapon="(?<weapon>[^"]+)" damage=(?<damage>-?\d+\.\d+)\.$/'; public const string COMBAT = '/^Combat: "(?<attacker>[^"]+)" \((?<ax>\d+),(?<ay>\d+),(?<az>-?\d+)\) hit "(?<victim>[^"]+)" \((?<vx>\d+),(?<vy>\d+),(?<vz>-?\d+)\) weapon="(?<weapon>[^"]+)" damage=(?<damage>-?\d+\.\d+)\.$/';
public const string SAFETY = '/^Safety: "(?<player>[^"]+)" \((?<x>\d+),(?<y>\d+),(?<z>-?\d+)\) (?<verb>\w+) (?<state>true|false)\.$/'; public const string SAFETY = '/^Safety: "(?<player>[^"]+)" \((?<x>\d+),(?<y>\d+),(?<z>-?\d+)\) (?<verb>\w+) (?<state>true|false)\.$/';
/**
* Real-PvP combat: weapon!="zombie" AND damage>0. Filtering is in the
* regex itself so PatternAnalyser produces no insights for zombie/zero
* rows. Damage clause matches any positive non-zero float (rejects
* 0.000000 and any leading-minus value).
*/
public const string COMBAT_REAL = '/Combat: "(?<attacker>[^"]+)" \([^)]+\) hit "(?<victim>[^"]+)" \([^)]+\) weapon="(?<weapon>(?!zombie")[^"]+)" damage=(?<damage>0\.0*[1-9][0-9]*|[1-9][0-9]*\.[0-9]+)/';
} }

View File

@@ -0,0 +1,53 @@
<?php
namespace IndifferentKetchup\Codex\Test\Tests\Games\ProjectZomboid\Analyser;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminAddedItemInformation;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminAddedXpInformation;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminChangedOptionInformation;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminGrantedAccessInformation;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminReloadedOptionsInformation;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminTeleportedInformation;
use IndifferentKetchup\Codex\Log\File\PathLogFile;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidAdminLog;
use PHPUnit\Framework\TestCase;
class AdminLogAnalysisTest extends TestCase
{
private function fixturePath(): string
{
return __DIR__ . '/../../../../src/Games/ProjectZomboid/fixtures/admin-minimal.txt';
}
public function testAnalyseProducesExpectedInsightCounts(): void
{
$log = (new ProjectZomboidAdminLog())->setLogFile(new PathLogFile($this->fixturePath()));
$log->parse();
$analysis = $log->analyse();
$this->assertCount(2, $analysis->getFilteredInsights(AdminAddedItemInformation::class));
$this->assertCount(2, $analysis->getFilteredInsights(AdminAddedXpInformation::class));
$this->assertCount(2, $analysis->getFilteredInsights(AdminGrantedAccessInformation::class));
$this->assertCount(2, $analysis->getFilteredInsights(AdminChangedOptionInformation::class));
$this->assertCount(1, $analysis->getFilteredInsights(AdminReloadedOptionsInformation::class));
$this->assertCount(2, $analysis->getFilteredInsights(AdminTeleportedInformation::class));
}
public function testIdenticalAddedItemEventsAreCoalesced(): void
{
$log = (new ProjectZomboidAdminLog())->setLogFile(new PathLogFile($this->fixturePath()));
$log->parse();
$analysis = $log->analyse();
$shotgunInsight = null;
foreach ($analysis->getFilteredInsights(AdminAddedItemInformation::class) as $insight) {
if (str_contains($insight->getValue(), 'Base.ShotgunShells')) {
$shotgunInsight = $insight;
break;
}
}
$this->assertNotNull($shotgunInsight);
$this->assertSame(2, $shotgunInsight->getCounterValue());
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace IndifferentKetchup\Codex\Test\Tests\Games\ProjectZomboid\Analyser;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\PvpDamageInformation;
use IndifferentKetchup\Codex\Log\File\PathLogFile;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidPvpLog;
use PHPUnit\Framework\TestCase;
class PvpLogAnalysisTest extends TestCase
{
private function fixturePath(): string
{
return __DIR__ . '/../../../../src/Games/ProjectZomboid/fixtures/pvp-minimal.txt';
}
public function testAnalyseProducesOnlyRealPvpInsights(): void
{
$log = (new ProjectZomboidPvpLog())->setLogFile(new PathLogFile($this->fixturePath()));
$log->parse();
$analysis = $log->analyse();
$insights = $analysis->getFilteredInsights(PvpDamageInformation::class);
$values = array_map(fn($i) => $i->getValue(), $insights);
sort($values);
$this->assertSame(
[
'AdminUser hit Player1 with Hunting Knife',
'Player1 hit Player2 with Bare Hands',
'Player1 hit Player2 with Tire Iron (Worn)',
],
$values
);
}
public function testZombieAndZeroDamageAreFilteredOut(): void
{
$log = (new ProjectZomboidPvpLog())->setLogFile(new PathLogFile($this->fixturePath()));
$log->parse();
$analysis = $log->analyse();
$insights = $analysis->getFilteredInsights(PvpDamageInformation::class);
foreach ($insights as $insight) {
$this->assertStringNotContainsString('zombie', $insight->getValue());
$this->assertStringNotContainsString('vehicle', $insight->getValue());
}
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace IndifferentKetchup\Codex\Test\Tests\Games\ProjectZomboid\Analysis;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminAddedItemInformation;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
use PHPUnit\Framework\TestCase;
class AdminAddedItemInformationTest extends TestCase
{
public function testGetPatternsReturnsEntryRegex(): void
{
$this->assertSame([AdminPattern::ADDED_ITEM_ENTRY], AdminAddedItemInformation::getPatterns());
}
public function testEntryRegexMatchesFullLine(): void
{
$line = "[16-04-26 18:33:34.289] AdminUser added item Base.ShotgunShells in Player1's inventory.";
$this->assertSame(1, preg_match(AdminPattern::ADDED_ITEM_ENTRY, $line, $m));
$insight = new AdminAddedItemInformation();
$insight->setMatches($m, 0);
$this->assertSame('Admin added item', $insight->getLabel());
$this->assertSame('AdminUser added Base.ShotgunShells to Player1', $insight->getValue());
}
public function testIsEqualCoalescesIdenticalAddedItem(): void
{
$a = $this->insightFor('AdminUser', 'Base.X', 'Player1');
$b = $this->insightFor('AdminUser', 'Base.X', 'Player1');
$c = $this->insightFor('AdminUser', 'Base.Y', 'Player1');
$this->assertTrue($a->isEqual($b));
$this->assertFalse($a->isEqual($c));
}
private function insightFor(string $admin, string $item, string $target): AdminAddedItemInformation
{
$insight = new AdminAddedItemInformation();
$insight->setMatches([
'admin' => $admin,
'item' => $item,
'target' => $target,
], 0);
return $insight;
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace IndifferentKetchup\Codex\Test\Tests\Games\ProjectZomboid\Analysis;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminAddedXpInformation;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
use PHPUnit\Framework\TestCase;
class AdminAddedXpInformationTest extends TestCase
{
public function testGetPatternsReturnsEntryRegex(): void
{
$this->assertSame([AdminPattern::ADDED_XP_ENTRY], AdminAddedXpInformation::getPatterns());
}
public function testEntryRegexMatchesFullLine(): void
{
$line = "[16-04-26 18:34:00.500] AdminUser added 750.0 Blunt xp's to Player1.";
$this->assertSame(1, preg_match(AdminPattern::ADDED_XP_ENTRY, $line, $m));
$insight = new AdminAddedXpInformation();
$insight->setMatches($m, 0);
$this->assertSame('Admin added xp', $insight->getLabel());
$this->assertSame('AdminUser added 750.0 Blunt xp to Player1', $insight->getValue());
}
public function testEntryRegexDoesNotMatchAddedItemLine(): void
{
$line = "[16-04-26 18:33:34.289] AdminUser added item Base.ShotgunShells in Player1's inventory.";
$this->assertSame(0, preg_match(AdminPattern::ADDED_XP_ENTRY, $line));
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace IndifferentKetchup\Codex\Test\Tests\Games\ProjectZomboid\Analysis;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminChangedOptionInformation;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
use PHPUnit\Framework\TestCase;
class AdminChangedOptionInformationTest extends TestCase
{
public function testGetPatternsReturnsEntryRegex(): void
{
$this->assertSame([AdminPattern::CHANGED_OPTION_ENTRY], AdminChangedOptionInformation::getPatterns());
}
public function testEntryRegexMatchesFullLine(): void
{
$line = "[16-04-26 18:36:15.500] AdminUser changed option AnnounceDeath=true.";
$this->assertSame(1, preg_match(AdminPattern::CHANGED_OPTION_ENTRY, $line, $m));
$insight = new AdminChangedOptionInformation();
$insight->setMatches($m, 0);
$this->assertSame('Admin changed option', $insight->getLabel());
$this->assertSame('AdminUser set AnnounceDeath=true', $insight->getValue());
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace IndifferentKetchup\Codex\Test\Tests\Games\ProjectZomboid\Analysis;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminGrantedAccessInformation;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
use PHPUnit\Framework\TestCase;
class AdminGrantedAccessInformationTest extends TestCase
{
public function testGetPatternsReturnsEntryRegex(): void
{
$this->assertSame([AdminPattern::GRANTED_ACCESS_ENTRY], AdminGrantedAccessInformation::getPatterns());
}
public function testEntryRegexMatchesFullLine(): void
{
$line = "[16-04-26 18:35:10.000] AdminUser granted admin access level on Player1.";
$this->assertSame(1, preg_match(AdminPattern::GRANTED_ACCESS_ENTRY, $line, $m));
$insight = new AdminGrantedAccessInformation();
$insight->setMatches($m, 0);
$this->assertSame('Admin granted access', $insight->getLabel());
$this->assertSame('AdminUser granted admin to Player1', $insight->getValue());
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace IndifferentKetchup\Codex\Test\Tests\Games\ProjectZomboid\Analysis;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminReloadedOptionsInformation;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
use PHPUnit\Framework\TestCase;
class AdminReloadedOptionsInformationTest extends TestCase
{
public function testGetPatternsReturnsEntryRegex(): void
{
$this->assertSame([AdminPattern::RELOADED_OPTIONS_ENTRY], AdminReloadedOptionsInformation::getPatterns());
}
public function testEntryRegexMatchesFullLine(): void
{
$line = "[16-04-26 18:37:00.014] AdminUser reloaded options.";
$this->assertSame(1, preg_match(AdminPattern::RELOADED_OPTIONS_ENTRY, $line, $m));
$insight = new AdminReloadedOptionsInformation();
$insight->setMatches($m, 0);
$this->assertSame('Admin reloaded options', $insight->getLabel());
$this->assertSame('AdminUser', $insight->getValue());
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace IndifferentKetchup\Codex\Test\Tests\Games\ProjectZomboid\Analysis;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\AdminTeleportedInformation;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
use PHPUnit\Framework\TestCase;
class AdminTeleportedInformationTest extends TestCase
{
public function testGetPatternsReturnsEntryRegex(): void
{
$this->assertSame([AdminPattern::TELEPORTED_ENTRY], AdminTeleportedInformation::getPatterns());
}
public function testEntryRegexMatchesPositiveZ(): void
{
$line = "[16-04-26 18:38:00.225] AdminUser teleported Player1 to 1100,2200,0.";
$this->assertSame(1, preg_match(AdminPattern::TELEPORTED_ENTRY, $line, $m));
$insight = new AdminTeleportedInformation();
$insight->setMatches($m, 0);
$this->assertSame('Admin teleported', $insight->getLabel());
$this->assertSame('AdminUser teleported Player1 to 1100,2200,0', $insight->getValue());
}
public function testEntryRegexHandlesNegativeZ(): void
{
$line = "[16-04-26 18:39:15.500] AdminUser teleported Player2 to 1100,2200,-1.";
$this->assertSame(1, preg_match(AdminPattern::TELEPORTED_ENTRY, $line, $m));
$this->assertSame('-1', $m['z']);
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace IndifferentKetchup\Codex\Test\Tests\Games\ProjectZomboid\Analysis;
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\PvpDamageInformation;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\PvpPattern;
use PHPUnit\Framework\TestCase;
class PvpDamageInformationTest extends TestCase
{
public function testGetPatternsReturnsCombatRealRegex(): void
{
$this->assertSame([PvpPattern::COMBAT_REAL], PvpDamageInformation::getPatterns());
}
public function testCombatRealMatchesPositiveDamageRealWeapon(): void
{
$line = 'Combat: "Player1" (1005,2005,0) hit "Player2" (1006,2005,0) weapon="Tire Iron (Worn)" damage=0.112317.';
$this->assertSame(1, preg_match(PvpPattern::COMBAT_REAL, $line, $m));
$insight = new PvpDamageInformation();
$insight->setMatches($m, 0);
$this->assertSame('PvP combat', $insight->getLabel());
$this->assertSame('Player1 hit Player2 with Tire Iron (Worn)', $insight->getValue());
}
public function testCombatRealRejectsZombieWeapon(): void
{
$line = 'Combat: "Player1" (1005,2005,0) hit "Player1" (1005,2005,0) weapon="zombie" damage=-1.000000.';
$this->assertSame(0, preg_match(PvpPattern::COMBAT_REAL, $line));
}
public function testCombatRealRejectsZeroDamage(): void
{
$line = 'Combat: "Player1" (1100,2200,0) hit "Player2" (1100,2201,0) weapon="vehicle" damage=0.000000.';
$this->assertSame(0, preg_match(PvpPattern::COMBAT_REAL, $line));
}
public function testCombatRealRejectsNegativeDamage(): void
{
$line = 'Combat: "Player1" (1005,2005,0) hit "Player2" (1005,2005,0) weapon="Bare Hands" damage=-0.500000.';
$this->assertSame(0, preg_match(PvpPattern::COMBAT_REAL, $line));
}
public function testIsEqualCoalescesSameAttackerVictimWeapon(): void
{
$a = $this->insightFor('Player1', 'Player2', 'Bare Hands');
$b = $this->insightFor('Player1', 'Player2', 'Bare Hands');
$c = $this->insightFor('Player1', 'Player2', 'Tire Iron');
$this->assertTrue($a->isEqual($b));
$this->assertFalse($a->isEqual($c));
}
private function insightFor(string $attacker, string $victim, string $weapon): PvpDamageInformation
{
$insight = new PvpDamageInformation();
$insight->setMatches([
'attacker' => $attacker,
'victim' => $victim,
'weapon' => $weapon,
], 0);
return $insight;
}
}