Compare commits

26 Commits

Author SHA1 Message Date
3640ca8291 Add CLAUDE.md project guidance and ignore Claude local artefacts
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
Captures the framework architecture, the docker-based PHP/Composer
runtime, the components-outer game subtree convention, the
PatternParser-and-named-groups gotcha, the workflow conventions that
emerged during the rename and ProjectZomboid build-out, and the
synthetic-only fixture rule for committed test data. Adds .claude/ and
.claude.local.md to .gitignore so Claude session state and personal
overrides don't ride along.
2026-04-30 21:01:10 +00:00
cca5208cc0 Wire ProjectZomboidDetective with all 11 log classes
Constructor pre-registers every concrete ProjectZomboid Log subclass so
that detect() can dispatch on filename hint plus content signature.
Data-provider test verifies each of the eleven synthetic fixtures
resolves to its expected Log class via the public Detective surface.
2026-04-30 20:43:51 +00:00
27424f6a14 Add ProjectZomboidBurdJournalsLog (BurdJournals.txt)
Per-line warnings emitted by the BurdJournals mod, format
'[time] [BurdJournals] LEVEL: message.'. Parser captures time, the
[BurdJournals] tag as the entry prefix, and the LEVEL token. Detectors:
filename match plus content signature on the literal '[BurdJournals]'
tag bracket.
2026-04-30 20:42:52 +00:00
d7c36ffc07 Add ProjectZomboidUserLog (user.txt)
Two row variants: low-level Connection events and player join/disconnect
events. The LINE regex accepts both shapes; analysers route via
CONNECTION (action/index/guid/id) and PLAYER_EVENT (steamid/player/event)
named-group regexes. Detectors: filename match plus content signatures
on either variant.
2026-04-30 20:42:19 +00:00
7b3342b3d2 Add ProjectZomboidAdminLog (admin.txt)
Free-form English message body with verb-dispatched analyser regexes
(ADDED_ITEM, ADDED_XP, GRANTED_ACCESS, CHANGED_OPTION,
RELOADED_OPTIONS, TELEPORTED). Parser captures only the timestamp,
since the admin name itself can include parentheses or whitespace.
Detectors: filename match plus content signatures on
'added item Base.X in Y's inventory' and 'granted ROLE access level on'.
2026-04-30 20:41:31 +00:00
af05c97dfc Add ProjectZomboidPvpLog (pvp.txt)
Two row variants share the file: Safe House toggles ([LOG] Safety:)
and Combat events ([INFO] Combat: ... weapon=... damage=...). Parser
captures time, level, and the subsystem token (Safety|Combat) as the
entry prefix. COMBAT and SAFETY regexes extract structured fields,
including support for negative Z coordinates from basement levels.
Synthetic fixture covers both variants and represents zombie/vehicle/
real-PvP weapon types so analysers can later filter on damage>0 and
weapon!=zombie.
2026-04-30 20:40:03 +00:00
00c17261a3 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.
2026-04-30 20:38:39 +00:00
6387fb1c52 Add ProjectZomboidMapLog (map.txt)
Per-line world object placement/removal log. LINE pattern handles both
integer and floating-point coordinates and both 'Base.X' and
'IsoObject (X)' object encodings. Detectors: filename match plus content
signature on the added/removed verbs paired with Base./IsoObject prefix.
2026-04-30 20:37:50 +00:00
49cf4927f6 Add ProjectZomboidItemLog (item.txt)
Per-line item gain/loss event log. Parser captures only the timestamp;
analysers decompose location/delta/item via ItemPattern::FIELDS.
Detectors: filename match plus content signature on the
container/floor/inventory location verbs paired with a signed delta.
2026-04-30 20:37:06 +00:00
cc9c512667 Add ProjectZomboidCmdLog (cmd.txt)
Per-line client RPC trace. Parser captures only the timestamp;
analysers decompose steamid/player/command/coords via CmdPattern::FIELDS.
Detectors: filename match plus content signature on the
'steamid "name" command @ x,y,z' line shape.
2026-04-30 20:36:26 +00:00
e74c105625 Add ProjectZomboidClientActionLog (ClientActionLog.txt)
Strict 5-field bracketed format. Parser captures only the timestamp;
analysers that want steamid/action/player/coords/param decompose the
Line text via ClientActionPattern::FIELDS. Detectors: filename match
plus content signature on the IS{Enter,Exit}Vehicle / ISWalkToTimedAction
action tokens.
2026-04-30 20:35:40 +00:00
28e8fc8dc6 Add ProjectZomboidChatLog (chat.txt)
Handles both chat-engine events (bracketed level prefix) and bare
server-alert lines via an optional level group. Detectors: filename
match on _chat.txt plus content signatures for ChatMessage{...} log
entries and the chat-server initialization banner. CHAT_MESSAGE and
SERVER_ALERT named-group regexes ride along on ChatPattern for analyser
extraction in phase B.
2026-04-30 20:34:50 +00:00
d863fae9e6 Add ProjectZomboidServerLog (DebugLog-server.txt)
Concrete Log subclass for the engine debug log. Captures time, level,
and subsystem prefix per entry; stack-trace continuation lines attach
to the triggering ERROR entry via PatternParser's append-on-no-match
behaviour. Detectors: filename match on DebugLog-server.txt plus two
content signatures (the version=X.Y.Z+hash banner and the level/
subsystem/f/t/st header shape). Pattern constants live in
src/Pattern/ProjectZomboid/DebugServerPattern.php with named groups
ready for analyser use in phase B. Synthetic fixture under
test/src/Games/ProjectZomboid/fixtures/ uses zeroed identifiers and
placeholder paths.
2026-04-30 20:34:03 +00:00
c032fd34b8 Add ProjectZomboid log base classes
ProjectZomboidLog (abstract): extends AnalysableLog, implements
DetectableLogInterface. Centralises the PZ timestamp format
('d-m-y H:i:s.v') and UTC default timezone, plus a makePatternParser()
helper so concrete subclasses only specify their line regex and capture
group names. ProjectZomboidEventLog (abstract): marker base for the ten
single-line structured PZ logs, distinct from the multi-line
ProjectZomboidServerLog. Concrete subclasses follow.
2026-04-30 20:31:12 +00:00
ada3c7875d Add FilenameDetector for path-based log type dispatch
New Detector that matches a configured regex against
LogFileInterface::getPath(). Returns a settable weight on match (default
0.95) and false otherwise, including when the log file has no known path
(StringLogFile, StreamLogFile). Lets game-specific Detectives prefer the
filename hint over content signatures when an upload's original name is
preserved.
2026-04-30 20:29:56 +00:00
8ae7da5259 Expose source path on LogFileInterface
Add LogFileInterface::getPath(): ?string so detectors can dispatch on a
filename hint when the original path is known. Default implementation on
the abstract LogFile base returns null; PathLogFile records its
constructor argument. StringLogFile and StreamLogFile inherit the null
default. Tests cover both the path and null-fallback cases.
2026-04-30 20:29:21 +00:00
e709389e08 Ignore log fixture working area 2026-04-30 19:22:22 +00:00
49249176fc Scaffold SevenDaysToDie game stubs
Add empty per-component subdirectories under src/{Analyser,Log,Parser,Pattern}/SevenDaysToDie/
with .gitkeep markers, plus SevenDaysToDieDetective stub extending the base Detective with
a TODO body. Smoke test under test/tests/Games/SevenDaysToDie/ asserts the detective is
instantiable. Directory name is alphabetic because PHP class names cannot begin with a digit.
2026-04-30 15:31:33 +00:00
484d3b88a3 Scaffold Hytale game stubs
Add empty per-component subdirectories under src/{Analyser,Log,Parser,Pattern}/Hytale/
with .gitkeep markers, plus HytaleDetective stub extending the base Detective with
a TODO body. Smoke test under test/tests/Games/Hytale/ asserts the detective is
instantiable.
2026-04-30 15:31:11 +00:00
e1df5cbfd8 Scaffold ProjectZomboid game stubs
Add empty per-component subdirectories under src/{Analyser,Log,Parser,Pattern}/ProjectZomboid/
with .gitkeep markers, plus ProjectZomboidDetective stub extending the base Detective with
a TODO body. Smoke test under test/tests/Games/ProjectZomboid/ asserts the detective is
instantiable.
2026-04-30 15:30:51 +00:00
c9956be7a2 Scaffold Minecraft game stubs
Add empty per-component subdirectories under src/{Analyser,Log,Parser,Pattern}/Minecraft/
with .gitkeep markers, plus MinecraftDetective stub extending the base Detective with
a TODO body. Smoke test under test/tests/Games/Minecraft/ asserts the detective is
instantiable. Introduces src/Pattern/ as a new top-level component directory.
2026-04-30 15:30:28 +00:00
30750ae9d1 pre-scaffold checkpoint 2026-04-30 15:30:04 +00:00
9e124f716b Rewrite README for IndifferentKetchup fork
Minimal replacement: title, one-paragraph generic description,
Composer install line, Gitea source link. Strips all Aternos and
codex-minecraft references and the Minecraft-server-logs framing.
2026-04-30 15:16:22 +00:00
aae016d17e Rewrite composer.json metadata for IndifferentKetchup fork
Rename package indifferentketchup/codex, replace authors entry with
samkintop@gmail.com, switch PSR-4 autoload roots to
IndifferentKetchup\Codex\, rewrite description as a generic log
parsing/analysis framework. License remains MIT. composer.lock left
intact; vendor/ regenerated locally via composer install (gitignored).
2026-04-30 15:16:01 +00:00
66a2fcc5f3 Rename namespace Aternos\Codex to IndifferentKetchup\Codex
Bulk substitution across all PHP files in src/ and test/. Covers
namespace declarations, use statements, fully-qualified class
references, and @package PHPDoc tags. No logic changes.
2026-04-30 15:13:52 +00:00
6870ed6ea7 pre-rename checkpoint 2026-04-30 15:12:33 +00:00
160 changed files with 2246 additions and 409 deletions

