First custom Analyser subclass in this game tree. PatternAnalyser operates per-entry without cross-entry state, so pairing 'attempting to join' with 'allowed to join' per Steam ID requires a bespoke pass over the log. The analyser counts attempts and allowed events per Steam ID and emits a ConnectionFailureProblem for each player whose attempt count exceeds their allowed count. Unmatched 'attempting to join used queue' rows are surfaced as failures in v1 because a long queue wait is indistinguishable from a real failure without timing context.
65 lines
2.3 KiB
PHP
65 lines
2.3 KiB
PHP
<?php
|
|
|
|
namespace IndifferentKetchup\Codex\Analyser\ProjectZomboid;
|
|
|
|
use IndifferentKetchup\Codex\Analyser\Analyser;
|
|
use IndifferentKetchup\Codex\Analysis\Analysis;
|
|
use IndifferentKetchup\Codex\Analysis\AnalysisInterface;
|
|
use IndifferentKetchup\Codex\Analysis\ProjectZomboid\ConnectionFailureProblem;
|
|
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\UserPattern;
|
|
|
|
/**
|
|
* Pairs "attempting to join" with subsequent "allowed to join" events per
|
|
* Steam ID and flags any unmatched attempts. PatternAnalyser cannot express
|
|
* this because it operates per-entry without cross-entry state, so this
|
|
* walks the entire log once and aggregates before emitting Problems.
|
|
*
|
|
* "attempting to join used queue" is treated as an attempt; a player still
|
|
* waiting in queue at end-of-log will therefore be flagged. This is
|
|
* intentional v1 behaviour — a long-lived queue wait looks indistinguishable
|
|
* from a real failure without timing context, and surfacing both lets a
|
|
* human triage.
|
|
*/
|
|
class ConnectionFailureAnalyser extends Analyser
|
|
{
|
|
public function analyse(): AnalysisInterface
|
|
{
|
|
$analysis = new Analysis();
|
|
$analysis->setLog($this->log);
|
|
|
|
$attempts = [];
|
|
$allowed = [];
|
|
$playerName = [];
|
|
|
|
foreach ($this->log as $entry) {
|
|
$text = (string) $entry;
|
|
if (preg_match(UserPattern::PLAYER_EVENT, $text, $m) !== 1) {
|
|
continue;
|
|
}
|
|
$steamId = $m['steamid'];
|
|
$playerName[$steamId] = $m['player'];
|
|
|
|
if (str_starts_with($m['event'], 'attempting to join')) {
|
|
$attempts[$steamId] = ($attempts[$steamId] ?? 0) + 1;
|
|
} elseif (str_starts_with($m['event'], 'allowed to join')) {
|
|
$allowed[$steamId] = ($allowed[$steamId] ?? 0) + 1;
|
|
}
|
|
}
|
|
|
|
foreach ($attempts as $steamId => $attemptCount) {
|
|
$allowedCount = $allowed[$steamId] ?? 0;
|
|
$unmatched = $attemptCount - $allowedCount;
|
|
if ($unmatched <= 0) {
|
|
continue;
|
|
}
|
|
|
|
$analysis->addInsight((new ConnectionFailureProblem())
|
|
->setSteamId($steamId)
|
|
->setPlayer($playerName[$steamId] ?? '')
|
|
->setUnmatchedAttempts($unmatched));
|
|
}
|
|
|
|
return $analysis;
|
|
}
|
|
}
|