tf-logparser 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +218 -0
- package/dist/generated/tf2-parser.js +6867 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +3 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +18 -0
- package/dist/parser.js.map +1 -0
- package/dist/schema.d.ts +3 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +429 -0
- package/dist/schema.js.map +1 -0
- package/dist/types.d.ts +372 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# tf-logparser
|
|
2
|
+
|
|
3
|
+
A TypeScript parser for Team Fortress 2 server logs. Parses raw TF2 log files into typed, structured event objects using a [Peggy](https://peggyjs.org/) grammar.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { parseLog } from "tf-logparser";
|
|
9
|
+
import type { TfLogEvent } from "tf-logparser";
|
|
10
|
+
|
|
11
|
+
const raw = fs.readFileSync("match.log", "utf-8");
|
|
12
|
+
const events: TfLogEvent[] = parseLog(raw);
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Every event includes a `timestamp` (ms since epoch) and the original `raw` log line. Events are discriminated by the `type` field, so you can narrow with a simple check:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
for (const event of events) {
|
|
19
|
+
if (event.type === "kill") {
|
|
20
|
+
console.log(`${event.player.name} killed ${event.victim.name} with ${event.weapon}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Log format spec
|
|
26
|
+
|
|
27
|
+
Each line in a TF2 server log follows this structure:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
L MM/DD/YYYY - HH:MM:SS: <event data>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Player format
|
|
34
|
+
|
|
35
|
+
Players are encoded as:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
"<name><<entityId>><<steamId>><<team>>"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For example: `"Frank<52><[U:1:156276611]><Red>"`
|
|
42
|
+
|
|
43
|
+
Parsed into:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
interface Player {
|
|
47
|
+
name: string;
|
|
48
|
+
entityId: number;
|
|
49
|
+
steamId: string;
|
|
50
|
+
team: string;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Supported event types
|
|
55
|
+
|
|
56
|
+
The parser recognizes the following events. Any line that doesn't match a known pattern is returned as an `unknown` event.
|
|
57
|
+
|
|
58
|
+
#### Combat
|
|
59
|
+
|
|
60
|
+
| Type | Description |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `damage` | Player damaged another player. Includes damage, realdamage, weapon, and optional crit/mini, headshot, airshot, height, healing fields. |
|
|
63
|
+
| `kill` | Player killed another player. Includes weapon, optional customkill, and attacker/victim positions. |
|
|
64
|
+
| `killAssist` | Player assisted a kill. Includes assister, attacker, and victim positions. |
|
|
65
|
+
| `suicide` | Player killed themselves. Includes weapon and position. |
|
|
66
|
+
| `medicDeath` | Medic was killed. Includes healing given and ubercharge percentage lost. |
|
|
67
|
+
| `medicDeathEx` | Extended medic death info with uber percentage. |
|
|
68
|
+
| `playerExtinguished` | Player extinguished a burning teammate. |
|
|
69
|
+
| `shotFired` | Player fired a weapon. |
|
|
70
|
+
| `shotHit` | Player's shot hit a target. |
|
|
71
|
+
|
|
72
|
+
#### Healing & Ubercharge
|
|
73
|
+
|
|
74
|
+
| Type | Description |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `healed` | Medic healed a target. Includes healing amount, optional airshot and height. |
|
|
77
|
+
| `chargeReady` | Medigun charge is ready. |
|
|
78
|
+
| `chargeDeployed` | Ubercharge deployed. Includes medigun type. |
|
|
79
|
+
| `chargeEnded` | Ubercharge ended. Includes duration in seconds. |
|
|
80
|
+
| `emptyUber` | Ubercharge fully depleted. |
|
|
81
|
+
| `firstHealAfterSpawn` | Time of first heal after medic spawned. |
|
|
82
|
+
| `lostUberAdvantage` | Medic lost uber advantage. Includes time in seconds. |
|
|
83
|
+
|
|
84
|
+
#### Objectives
|
|
85
|
+
|
|
86
|
+
| Type | Description |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `pointCaptured` | Team captured a control point. Includes cp index, name, number of cappers, and per-player positions. |
|
|
89
|
+
| `captureBlocked` | Player blocked a capture. Includes cp index, name, and position. |
|
|
90
|
+
|
|
91
|
+
#### Buildings & Objects
|
|
92
|
+
|
|
93
|
+
| Type | Description |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `playerBuiltObject` | Player built an object (sentry, dispenser, etc). |
|
|
96
|
+
| `killedObject` | Player destroyed an object. Includes weapon, object owner, optional assist info. |
|
|
97
|
+
| `objectDetonated` | Player detonated their own object. |
|
|
98
|
+
| `playerCarryObject` | Player picked up their building. |
|
|
99
|
+
| `playerDropObject` | Player dropped their building. |
|
|
100
|
+
|
|
101
|
+
#### Round & Game
|
|
102
|
+
|
|
103
|
+
| Type | Description |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `roundStart` | Round started. |
|
|
106
|
+
| `roundSetupBegin` | Setup phase began. |
|
|
107
|
+
| `roundSetupEnd` | Setup phase ended. |
|
|
108
|
+
| `roundWin` | Round won by a team. |
|
|
109
|
+
| `roundLength` | Round duration in seconds. |
|
|
110
|
+
| `roundOvertime` | Overtime started. |
|
|
111
|
+
| `gameOver` | Game ended with a reason string. |
|
|
112
|
+
| `currentScore` | Mid-game score report (team, score, numPlayers). |
|
|
113
|
+
| `finalScore` | End-of-game score report. |
|
|
114
|
+
| `intermissionWinLimit` | Intermission or win limit reached. |
|
|
115
|
+
|
|
116
|
+
#### Player State
|
|
117
|
+
|
|
118
|
+
| Type | Description |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `spawned` | Player spawned as a class/role. |
|
|
121
|
+
| `spawnedMFilter` | Player spawned with m_filter (optional role). |
|
|
122
|
+
| `changedRole` | Player changed class. |
|
|
123
|
+
| `changedName` | Player changed their name. |
|
|
124
|
+
| `chargedMFilter` | Player charged as role with m_filter. |
|
|
125
|
+
| `pickedUpItem` | Player picked up an item (optional healing value). |
|
|
126
|
+
| `joinedTeam` | Player joined a team. |
|
|
127
|
+
| `connected` | Player connected to the server. |
|
|
128
|
+
| `enteredGame` | Player entered the game. |
|
|
129
|
+
| `positionReport` | Player position report. |
|
|
130
|
+
|
|
131
|
+
#### Domination & Revenge
|
|
132
|
+
|
|
133
|
+
| Type | Description |
|
|
134
|
+
|---|---|
|
|
135
|
+
| `domination` | Player is dominating another. Optional assist flag. |
|
|
136
|
+
| `revenge` | Player got revenge. Optional assist flag. |
|
|
137
|
+
|
|
138
|
+
#### Chat
|
|
139
|
+
|
|
140
|
+
| Type | Description |
|
|
141
|
+
|---|---|
|
|
142
|
+
| `say` | Public chat message. |
|
|
143
|
+
| `sayTeam` | Team chat message. |
|
|
144
|
+
|
|
145
|
+
#### Pause
|
|
146
|
+
|
|
147
|
+
| Type | Description |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `matchPause` | Player triggered a pause. |
|
|
150
|
+
| `matchUnpause` | Player triggered an unpause. |
|
|
151
|
+
| `gamePaused` | Game is paused. |
|
|
152
|
+
| `gameUnpaused` | Game is unpaused. |
|
|
153
|
+
| `pauseLength` | Pause duration in seconds. |
|
|
154
|
+
|
|
155
|
+
#### Passtime
|
|
156
|
+
|
|
157
|
+
| Type | Description |
|
|
158
|
+
|---|---|
|
|
159
|
+
| `passGet` | Player got the ball. Includes firstcontact flag and position. |
|
|
160
|
+
| `passFree` | Ball became free. |
|
|
161
|
+
| `passPassCaught` | Pass was caught. Includes interception, save, handoff flags, distance, duration, and positions. |
|
|
162
|
+
| `passScore` | Player scored. Includes points, panacea, winStrat, deathbomb flags, distance, and position. |
|
|
163
|
+
| `passScoreAssist` | Player assisted a score. |
|
|
164
|
+
| `passBallStolen` | Ball was stolen. Includes stealDefense flag and positions. |
|
|
165
|
+
| `catapult` | Player used a catapult. |
|
|
166
|
+
| `passtimeBallSpawned` | Ball spawned at a location. |
|
|
167
|
+
| `passtimeBallDamage` | Ball took damage. |
|
|
168
|
+
| `panaceaCheck` | Panacea check event. |
|
|
169
|
+
|
|
170
|
+
#### System
|
|
171
|
+
|
|
172
|
+
| Type | Description |
|
|
173
|
+
|---|---|
|
|
174
|
+
| `demosTf` | Message from the demos.tf plugin. |
|
|
175
|
+
| `printingForClient` | Server printing for a client. |
|
|
176
|
+
| `unknown` | Unrecognized log line (fallback). |
|
|
177
|
+
|
|
178
|
+
## Benchmarks
|
|
179
|
+
|
|
180
|
+
Measured on real match logs (median of 20 runs after 3 warmup runs):
|
|
181
|
+
|
|
182
|
+
| Fixture | Size | Lines | Time | Lines/sec |
|
|
183
|
+
|----------------|-------:|-------:|-------:|-----------:|
|
|
184
|
+
| cp.log | 1601 KB | 12,692 | 151.1 ms | 83,985 |
|
|
185
|
+
| koth.log | 1147 KB | 8,519 | 90.5 ms | 94,089 |
|
|
186
|
+
| passtime.log | 1246 KB | 10,260 | 185.8 ms | 55,228 |
|
|
187
|
+
| payload.log | 1463 KB | 11,066 | 134.8 ms | 82,102 |
|
|
188
|
+
| ultiduo.log | 285 KB | 2,172 | 25.4 ms | 85,614 |
|
|
189
|
+
|
|
190
|
+
Run benchmarks yourself with:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
npm run build:parser && npx tsx scripts/benchmark.ts
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Tested game modes
|
|
197
|
+
|
|
198
|
+
The parser is tested against real log fixtures for:
|
|
199
|
+
|
|
200
|
+
- Control Points (5CP)
|
|
201
|
+
- King of the Hill
|
|
202
|
+
- Payload
|
|
203
|
+
- Passtime
|
|
204
|
+
- Ultiduo
|
|
205
|
+
|
|
206
|
+
## Development
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
npm run build # Generate parser + compile TypeScript
|
|
210
|
+
npm test # Build parser + run tests
|
|
211
|
+
npm run test:watch # Run tests in watch mode
|
|
212
|
+
npm run lint # Lint source
|
|
213
|
+
npm run format # Format with Prettier
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
ISC
|