4
.gitignore vendored
View File

@@ -1,3 +1,7 @@
.idea
vendor
.phpunit.result.cache
Logs.zip
.scratch/
.claude/
.claude.local.md

94
CLAUDE.md Normal file
View File

@@ -0,0 +1,94 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What this is
`indifferentketchup/codex` — a generic PHP log parsing and analysis framework, plus per-game subclasses that adapt the framework to specific games' log formats. PHP `>=8.4`, MIT license. Forked from `aternos/codex`; namespace was renamed in-tree (`Aternos\Codex``IndifferentKetchup\Codex`) — only the LICENSE retains the original Aternos GmbH copyright line, which must remain byte-for-byte (MIT requires it).
## Local environment
PHP and Composer are **not** installed on the host. All Composer/PHPUnit invocations go through the official `composer:latest` Docker image (currently PHP 8.5, satisfies the `>=8.4` floor):
```
docker run --rm -v "$(pwd):/app" -w /app -u "$(id -u):$(id -g)" composer:latest <subcommand>
```
Use `$(pwd)` or an absolute path — bare `$PWD` has misfired here, mounting nothing and silently no-op'ing the run.
## Common commands
- All tests: `composer test` (= `phpunit test/tests` per `composer.json`)
- One test file or method (wrap in the same docker invocation):
`docker run --rm -v "$(pwd):/app" -w /app -u "$(id -u):$(id -g)" composer:latest vendor/bin/phpunit --filter=testFooBar test/tests/path/to/SomeTest.php`
- Refresh autoloader after editing `composer.json`: `composer dump-autoload`
- After cloning: `composer install` (writes `vendor/`, gitignored)
## Framework architecture
```
LogFile (Path|String|Stream)
Log ── extends AnalysableLog ── implements DetectableLogInterface
│ │ │
│ │ └─ static getDetectors(): Detector[]
│ └─ static getDefaultAnalyser(): Analyser
├─ static getDefaultParser(): Parser
▼ Log->parse()
Entry[] of Line[] (each Entry has level, time, prefix, lines)
▼ Log->analyse()
Analysis of Insight[]
└── Information (label + value) or
Problem (with attached Solution[])
```
- **`Detective`** ranks candidate Log subclasses by running each candidate's `getDetectors()` and picking the highest-scoring result (`bool|float`). It receives a `LogFile`, returns a constructed `Log` subclass.
- **`PatternParser`** is regex-driven. Lines that don't match the LINE regex append to the previous `Entry` — this is the mechanism that handles multi-line records like Java stack traces under an ERROR header.
- **`PatternAnalyser`** walks entries, runs each registered insight class's static `getPatterns()` against entry text via `preg_match_all`, and emits coalesced insights (equal insights bump a counter instead of duplicating).
- Detectors available out of the box: `SinglePatternDetector`, `WeightedSinglePatternDetector`, `LinePatternDetector` (returns match ratio), `MultiPatternDetector` (AND), and the path-based `FilenameDetector` (uses `LogFileInterface::getPath()`, returns `false` when no path is available).
## Game subtrees
Layout is **components-outer with game suffix**, not games-outer:
```
src/<Component>/<Game>/... e.g. src/Log/ProjectZomboid/ProjectZomboidServerLog.php
src/Pattern/<Game>/<Type>Pattern.php (regex string constants; not a framework abstraction)
test/tests/Games/<Game>/...
test/src/Games/<Game>/fixtures/<type>-minimal.txt (synthetic fixtures only)
```
Scaffolded games: `Minecraft`, `Hytale`, `SevenDaysToDie` (stubs only — empty `.gitkeep`s plus a TODO `<Game>Detective` extending base `Detective`). `ProjectZomboid` is fully implemented (11 log subclasses, 11 pattern classes, detective wired with all 11, synthetic fixtures, dispatch tests).
`src/Pattern/` is **not a framework abstraction** — patterns are plain `string` class constants. Each `<Type>Pattern` typically holds a `LINE` constant for the parser plus named-group extractor constants (`FIELDS`, `COMBAT`, `MOD_LOAD`, etc.) for analysers.
### ProjectZomboid specifics
- Two abstract bases: `ProjectZomboidLog` (`TIME_FORMAT = 'd-m-y H:i:s.v'`, UTC default, `makePatternParser()` helper) and `ProjectZomboidEventLog` (marker for the ten single-line logs; `ProjectZomboidServerLog` extends the parent directly because it permits multi-line entries).
- `ProjectZomboidDetective::__construct()` pre-registers all 11 log classes — instantiate it and call `setLogFile(...)->detect()`.
### Standard test template for a Log subclass
At minimum: (1) entry count after `parse()` matches the synthetic fixture's line count, (2) one or more named-group `FIELDS` regexes from the `<Type>Pattern` class extract correctly from a representative line, (3) `Detective` handed the fixture path returns an instance of this Log class. Use `#[DataProvider]` when the same shape repeats per file.
## Pitfalls
1. **`PatternParser` is incompatible with named regex groups.** PHP's `preg_match` returns named groups *plus* their numeric duplicates in the same array; `PatternParser`'s foreach iterates both and throws on the string-key entries. Convention: `LINE` regexes (used by the parser) use **unnamed** groups with field order documented in the Pattern class's docblock. Named groups are fine inside extractor regexes invoked from analysers, since `PatternAnalyser` hands the whole match array to `Insight::setMatches`.
2. **PHPUnit 12 requires the `#[DataProvider('methodName')]` attribute.** The legacy `@dataProvider` annotation silently passes zero args and fails with `ArgumentCountError`.
3. **`Level::fromString()` defaults to `Level::INFO` for unknown tokens.** Project Zomboid log levels map: `LOG`/`INFO` → INFO; `WARN` → WARNING; `ERROR` → ERROR.
4. **`PatternParser` matches array** must declare a match-type for **every** capture group in the regex (`TIME`, `LEVEL`, or `PREFIX`); otherwise the parser throws on the unmapped index. Use non-capturing groups `(?:...)` for fields you want to skip.
## Workflow conventions
- **One commit per concrete log type** when adding game support: pattern class + log subclass + synthetic fixture + test in a single commit, run `composer test`, then move on. `<Game>Detective::__construct()` wiring goes in its own follow-up commit once all log types are present.
- **Out-of-scope cleanup goes in its own commit.** Tempting workflow/lint fixes (e.g. deprecated CI syntax, comment hygiene) noticed mid-feature should not be folded in — separate commit or follow-up PR.
- **Pre-destructive checkpoint pattern.** Before bulk renames/moves: `git commit --allow-empty -m "pre-X checkpoint"` as a revert anchor. Skip the empty slot if it produces no diff at the end of a plan.
## Privacy / fixture rules
- `Logs.zip` at the repo root contains real production server data (Steam IDs, player names, world coordinates). It is gitignored.
- Extract for reference: `unzip -q Logs.zip -d .scratch/pz/`. Real logs then live under `.scratch/pz/Logs/` (gitignored). Use only as format reference. Do not paste raw Steam IDs, player names, or coordinates into chat output, commit messages, or any committed file.
- All fixtures committed under `test/src/Games/<Game>/fixtures/` must be **synthetic**, hand-crafted from the observed format with placeholder identifiers: `76561198000000001/2/3` for Steam IDs, `Player1`/`Player2`/`AdminUser` for names, generic coords (`1000-1100, 2000-2200, 0`).

114
README.md
View File

@@ -1,115 +1,13 @@
# Codex
# IndifferentKetchup Codex
### About
A generic PHP log parsing and analysis framework. Provides interfaces and base implementations for reading log files, detecting log types, parsing entries into structured form, analysing them for problems and information, and printing results.
Codex (*lat. roughly for "log"*) is a PHP library to read, parse, print and analyse log files to find problems and suggest possible
solutions. It was created mainly for Minecraft server logs but could be used for any other logs as well. This library provides a set
up for a structured log parsing implementation and provides some useful basic implementation, mainly based on RegEx. Every part
of this library can or even must be extended/overwritten while still following the interfaces, which ensure interoperability between
the different parts of this library.
### Installation
## Installation
```
composer require aternos/codex
composer require indifferentketchup/codex
```
## Usage
## Source
This is a short introduction to the idea of Codex, for some more examples check the [test](test) folder
and/or read the [code](src).
### Logfile
A [`LogFile`](src/Log/File/LogFile.php) object implementing the [`LogFileInterface`](src/Log/File/LogFileInterface.php) object is required
to start reading a log. There are currently three different log file classes in this library.
```php
<?php
$logFile = new \Aternos\Codex\Log\File\StringLogFile("This is the log content");
$logFile = new \Aternos\Codex\Log\File\PathLogFile("/path/to/log");
$logFile = new \Aternos\Codex\Log\File\StreamLogFile(fopen("/path/to/log", "r"));
```
### Log
A [`Log`](src/Log/Log.php) object implementing the [`LogInterface`](src/Log/LogInterface.php) is the most important object
for the different operations. It represents the log content, which is split in [Entries](src/Log/EntryInterface.php) and [Lines](src/Log/LineInterface.php).
And it offers quick access to the detection, parsing and analysing functions and can define which classes are used
for those functions. If you know which log type you have or just want to test the default [Log](src/Log/Log.php) class, you can
directly create a new instance, otherwise you can use detection as described below.
```php
<?php
$log = new \Aternos\Codex\Log\Log();
$log->setLogFile($logFile);
```
### Detection
If the log type (specifically the class name of the log type) is unknown you can use the [`Detective`](src/Detective/Detective.php) class
to automatically detect the log type. The `Detective` class gets a list of possible log class names and executes
their given [Detectors](src/Detective/DetectorInterface.php).
```php
<?php
$detective = new \Aternos\Codex\Detective\Detective();
$detective->addPossibleLogClass(\Aternos\Codex\Log\Log::class);
$log = $detective->detect();
```
The `detect()` function always returns a log object, if necessary it defaults to [`Log`](src/Log/Log.php).
### Parsing
Parsing reads the entire log and creates the [`Entry`](src/Log/EntryInterface.php) and [`Line`](src/Log/LineInterface.php) objects which
are parts of a [`Log`](src/Log/LogInterface.php) object. Different log types can use different parsers by overwriting the
`LogInterface::getDefaultParser()` function or by passing a parser object to the parse function.
```php
<?php
$log->parse();
```
### Analysing
An analysis is performed by an [`Analyser`](src/Analyser/AnalyserInterface.php) on an [`AnalysableLog`](src/Log/AnalysableLogInterface.php) and returns
an [`Analysis`](src/Analysis/AnalysisInterface.php) object containing various [`Insight`](src/Analysis/InsightInterface.php) objects, e.g. a [`Problem`](src/Analysis/ProblemInterface.php)
or an [`Information`](src/Analysis/InformationInterface.php) object. Different log types can use different analysers by overwriting
the `AnalysableLogInterface::getDefaultAnalyser()` function or by passing an analyser object to the analyse function.
```php
<?php
$analysis = $log->analyse();
```
### Printing
The entire [`Log`](src/Log/LogInterface.php) or just an [`Entry`](src/Log/EntryInterface.php) can be printed through a [`Printer`](src/Printer/PrinterInterface.php). The basic
[`DefaultPrinter`](src/Printer/DefaultPrinter.php) only prints the plain content line by line. The [`ModifiableDefaultPrinter`](src/Printer/ModifiableDefaultPrinter.php)
allows [`Modification`](src/Printer/ModificationInterface.php), e.g. to highlight certain characters/words.
```php
<?php
$printer = new \Aternos\Codex\Printer\DefaultPrinter();
$printer->setLog($log);
$printer->print();
$printer = new \Aternos\Codex\Printer\DefaultPrinter();
$printer->setEntry($entry);
$printer->print();
$printer = new \Aternos\Codex\Printer\ModifiableDefaultPrinter();
$printer->setLog($log);
$modification = new \Aternos\Codex\Printer\PatternModification();
$modification->setPattern('/foo/');
$modification->setReplacement('bar');
$printer->addModification($modification);
$printer->print();
```
<https://git.indifferentketchup.com/indifferentketchup/ik-codex>

View File

@@ -1,12 +1,12 @@
{
"name": "aternos/codex",
"description": "PHP library to read, parse, print and analyse log files.",
"name": "indifferentketchup/codex",
"description": "Generic PHP log parsing and analysis framework.",
"license": "MIT",
"type": "library",
"authors": [
{
"name": "Matthias Neid",
"email": "matthias@aternos.org"
"name": "indifferentketchup",
"email": "samkintop@gmail.com"
}
],
"require": {
@@ -17,13 +17,13 @@
},
"autoload": {
"psr-4": {
"Aternos\\Codex\\": "src/"
"IndifferentKetchup\\Codex\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Aternos\\Codex\\Test\\Src\\": "test/src/",
"Aternos\\Codex\\Test\\Tests\\": "test/tests/"
"IndifferentKetchup\\Codex\\Test\\Src\\": "test/src/",
"IndifferentKetchup\\Codex\\Test\\Tests\\": "test/tests/"
}
},
"scripts": {

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Analyser;
namespace IndifferentKetchup\Codex\Analyser;
use Aternos\Codex\Log\AnalysableLogInterface;
use IndifferentKetchup\Codex\Log\AnalysableLogInterface;
/**
* Class Analyser
*
* @package Aternos\Codex\Analyser
* @package IndifferentKetchup\Codex\Analyser
*/
abstract class Analyser implements AnalyserInterface
{

View File

@@ -1,14 +1,14 @@
<?php
namespace Aternos\Codex\Analyser;
namespace IndifferentKetchup\Codex\Analyser;
use Aternos\Codex\Analysis\AnalysisInterface;
use Aternos\Codex\Log\AnalysableLogInterface;
use IndifferentKetchup\Codex\Analysis\AnalysisInterface;
use IndifferentKetchup\Codex\Log\AnalysableLogInterface;
/**
* Interface AnalyserInterface
*
* @package Aternos\Codex\Analyser
* @package IndifferentKetchup\Codex\Analyser
*/
interface AnalyserInterface
{

View File

View File

View File

@@ -1,17 +1,17 @@
<?php
namespace Aternos\Codex\Analyser;
namespace IndifferentKetchup\Codex\Analyser;
use Aternos\Codex\Analysis\Analysis;
use Aternos\Codex\Analysis\AnalysisInterface;
use Aternos\Codex\Analysis\PatternInsightInterface;
use Aternos\Codex\Log\EntryInterface;
use IndifferentKetchup\Codex\Analysis\Analysis;
use IndifferentKetchup\Codex\Analysis\AnalysisInterface;
use IndifferentKetchup\Codex\Analysis\PatternInsightInterface;
use IndifferentKetchup\Codex\Log\EntryInterface;
use InvalidArgumentException;
/**
* Class PatternAnalyser
*
* @package Aternos\Codex\Analyser
* @package IndifferentKetchup\Codex\Analyser
*/
class PatternAnalyser extends Analyser
{

View File

View File

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Analysis;
namespace IndifferentKetchup\Codex\Analysis;
use Aternos\Codex\Log\LogInterface;
use IndifferentKetchup\Codex\Log\LogInterface;
/**
* Class Analysis
*
* @package Aternos\Codex\Analysis
* @package IndifferentKetchup\Codex\Analysis
*/
class Analysis implements AnalysisInterface
{

View File

@@ -1,9 +1,9 @@
<?php
namespace Aternos\Codex\Analysis;
namespace IndifferentKetchup\Codex\Analysis;
use ArrayAccess;
use Aternos\Codex\Log\LogInterface;
use IndifferentKetchup\Codex\Log\LogInterface;
use Countable;
use Iterator;
use JsonSerializable;
@@ -11,7 +11,7 @@ use JsonSerializable;
/**
* Interface AnalysisInterface
*
* @package Aternos\Codex\Analysis
* @package IndifferentKetchup\Codex\Analysis
*/
interface AnalysisInterface extends Iterator, Countable, ArrayAccess, JsonSerializable
{

View File

@@ -1,6 +1,6 @@
<?php
namespace Aternos\Codex\Analysis;
namespace IndifferentKetchup\Codex\Analysis;
/**
* Interface AutomatableSolutionInterface
@@ -9,7 +9,7 @@ namespace Aternos\Codex\Analysis;
* that a solution can be solved automatically
* e.g. deletion/creation/modification of files
*
* @package Aternos\Codex\Analysis
* @package IndifferentKetchup\Codex\Analysis
*/
interface AutomatableSolutionInterface extends SolutionInterface
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Analysis;
namespace IndifferentKetchup\Codex\Analysis;
/**
* Class Information
*
* @package Aternos\Codex\Analysis
* @package IndifferentKetchup\Codex\Analysis
*/
abstract class Information extends Insight implements InformationInterface
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Analysis;
namespace IndifferentKetchup\Codex\Analysis;
/**
* Interface InformationInterface
*
* @package Aternos\Codex\Analysis
* @package IndifferentKetchup\Codex\Analysis
*/
interface InformationInterface extends InsightInterface
{

View File

@@ -1,14 +1,14 @@
<?php
namespace Aternos\Codex\Analysis;
namespace IndifferentKetchup\Codex\Analysis;
use Aternos\Codex\Log\EntryInterface;
use Aternos\Codex\Log\LogInterface;
use IndifferentKetchup\Codex\Log\EntryInterface;
use IndifferentKetchup\Codex\Log\LogInterface;
/**
* Class Insight
*
* @package Aternos\Codex\Analysis
* @package IndifferentKetchup\Codex\Analysis
*/
abstract class Insight implements InsightInterface
{

View File

@@ -1,14 +1,14 @@
<?php
namespace Aternos\Codex\Analysis;
namespace IndifferentKetchup\Codex\Analysis;
use Aternos\Codex\Log\EntryInterface;
use IndifferentKetchup\Codex\Log\EntryInterface;
use JsonSerializable;
/**
* Interface InsightInterface
*
* @package Aternos\Codex\Analysis
* @package IndifferentKetchup\Codex\Analysis
*/
interface InsightInterface extends JsonSerializable
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Analysis;
namespace IndifferentKetchup\Codex\Analysis;
/**
* Interface PatternInsightInterface
*
* @package Aternos\Codex\Analysis
* @package IndifferentKetchup\Codex\Analysis
*/
interface PatternInsightInterface extends InsightInterface
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Analysis;
namespace IndifferentKetchup\Codex\Analysis;
/**
* Class Problem
*
* @package Aternos\Codex\Analysis
* @package IndifferentKetchup\Codex\Analysis
*/
abstract class Problem extends Insight implements ProblemInterface
{

View File

@@ -1,6 +1,6 @@
<?php
namespace Aternos\Codex\Analysis;
namespace IndifferentKetchup\Codex\Analysis;
use ArrayAccess;
use Countable;
@@ -9,7 +9,7 @@ use Iterator;
/**
* Interface ProblemInterface
*
* @package Aternos\Codex\Analysis
* @package IndifferentKetchup\Codex\Analysis
*/
interface ProblemInterface extends Iterator, Countable, ArrayAccess, InsightInterface
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Analysis;
namespace IndifferentKetchup\Codex\Analysis;
/**
* Class Solution
*
* @package Aternos\Codex\Analysis
* @package IndifferentKetchup\Codex\Analysis
*/
abstract class Solution implements SolutionInterface
{

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Analysis;
namespace IndifferentKetchup\Codex\Analysis;
use JsonSerializable;
/**
* Interface SolutionInterface
*
* @package Aternos\Codex\Analysis
* @package IndifferentKetchup\Codex\Analysis
*/
interface SolutionInterface extends JsonSerializable
{

View File

@@ -1,17 +1,17 @@
<?php
namespace Aternos\Codex\Detective;
namespace IndifferentKetchup\Codex\Detective;
use Aternos\Codex\Log\DetectableLogInterface;
use Aternos\Codex\Log\File\LogFileInterface;
use Aternos\Codex\Log\Log;
use Aternos\Codex\Log\LogInterface;
use IndifferentKetchup\Codex\Log\DetectableLogInterface;
use IndifferentKetchup\Codex\Log\File\LogFileInterface;
use IndifferentKetchup\Codex\Log\Log;
use IndifferentKetchup\Codex\Log\LogInterface;
use InvalidArgumentException;
/**
* Class Detective
*
* @package Aternos\Codex\Detective
* @package IndifferentKetchup\Codex\Detective
*/
class Detective implements DetectiveInterface
{

View File

@@ -1,14 +1,14 @@
<?php
namespace Aternos\Codex\Detective;
namespace IndifferentKetchup\Codex\Detective;
use Aternos\Codex\Log\File\LogFileInterface;
use Aternos\Codex\Log\LogInterface;
use IndifferentKetchup\Codex\Log\File\LogFileInterface;
use IndifferentKetchup\Codex\Log\LogInterface;
/**
* Interface DetectiveInterface
*
* @package Aternos\Codex\Detective
* @package IndifferentKetchup\Codex\Detective
*/
interface DetectiveInterface
{

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Detective;
namespace IndifferentKetchup\Codex\Detective;
use Aternos\Codex\Log\File\LogFileInterface;
use IndifferentKetchup\Codex\Log\File\LogFileInterface;
/**
* Class Detector
*
* @package Aternos\Codex\Detective
* @package IndifferentKetchup\Codex\Detective
*/
abstract class Detector implements DetectorInterface
{

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Detective;
namespace IndifferentKetchup\Codex\Detective;
use Aternos\Codex\Log\File\LogFileInterface;
use IndifferentKetchup\Codex\Log\File\LogFileInterface;
/**
* Interface DetectorInterface
*
* @package Aternos\Codex\Detective
* @package IndifferentKetchup\Codex\Detective
*/
interface DetectorInterface
{

View File

@@ -0,0 +1,45 @@
<?php
namespace IndifferentKetchup\Codex\Detective;
/**
* Match a regex against the source path of the log file
*
* Returns a configured weight when the LogFileInterface exposes a non-null
* path that matches $pattern. Returns false when no path is known
* (StringLogFile, StreamLogFile) or when the pattern does not match. Pattern
* is compared against the full path; anchor with $ for strict suffix matching.
*
* @package IndifferentKetchup\Codex\Detective
*/
class FilenameDetector extends Detector
{
protected ?string $pattern = null;
protected float $weight = 0.95;
public function setPattern(string $pattern): static
{
$this->pattern = $pattern;
return $this;
}
public function setWeight(float $weight): static
{
$this->weight = $weight;
return $this;
}
public function detect(): bool|float
{
$path = $this->logFile->getPath();
if ($path === null || $this->pattern === null) {
return false;
}
if (preg_match($this->pattern, $path) === 1) {
return $this->weight;
}
return false;
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace IndifferentKetchup\Codex\Detective\Hytale;
use IndifferentKetchup\Codex\Detective\Detective;
class HytaleDetective extends Detective
{
// TODO: implement game-specific log type detection
}

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Detective;
namespace IndifferentKetchup\Codex\Detective;
/**
* Class LinePatternDetector
*
* @package Aternos\Codex\Detective
* @package IndifferentKetchup\Codex\Detective
*/
class LinePatternDetector extends PatternDetector
{

View File

@@ -0,0 +1,10 @@
<?php
namespace IndifferentKetchup\Codex\Detective\Minecraft;
use IndifferentKetchup\Codex\Detective\Detective;
class MinecraftDetective extends Detective
{
// TODO: implement game-specific log type detection
}

View File

@@ -1,6 +1,6 @@
<?php
namespace Aternos\Codex\Detective;
namespace IndifferentKetchup\Codex\Detective;
/**
* MultiPatternDetector can detect multiple patterns in a log and return true if all patterns are found

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Detective;
namespace IndifferentKetchup\Codex\Detective;
/**
* Class PatternDetector
*
* @package Aternos\Codex\Detective
* @package IndifferentKetchup\Codex\Detective
*/
abstract class PatternDetector extends Detector
{

View File

@@ -0,0 +1,38 @@
<?php
namespace IndifferentKetchup\Codex\Detective\ProjectZomboid;
use IndifferentKetchup\Codex\Detective\Detective;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidAdminLog;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidBurdJournalsLog;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidChatLog;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidClientActionLog;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidCmdLog;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidItemLog;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidMapLog;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidPerkLog;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidPvpLog;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidServerLog;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidUserLog;
/**
* Pre-registers all eleven ProjectZomboid log classes so that detect()
* can dispatch among them on filename hint + content signature.
*/
class ProjectZomboidDetective extends Detective
{
public function __construct()
{
$this->addPossibleLogClass(ProjectZomboidServerLog::class);
$this->addPossibleLogClass(ProjectZomboidChatLog::class);
$this->addPossibleLogClass(ProjectZomboidClientActionLog::class);
$this->addPossibleLogClass(ProjectZomboidCmdLog::class);
$this->addPossibleLogClass(ProjectZomboidItemLog::class);
$this->addPossibleLogClass(ProjectZomboidMapLog::class);
$this->addPossibleLogClass(ProjectZomboidPerkLog::class);
$this->addPossibleLogClass(ProjectZomboidPvpLog::class);
$this->addPossibleLogClass(ProjectZomboidAdminLog::class);
$this->addPossibleLogClass(ProjectZomboidUserLog::class);
$this->addPossibleLogClass(ProjectZomboidBurdJournalsLog::class);
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace IndifferentKetchup\Codex\Detective\SevenDaysToDie;
use IndifferentKetchup\Codex\Detective\Detective;
class SevenDaysToDieDetective extends Detective
{
// TODO: implement game-specific log type detection
}

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Detective;
namespace IndifferentKetchup\Codex\Detective;
/**
* Class SinglePatternDetector
*
* @package Aternos\Codex\Detective
* @package IndifferentKetchup\Codex\Detective
*/
class SinglePatternDetector extends PatternDetector
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Detective;
namespace IndifferentKetchup\Codex\Detective;
/**
* Class WeightedSinglePatternDetector
*
* @package Aternos\Codex\Detective
* @package IndifferentKetchup\Codex\Detective
*/
class WeightedSinglePatternDetector extends SinglePatternDetector
{

View File

@@ -1,14 +1,14 @@
<?php
namespace Aternos\Codex\Log;
namespace IndifferentKetchup\Codex\Log;
use Aternos\Codex\Analyser\AnalyserInterface;
use Aternos\Codex\Analysis\AnalysisInterface;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analysis\AnalysisInterface;
/**
* Class AnalysableLog
*
* @package Aternos\Codex\Log
* @package IndifferentKetchup\Codex\Log
*/
abstract class AnalysableLog extends Log implements AnalysableLogInterface
{

View File

@@ -1,14 +1,14 @@
<?php
namespace Aternos\Codex\Log;
namespace IndifferentKetchup\Codex\Log;
use Aternos\Codex\Analyser\AnalyserInterface;
use Aternos\Codex\Analysis\AnalysisInterface;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analysis\AnalysisInterface;
/**
* Interface AnalysableLogInterface
*
* @package Aternos\Codex\Log
* @package IndifferentKetchup\Codex\Log
*/
interface AnalysableLogInterface
{

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Log;
namespace IndifferentKetchup\Codex\Log;
use Aternos\Codex\Detective\DetectorInterface;
use IndifferentKetchup\Codex\Detective\DetectorInterface;
/**
* Interface DetectableLogInterface
*
* @package Aternos\Codex\Log
* @package IndifferentKetchup\Codex\Log
*/
interface DetectableLogInterface extends LogInterface
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Log;
namespace IndifferentKetchup\Codex\Log;
/**
* Class Entry
*
* @package Aternos\Codex\Log
* @package IndifferentKetchup\Codex\Log
*/
class Entry implements EntryInterface
{

View File

@@ -1,6 +1,6 @@
<?php
namespace Aternos\Codex\Log;
namespace IndifferentKetchup\Codex\Log;
use ArrayAccess;
use Countable;
@@ -10,7 +10,7 @@ use JsonSerializable;
/**
* Interface EntryInterface
*
* @package Aternos\Codex\Log
* @package IndifferentKetchup\Codex\Log
*/
interface EntryInterface extends Iterator, Countable, ArrayAccess, JsonSerializable
{

View File

@@ -1,15 +1,16 @@
<?php
namespace Aternos\Codex\Log\File;
namespace IndifferentKetchup\Codex\Log\File;
/**
* Class LogFile
*
* @package Aternos\Codex\Log\File
* @package IndifferentKetchup\Codex\Log\File
*/
abstract class LogFile implements LogFileInterface
{
protected ?string $content = null;
protected ?string $path = null;
/**
* Get the log file content
@@ -20,4 +21,14 @@ abstract class LogFile implements LogFileInterface
{
return $this->content;
}
/**
* Get the source path of the log file when one is known
*
* @return string|null
*/
public function getPath(): ?string
{
return $this->path;
}
}

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Log\File;
namespace IndifferentKetchup\Codex\Log\File;
/**
* Interface LogFileInterface
*
* @package Aternos\Codex\Log\File
* @package IndifferentKetchup\Codex\Log\File
*/
interface LogFileInterface
{
@@ -15,4 +15,15 @@ interface LogFileInterface
* @return string
*/
public function getContent(): string;
/**
* Get the source path of the log file when one is known
*
* Returns null for log files without a filesystem origin (string content,
* arbitrary streams). Concrete implementations should return the path used
* to construct them when applicable.
*
* @return string|null
*/
public function getPath(): ?string;
}

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Log\File;
namespace IndifferentKetchup\Codex\Log\File;
use InvalidArgumentException;
/**
* Class PathLogFile
*
* @package Aternos\Codex\Log\File
* @package IndifferentKetchup\Codex\Log\File
*/
class PathLogFile extends LogFile
{
@@ -22,6 +22,7 @@ class PathLogFile extends LogFile
throw new InvalidArgumentException("File '" . $path . "' not found.");
}
$this->path = $path;
$this->content = file_get_contents($path);
}
}

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Log\File;
namespace IndifferentKetchup\Codex\Log\File;
use InvalidArgumentException;
/**
* Class StreamLogFile
*
* @package Aternos\Codex\Log\File
* @package IndifferentKetchup\Codex\Log\File
*/
class StreamLogFile extends LogFile
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Log\File;
namespace IndifferentKetchup\Codex\Log\File;
/**
* Class StringLogFile
*
* @package Aternos\Codex\Log\File
* @package IndifferentKetchup\Codex\Log\File
*/
class StringLogFile extends LogFile
{

0
src/Log/Hytale/.gitkeep Normal file
View File

View File

@@ -1,6 +1,6 @@
<?php
namespace Aternos\Codex\Log;
namespace IndifferentKetchup\Codex\Log;
enum Level: int implements LevelInterface
{

View File

@@ -1,6 +1,6 @@
<?php
namespace Aternos\Codex\Log;
namespace IndifferentKetchup\Codex\Log;
use JsonSerializable;

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Log;
namespace IndifferentKetchup\Codex\Log;
/**
* Class Line
*
* @package Aternos\Codex\Log
* @package IndifferentKetchup\Codex\Log
*/
class Line implements LineInterface
{

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Log;
namespace IndifferentKetchup\Codex\Log;
use JsonSerializable;
/**
* Interface LineInterface
*
* @package Aternos\Codex\Log
* @package IndifferentKetchup\Codex\Log
*/
interface LineInterface extends JsonSerializable
{

View File

@@ -1,15 +1,15 @@
<?php
namespace Aternos\Codex\Log;
namespace IndifferentKetchup\Codex\Log;
use Aternos\Codex\Log\File\LogFileInterface;
use Aternos\Codex\Parser\DefaultParser;
use Aternos\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Log\File\LogFileInterface;
use IndifferentKetchup\Codex\Parser\DefaultParser;
use IndifferentKetchup\Codex\Parser\ParserInterface;
/**
* Class Log
*
* @package Aternos\Codex\Log
* @package IndifferentKetchup\Codex\Log
*/
class Log implements LogInterface
{

View File

@@ -1,10 +1,10 @@
<?php
namespace Aternos\Codex\Log;
namespace IndifferentKetchup\Codex\Log;
use ArrayAccess;
use Aternos\Codex\Log\File\LogFileInterface;
use Aternos\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Log\File\LogFileInterface;
use IndifferentKetchup\Codex\Parser\ParserInterface;
use Countable;
use Iterator;
use JsonSerializable;
@@ -12,7 +12,7 @@ use JsonSerializable;
/**
* Interface LogInterface
*
* @package Aternos\Codex\Log
* @package IndifferentKetchup\Codex\Log
*/
interface LogInterface extends Iterator, Countable, ArrayAccess, JsonSerializable
{

View File

View File

@@ -0,0 +1,47 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Parser\PatternParser;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\AdminPattern;
class ProjectZomboidAdminLog extends ProjectZomboidEventLog
{
public static function getDefaultParser(): ParserInterface
{
return static::makePatternParser(
AdminPattern::LINE,
[PatternParser::TIME]
);
}
public static function getDefaultAnalyser(): AnalyserInterface
{
return new PatternAnalyser();
}
public static function getDetectors(): array
{
return [
(new FilenameDetector())
->setPattern('/_admin\.txt$/')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/^\[[^\]]+\] .+? added item Base\.\S+ in .+?\'s inventory/m')
->setWeight(0.90),
(new WeightedSinglePatternDetector())
->setPattern('/^\[[^\]]+\] .+? granted (?:admin|user|moderator|gm|observer) access level on /m')
->setWeight(0.85),
];
}
public function getTitle(): string
{
return "Project Zomboid Admin Log";
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Parser\PatternParser;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\BurdJournalsPattern;
class ProjectZomboidBurdJournalsLog extends ProjectZomboidEventLog
{
public static function getDefaultParser(): ParserInterface
{
return static::makePatternParser(
BurdJournalsPattern::LINE,
[PatternParser::TIME, PatternParser::PREFIX, PatternParser::LEVEL]
);
}
public static function getDefaultAnalyser(): AnalyserInterface
{
return new PatternAnalyser();
}
public static function getDetectors(): array
{
return [
(new FilenameDetector())
->setPattern('/_BurdJournals\.txt$/')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/\[BurdJournals\]/')
->setWeight(0.95),
];
}
public function getTitle(): string
{
return "Project Zomboid BurdJournals Mod Log";
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Parser\PatternParser;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\ChatPattern;
class ProjectZomboidChatLog extends ProjectZomboidEventLog
{
public static function getDefaultParser(): ParserInterface
{
return static::makePatternParser(
ChatPattern::LINE,
[PatternParser::TIME, PatternParser::LEVEL]
);
}
public static function getDefaultAnalyser(): AnalyserInterface
{
return new PatternAnalyser();
}
public static function getDetectors(): array
{
return [
(new FilenameDetector())
->setPattern('/_chat\.txt$/')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/Got message:ChatMessage\{chat=\w+/')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/Start chat server initialization/')
->setWeight(0.85),
];
}
public function getTitle(): string
{
return "Project Zomboid Chat Log";
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Parser\PatternParser;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\ClientActionPattern;
class ProjectZomboidClientActionLog extends ProjectZomboidEventLog
{
public static function getDefaultParser(): ParserInterface
{
return static::makePatternParser(
ClientActionPattern::LINE,
[PatternParser::TIME]
);
}
public static function getDefaultAnalyser(): AnalyserInterface
{
return new PatternAnalyser();
}
public static function getDetectors(): array
{
return [
(new FilenameDetector())
->setPattern('/_ClientActionLog\.txt$/')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/\[\d{17}\]\[(?:ISEnterVehicle|ISExitVehicle|ISWalkToTimedAction)\]\[/')
->setWeight(0.95),
];
}
public function getTitle(): string
{
return "Project Zomboid Client Action Log";
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Parser\PatternParser;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\CmdPattern;
class ProjectZomboidCmdLog extends ProjectZomboidEventLog
{
public static function getDefaultParser(): ParserInterface
{
return static::makePatternParser(
CmdPattern::LINE,
[PatternParser::TIME]
);
}
public static function getDefaultAnalyser(): AnalyserInterface
{
return new PatternAnalyser();
}
public static function getDetectors(): array
{
return [
(new FilenameDetector())
->setPattern('/_cmd\.txt$/')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/^\[[^\]]+\] \d{17} "[^"]+" \w[\w.]+ @ \d/m')
->setWeight(0.85),
];
}
public function getTitle(): string
{
return "Project Zomboid Command Log";
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
/**
* Marker base for ProjectZomboid logs whose entries are strictly one line
* each (the ten structured event files: admin, BurdJournals, chat,
* ClientActionLog, cmd, item, map, PerkLog, pvp, user). Distinct from
* ProjectZomboidServerLog, which permits multi-line entries
* (DebugLog-server stack traces).
*/
abstract class ProjectZomboidEventLog extends ProjectZomboidLog
{
}

View File

@@ -0,0 +1,44 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Parser\PatternParser;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\ItemPattern;
class ProjectZomboidItemLog extends ProjectZomboidEventLog
{
public static function getDefaultParser(): ParserInterface
{
return static::makePatternParser(
ItemPattern::LINE,
[PatternParser::TIME]
);
}
public static function getDefaultAnalyser(): AnalyserInterface
{
return new PatternAnalyser();
}
public static function getDetectors(): array
{
return [
(new FilenameDetector())
->setPattern('/_item\.txt$/')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/^\[[^\]]+\] \d{17} "[^"]+" (?:container|floor|inventory) [+\-]\d+ /m')
->setWeight(0.90),
];
}
public function getTitle(): string
{
return "Project Zomboid Item Log";
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use DateTimeZone;
use IndifferentKetchup\Codex\Log\AnalysableLog;
use IndifferentKetchup\Codex\Log\DetectableLogInterface;
use IndifferentKetchup\Codex\Parser\PatternParser;
abstract class ProjectZomboidLog extends AnalysableLog implements DetectableLogInterface
{
public const string TIME_FORMAT = 'd-m-y H:i:s.v';
public const string DEFAULT_TIMEZONE = 'UTC';
/**
* Build a PatternParser preconfigured with the shared PZ time format
* and timezone. Subclasses pass their line regex and the names of the
* capture groups by index.
*
* @param string $pattern PCRE regex anchored at line start, with named groups
* @param array<int, string> $matches Match-type constants in capture-group order
*/
protected static function makePatternParser(string $pattern, array $matches): PatternParser
{
return (new PatternParser())
->setPattern($pattern)
->setMatches($matches)
->setTimeFormat(static::TIME_FORMAT)
->setTimezone(new DateTimeZone(static::DEFAULT_TIMEZONE));
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Parser\PatternParser;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\MapPattern;
class ProjectZomboidMapLog extends ProjectZomboidEventLog
{
public static function getDefaultParser(): ParserInterface
{
return static::makePatternParser(
MapPattern::LINE,
[PatternParser::TIME]
);
}
public static function getDefaultAnalyser(): AnalyserInterface
{
return new PatternAnalyser();
}
public static function getDetectors(): array
{
return [
(new FilenameDetector())
->setPattern('/_map\.txt$/')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/^\[[^\]]+\] \d{17} "[^"]+" (?:added|removed) (?:Base\.|IsoObject )/m')
->setWeight(0.90),
];
}
public function getTitle(): string
{
return "Project Zomboid Map Log";
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Parser\PatternParser;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\PerkPattern;
class ProjectZomboidPerkLog extends ProjectZomboidEventLog
{
public static function getDefaultParser(): ParserInterface
{
return static::makePatternParser(
PerkPattern::LINE,
[PatternParser::TIME]
);
}
public static function getDefaultAnalyser(): AnalyserInterface
{
return new PatternAnalyser();
}
public static function getDetectors(): array
{
return [
(new FilenameDetector())
->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";
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Parser\PatternParser;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\PvpPattern;
class ProjectZomboidPvpLog extends ProjectZomboidEventLog
{
public static function getDefaultParser(): ParserInterface
{
return static::makePatternParser(
PvpPattern::LINE,
[PatternParser::TIME, PatternParser::LEVEL, PatternParser::PREFIX]
);
}
public static function getDefaultAnalyser(): AnalyserInterface
{
return new PatternAnalyser();
}
public static function getDetectors(): array
{
return [
(new FilenameDetector())
->setPattern('/_pvp\.txt$/')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/^\[[^\]]+\]\[\w+\] Combat: "[^"]+" \(/m')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/^\[[^\]]+\]\[\w+\] Safety: "/m')
->setWeight(0.85),
];
}
public function getTitle(): string
{
return "Project Zomboid PvP Log";
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Parser\PatternParser;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\DebugServerPattern;
/**
* Project Zomboid engine debug log (DebugLog-server.txt).
*
* Multi-line format: ERROR entries are followed by tab-indented stack trace
* frames. PatternParser handles continuation by appending non-matching lines
* to the most recent Entry, which is exactly the behaviour we need.
*/
class ProjectZomboidServerLog extends ProjectZomboidLog
{
public static function getDefaultParser(): ParserInterface
{
return static::makePatternParser(
DebugServerPattern::LINE,
[PatternParser::TIME, PatternParser::LEVEL, PatternParser::PREFIX]
);
}
public static function getDefaultAnalyser(): AnalyserInterface
{
return new PatternAnalyser();
}
public static function getDetectors(): array
{
return [
(new FilenameDetector())
->setPattern('/DebugLog-server\.txt$/')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/version=\d+\.\d+\.\d+ [a-f0-9]{40}/')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] (?:LOG|WARN|ERROR):\s+\w+\s+f:\d+, t:\d+, st:[\d,]+>/m')
->setWeight(0.80),
];
}
public function getTitle(): string
{
return "Project Zomboid Debug Server Log";
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace IndifferentKetchup\Codex\Log\ProjectZomboid;
use IndifferentKetchup\Codex\Analyser\AnalyserInterface;
use IndifferentKetchup\Codex\Analyser\PatternAnalyser;
use IndifferentKetchup\Codex\Detective\FilenameDetector;
use IndifferentKetchup\Codex\Detective\WeightedSinglePatternDetector;
use IndifferentKetchup\Codex\Parser\ParserInterface;
use IndifferentKetchup\Codex\Parser\PatternParser;
use IndifferentKetchup\Codex\Pattern\ProjectZomboid\UserPattern;
class ProjectZomboidUserLog extends ProjectZomboidEventLog
{
public static function getDefaultParser(): ParserInterface
{
return static::makePatternParser(
UserPattern::LINE,
[PatternParser::TIME]
);
}
public static function getDefaultAnalyser(): AnalyserInterface
{
return new PatternAnalyser();
}
public static function getDetectors(): array
{
return [
(new FilenameDetector())
->setPattern('/_user\.txt$/')
->setWeight(0.95),
(new WeightedSinglePatternDetector())
->setPattern('/^\[[^\]]+\] Connection (?:add|disconnect) index=\d+ guid=\d+/m')
->setWeight(0.90),
(new WeightedSinglePatternDetector())
->setPattern('/^\[[^\]]+\] \d{17} "[^"]+" (?:attempting to join|allowed to join)/m')
->setWeight(0.85),
];
}
public function getTitle(): string
{
return "Project Zomboid User Log";
}
}

View File

View File

@@ -1,14 +1,14 @@
<?php
namespace Aternos\Codex\Parser;
namespace IndifferentKetchup\Codex\Parser;
use Aternos\Codex\Log\Entry;
use Aternos\Codex\Log\Line;
use IndifferentKetchup\Codex\Log\Entry;
use IndifferentKetchup\Codex\Log\Line;
/**
* Class DefaultParser
*
* @package Aternos\Codex\Parser
* @package IndifferentKetchup\Codex\Parser
*/
class DefaultParser extends Parser
{

View File

View File

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Parser;
namespace IndifferentKetchup\Codex\Parser;
use Aternos\Codex\Log\LogInterface;
use IndifferentKetchup\Codex\Log\LogInterface;
/**
* Class Parser
*
* @package Aternos\Codex\Parser
* @package IndifferentKetchup\Codex\Parser
*/
abstract class Parser implements ParserInterface
{

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Parser;
namespace IndifferentKetchup\Codex\Parser;
use Aternos\Codex\Log\LogInterface;
use IndifferentKetchup\Codex\Log\LogInterface;
/**
* Interface ParserInterface
*
* @package Aternos\Codex\Parser
* @package IndifferentKetchup\Codex\Parser
*/
interface ParserInterface
{

View File

@@ -1,12 +1,12 @@
<?php
namespace Aternos\Codex\Parser;
namespace IndifferentKetchup\Codex\Parser;
use Aternos\Codex\Log\Entry;
use Aternos\Codex\Log\EntryInterface;
use Aternos\Codex\Log\Level;
use Aternos\Codex\Log\LevelInterface;
use Aternos\Codex\Log\Line;
use IndifferentKetchup\Codex\Log\Entry;
use IndifferentKetchup\Codex\Log\EntryInterface;
use IndifferentKetchup\Codex\Log\Level;
use IndifferentKetchup\Codex\Log\LevelInterface;
use IndifferentKetchup\Codex\Log\Line;
use DateTime;
use DateTimeZone;
use InvalidArgumentException;
@@ -14,7 +14,7 @@ use InvalidArgumentException;
/**
* Class PatternParser
*
* @package Aternos\Codex\Parser
* @package IndifferentKetchup\Codex\Parser
*/
class PatternParser extends Parser
{

View File

View File

View File

View File

View File

@@ -0,0 +1,28 @@
<?php
namespace IndifferentKetchup\Codex\Pattern\ProjectZomboid;
/**
* Regex constants for the Project Zomboid admin.txt format.
*
* Free-form English: '[time] <admin> <verb> ...' Verb dispatch is left
* to the analyser layer. The admin name itself can contain parentheses
* (Nathan(Weerd)) or whitespace (silly goose) so the parser captures
* only the timestamp.
*/
class AdminPattern
{
public const string LINE = '/^\[(\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\] .+\.$/';
public const string ADDED_ITEM = '/^(?<admin>.+?) added item (?<item>Base\.\S+) in (?<target>.+?)\'s inventory$/';
public const string ADDED_XP = '/^(?<admin>.+?) added (?<amount>[\d.]+) (?<skill>\S+) xp\'s to (?<target>.+)$/';
public const string GRANTED_ACCESS = '/^(?<admin>.+?) granted (?<level>\w+) access level on (?<target>.+)$/';
public const string CHANGED_OPTION = '/^(?<admin>.+?) changed option (?<option>\S+?)=(?<value>.+)$/';
public const string RELOADED_OPTIONS = '/^(?<admin>.+?) reloaded options$/';
public const string TELEPORTED = '/^(?<admin>.+?) teleported (?<target>.+?) to (?<x>\d+),(?<y>\d+),(?<z>-?\d+)$/';
}

View File

@@ -0,0 +1,18 @@
<?php
namespace IndifferentKetchup\Codex\Pattern\ProjectZomboid;
/**
* Regex constants for the Project Zomboid BurdJournals.txt format.
*
* [time] [BurdJournals] LEVEL: message.
*
* LINE captures, in order:
* 1. time
* 2. tag (e.g. BurdJournals)
* 3. level (WARNING | ERROR | INFO | DEBUG)
*/
class BurdJournalsPattern
{
public const string LINE = '/^\[(\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\] \[(\w+)\] (WARNING|ERROR|INFO|DEBUG): .+\.?$/';
}

View File

@@ -0,0 +1,24 @@
<?php
namespace IndifferentKetchup\Codex\Pattern\ProjectZomboid;
/**
* Regex constants for the Project Zomboid chat.txt format.
*
* Two row variants share the file: bracket-level chat-engine events
* (e.g. [time][info] message) and bare server-alert messages
* (e.g. [time] Server alert ...). The LINE pattern accepts both via an
* optional non-capturing wrapper around the level.
*
* LINE captures, in order:
* 1. time (DD-MM-YY HH:MM:SS.mmm)
* 2. level (info | warn | error | empty for server alerts)
*/
class ChatPattern
{
public const string LINE = '/^\[(\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\](?:\[(\w+)\])?\s+.*$/';
public const string CHAT_MESSAGE = '/ChatMessage\{chat=(?<channel>\w+), author=\'(?<author>[^\']+)\', text=\'(?<text>.*?)\'\}/';
public const string SERVER_ALERT = '/^Server alert message:\s*\'(?<text>.*?)\'\s+sent\.\.?$/';
}

View File

@@ -0,0 +1,21 @@
<?php
namespace IndifferentKetchup\Codex\Pattern\ProjectZomboid;
/**
* Regex constants for the Project Zomboid ClientActionLog.txt format.
*
* Strict 5-field bracketed structure:
* [time] [steamid][action][player][x,y,z][param].
*
* LINE captures, in order:
* 1. time (DD-MM-YY HH:MM:SS.mmm)
*
* The remaining bracketed fields are extractable via FIELDS for analysers.
*/
class ClientActionPattern
{
public const string LINE = '/^\[(\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\] \[\d{17}\]\[[^\]]+\]\[[^\]]+\]\[\d+,\d+,\d+\]\[[^\]]+\]\.$/';
public const string FIELDS = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] \[(?<steamid>\d{17})\]\[(?<action>[^\]]+)\]\[(?<player>[^\]]+)\]\[(?<x>\d+),(?<y>\d+),(?<z>\d+)\]\[(?<param>[^\]]+)\]\.$/';
}

View File

@@ -0,0 +1,18 @@
<?php
namespace IndifferentKetchup\Codex\Pattern\ProjectZomboid;
/**
* Regex constants for the Project Zomboid cmd.txt format.
*
* [time] steamid "player" command @ x,y,z.
*
* LINE captures, in order:
* 1. time
*/
class CmdPattern
{
public const string LINE = '/^\[(\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\] \d{17} "[^"]+" \S+ @ \d+,\d+,\d+\.$/';
public const string FIELDS = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] (?<steamid>\d{17}) "(?<player>[^"]+)" (?<command>\S+) @ (?<x>\d+),(?<y>\d+),(?<z>\d+)\.$/';
}

View File

@@ -0,0 +1,27 @@
<?php
namespace IndifferentKetchup\Codex\Pattern\ProjectZomboid;
/**
* Regex constants for the Project Zomboid DebugLog-server.txt format.
*
* LINE captures, in order:
* 1. time (DD-MM-YY HH:MM:SS.mmm)
* 2. level (LOG | WARN | ERROR | INFO | DEBUG)
* 3. prefix (subsystem name, e.g. General, Mod, WorldGen)
*
* The f:/t:/st: metadata and trailing message body are intentionally not
* captured by the parser; analyzers reach into the Line raw text directly.
*/
class DebugServerPattern
{
public const string LINE = '/^\[(\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\]\s+(\w+)\s*:\s+(\S+)\s+f:\d+,\s+t:\d+,\s+st:[\d,]+>\s+.*$/';
public const string VERSION = '/version=(?<version>\S+) (?<hash>[a-f0-9]{40}) (?<date>\d{4}-\d{2}-\d{2}) (?<time>\d{2}:\d{2}:\d{2})/';
public const string MOD_LOAD = '/loading (?<mod>[A-Za-z0-9_]+)\.?$/';
public const string MOD_MISSING = '/required mod "(?<mod>[^"]+)" not found/';
public const string EXCEPTION_HEADER = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\]\s+ERROR:.*Exception thrown/';
}

View File

@@ -0,0 +1,15 @@
<?php
namespace IndifferentKetchup\Codex\Pattern\ProjectZomboid;
/**
* Regex constants for the Project Zomboid item.txt format.
*
* [time] steamid "player" location ±N x,y,z [Base.ItemId].
*/
class ItemPattern
{
public const string LINE = '/^\[(\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\] \d{17} "[^"]+" \S+ [+\-]\d+ \d+,\d+,\d+ \[[^\]]+\]\.$/';
public const string FIELDS = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] (?<steamid>\d{17}) "(?<player>[^"]+)" (?<location>\S+) (?<delta>[+\-]\d+) (?<x>\d+),(?<y>\d+),(?<z>\d+) \[(?<item>[^\]]+)\]\.$/';
}

View File

@@ -0,0 +1,18 @@
<?php
namespace IndifferentKetchup\Codex\Pattern\ProjectZomboid;
/**
* Regex constants for the Project Zomboid map.txt format.
*
* [time] steamid "player" verb object at x,y,z.
*
* Coordinates may be integer or floating point; objects may be Base.X
* tokens or 'IsoObject (X)' parenthesised forms.
*/
class MapPattern
{
public const string LINE = '/^\[(\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\] \d{17} "[^"]+" \S+ .+ at [\d.]+,[\d.]+,[\d.]+\.$/';
public const string FIELDS = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] (?<steamid>\d{17}) "(?<player>[^"]+)" (?<verb>\S+) (?<object>.+) at (?<x>[\d.]+),(?<y>[\d.]+),(?<z>[\d.]+)\.$/';
}

View File

@@ -0,0 +1,21 @@
<?php
namespace IndifferentKetchup\Codex\Pattern\ProjectZomboid;
/**
* Regex constants for the Project Zomboid PerkLog.txt format.
*
* [time] [steamid][player][x,y,z][event-or-perks][Hours Survived: N].
*
* The fourth bracketed field is either a single token (Login, Logout,
* LevelUp, etc.) or a comma-separated list of Skill=N pairs. Both fit
* the same character class.
*/
class PerkPattern
{
public const string LINE = '/^\[(\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\] \[\d{17}\]\[[^\]]+\]\[\d+,\d+,\d+\]\[[^\]]+\]\[Hours Survived: \d+\]\.$/';
public const string FIELDS = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] \[(?<steamid>\d{17})\]\[(?<player>[^\]]+)\]\[(?<x>\d+),(?<y>\d+),(?<z>\d+)\]\[(?<event>[^\]]+)\]\[Hours Survived: (?<hours>\d+)\]\.$/';
public const string PERK_PAIR = '/(?<skill>[A-Za-z_]+)=(?<level>\d+)/';
}

View File

@@ -0,0 +1,27 @@
<?php
namespace IndifferentKetchup\Codex\Pattern\ProjectZomboid;
/**
* Regex constants for the Project Zomboid pvp.txt format.
*
* Two row variants share the file: Safe House toggles
* [time][LOG] Safety: "player" (x,y,z) restore true.
* and Combat events
* [time][INFO] Combat: "attacker" (x,y,z) hit "victim" (x,y,z) weapon="W" damage=N.NN.
*
* Z coordinates can be negative (basement levels: -1, -2).
*
* LINE captures, in order:
* 1. time
* 2. level (LOG | INFO | WARN | ERROR)
* 3. subsystem (Safety | Combat)
*/
class PvpPattern
{
public const string LINE = '/^\[(\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\]\[(LOG|INFO|WARN|ERROR)\] (\w+): .+\.$/';
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)\.$/';
}

View File

@@ -0,0 +1,22 @@
<?php
namespace IndifferentKetchup\Codex\Pattern\ProjectZomboid;
/**
* Regex constants for the Project Zomboid user.txt format.
*
* Two row variants share the file: low-level connection events
* [time] Connection {add|disconnect} index=N guid=N id={N|null}.
* and player join/leave events
* [time] steamid "player" {attempting|allowed} to join.
*
* Both variants are accepted by LINE, which captures only the timestamp.
*/
class UserPattern
{
public const string LINE = '/^\[(\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\] (?:Connection (?:add|disconnect) index=\d+ guid=\d+ id=(?:\d+|null)|\d{17} "[^"]+" .+?)\.?$/';
public const string CONNECTION = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] Connection (?<action>add|disconnect) index=(?<index>\d+) guid=(?<guid>\d+) id=(?<id>\d+|null)\.?$/';
public const string PLAYER_EVENT = '/^\[\d{2}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] (?<steamid>\d{17}) "(?<player>[^"]+)" (?<event>.+?)\.?$/';
}

View File

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Printer;
namespace IndifferentKetchup\Codex\Printer;
use Aternos\Codex\Log\LineInterface;
use IndifferentKetchup\Codex\Log\LineInterface;
/**
* Class DefaultPrinter
*
* @package Aternos\Codex\Printer
* @package IndifferentKetchup\Codex\Printer
*/
class DefaultPrinter extends Printer
{

View File

@@ -1,13 +1,13 @@
<?php
namespace Aternos\Codex\Printer;
namespace IndifferentKetchup\Codex\Printer;
use Aternos\Codex\Log\LineInterface;
use IndifferentKetchup\Codex\Log\LineInterface;
/**
* Class ModifiableDefaultPrinter
*
* @package Aternos\Codex\Printer
* @package IndifferentKetchup\Codex\Printer
*/
class ModifiableDefaultPrinter extends ModifiablePrinter
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Printer;
namespace IndifferentKetchup\Codex\Printer;
/**
* Class ModifiablePrinter
*
* @package Aternos\Codex\Printer
* @package IndifferentKetchup\Codex\Printer
*/
abstract class ModifiablePrinter extends Printer implements ModifiablePrinterInterface
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Printer;
namespace IndifferentKetchup\Codex\Printer;
/**
* Interface ModifiablePrinterInterface
*
* @package Aternos\Codex\Printer
* @package IndifferentKetchup\Codex\Printer
*/
interface ModifiablePrinterInterface extends PrinterInterface
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Printer;
namespace IndifferentKetchup\Codex\Printer;
/**
* Class Modification
*
* @package Aternos\Codex\Printer
* @package IndifferentKetchup\Codex\Printer
*/
abstract class Modification implements ModificationInterface
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Printer;
namespace IndifferentKetchup\Codex\Printer;
/**
* Interface ModificationInterface
*
* @package Aternos\Codex\Printer
* @package IndifferentKetchup\Codex\Printer
*/
interface ModificationInterface
{

View File

@@ -1,11 +1,11 @@
<?php
namespace Aternos\Codex\Printer;
namespace IndifferentKetchup\Codex\Printer;
/**
* Class PatternModification
*
* @package Aternos\Codex\Printer
* @package IndifferentKetchup\Codex\Printer
*/
class PatternModification extends Modification
{

View File

@@ -1,15 +1,15 @@
<?php
namespace Aternos\Codex\Printer;
namespace IndifferentKetchup\Codex\Printer;
use Aternos\Codex\Log\EntryInterface;
use Aternos\Codex\Log\LineInterface;
use Aternos\Codex\Log\LogInterface;
use IndifferentKetchup\Codex\Log\EntryInterface;
use IndifferentKetchup\Codex\Log\LineInterface;
use IndifferentKetchup\Codex\Log\LogInterface;
/**
* Class Printer
*
* @package Aternos\Codex\Printer
* @package IndifferentKetchup\Codex\Printer
*/
abstract class Printer implements PrinterInterface
{

View File

@@ -1,14 +1,14 @@
<?php
namespace Aternos\Codex\Printer;
namespace IndifferentKetchup\Codex\Printer;
use Aternos\Codex\Log\EntryInterface;
use Aternos\Codex\Log\LogInterface;
use IndifferentKetchup\Codex\Log\EntryInterface;
use IndifferentKetchup\Codex\Log\LogInterface;
/**
* Interface PrinterInterface
*
* @package Aternos\Codex\Printer
* @package IndifferentKetchup\Codex\Printer
*/
interface PrinterInterface
{

Some files were not shown because too many files have changed in this diff Show More