@rine-kit/pubg-domain 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +38 -2
- package/dist/config/default-team.json +27 -0
- package/dist/src/config/chicken-index.d.ts +9 -0
- package/dist/src/config/chicken-index.js +37 -0
- package/dist/src/config/chicken-index.js.map +1 -0
- package/dist/src/config/team.d.ts +22 -0
- package/dist/src/config/team.js +69 -0
- package/dist/src/config/team.js.map +1 -0
- package/dist/src/context/context-store.d.ts +40 -0
- package/dist/src/context/context-store.js +119 -0
- package/dist/src/context/context-store.js.map +1 -0
- package/dist/src/context/team-context.d.ts +13 -0
- package/dist/src/context/team-context.js +16 -0
- package/dist/src/context/team-context.js.map +1 -0
- package/dist/src/core.d.ts +23 -0
- package/dist/src/core.js +24 -0
- package/dist/src/core.js.map +1 -0
- package/dist/src/data/model.d.ts +123 -0
- package/dist/src/data/model.js +100 -0
- package/dist/src/data/model.js.map +1 -0
- package/dist/src/data/pubg-api-client.d.ts +59 -0
- package/dist/src/data/pubg-api-client.js +441 -0
- package/dist/src/data/pubg-api-client.js.map +1 -0
- package/dist/src/engine/query-engine.d.ts +20 -0
- package/dist/src/engine/query-engine.js +765 -0
- package/dist/src/engine/query-engine.js.map +1 -0
- package/dist/src/index.d.ts +27 -0
- package/dist/src/index.js +28 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/migration/importer.d.ts +35 -0
- package/dist/src/migration/importer.js +229 -0
- package/dist/src/migration/importer.js.map +1 -0
- package/dist/src/review/combat-scope.d.ts +11 -0
- package/dist/src/review/combat-scope.js +101 -0
- package/dist/src/review/combat-scope.js.map +1 -0
- package/dist/src/review/event-combination-engine.d.ts +17 -0
- package/dist/src/review/event-combination-engine.js +534 -0
- package/dist/src/review/event-combination-engine.js.map +1 -0
- package/dist/src/review/fight-detector.d.ts +4 -0
- package/dist/src/review/fight-detector.js +138 -0
- package/dist/src/review/fight-detector.js.map +1 -0
- package/dist/src/review/fight-integrity-validator.d.ts +13 -0
- package/dist/src/review/fight-integrity-validator.js +134 -0
- package/dist/src/review/fight-integrity-validator.js.map +1 -0
- package/dist/src/review/fun-candidate-generator.d.ts +9 -0
- package/dist/src/review/fun-candidate-generator.js +267 -0
- package/dist/src/review/fun-candidate-generator.js.map +1 -0
- package/dist/src/review/fun-event-generator.d.ts +8 -0
- package/dist/src/review/fun-event-generator.js +740 -0
- package/dist/src/review/fun-event-generator.js.map +1 -0
- package/dist/src/review/fun-intelligence.d.ts +13 -0
- package/dist/src/review/fun-intelligence.js +20 -0
- package/dist/src/review/fun-intelligence.js.map +1 -0
- package/dist/src/review/fun-ranker.d.ts +13 -0
- package/dist/src/review/fun-ranker.js +68 -0
- package/dist/src/review/fun-ranker.js.map +1 -0
- package/dist/src/review/heavy-weapon-intelligence.d.ts +5 -0
- package/dist/src/review/heavy-weapon-intelligence.js +215 -0
- package/dist/src/review/heavy-weapon-intelligence.js.map +1 -0
- package/dist/src/review/key-operation-detector.d.ts +3 -0
- package/dist/src/review/key-operation-detector.js +126 -0
- package/dist/src/review/key-operation-detector.js.map +1 -0
- package/dist/src/review/match-selector.d.ts +18 -0
- package/dist/src/review/match-selector.js +202 -0
- package/dist/src/review/match-selector.js.map +1 -0
- package/dist/src/review/review-analyzer.d.ts +2 -0
- package/dist/src/review/review-analyzer.js +652 -0
- package/dist/src/review/review-analyzer.js.map +1 -0
- package/dist/src/review/review-facts.d.ts +17 -0
- package/dist/src/review/review-facts.js +560 -0
- package/dist/src/review/review-facts.js.map +1 -0
- package/dist/src/review/review-share.d.ts +48 -0
- package/dist/src/review/review-share.js +37 -0
- package/dist/src/review/review-share.js.map +1 -0
- package/dist/src/review/selection-store.d.ts +25 -0
- package/dist/src/review/selection-store.js +80 -0
- package/dist/src/review/selection-store.js.map +1 -0
- package/dist/src/review/session-review.d.ts +72 -0
- package/dist/src/review/session-review.js +492 -0
- package/dist/src/review/session-review.js.map +1 -0
- package/dist/src/review/special-events.d.ts +3 -0
- package/dist/src/review/special-events.js +258 -0
- package/dist/src/review/special-events.js.map +1 -0
- package/dist/src/review/subgraph.d.ts +26 -0
- package/dist/src/review/subgraph.js +146 -0
- package/dist/src/review/subgraph.js.map +1 -0
- package/dist/src/review/supplemental-intelligence.d.ts +15 -0
- package/dist/src/review/supplemental-intelligence.js +431 -0
- package/dist/src/review/supplemental-intelligence.js.map +1 -0
- package/dist/src/review/team-damage.d.ts +8 -0
- package/dist/src/review/team-damage.js +180 -0
- package/dist/src/review/team-damage.js.map +1 -0
- package/dist/src/review/telemetry-events.d.ts +72 -0
- package/dist/src/review/telemetry-events.js +573 -0
- package/dist/src/review/telemetry-events.js.map +1 -0
- package/dist/src/review/telemetry.d.ts +86 -0
- package/dist/src/review/telemetry.js +266 -0
- package/dist/src/review/telemetry.js.map +1 -0
- package/dist/src/review/types.d.ts +501 -0
- package/dist/src/review/types.js +2 -0
- package/dist/src/review/types.js.map +1 -0
- package/dist/src/review/vehicle-intelligence.d.ts +3 -0
- package/dist/src/review/vehicle-intelligence.js +148 -0
- package/dist/src/review/vehicle-intelligence.js.map +1 -0
- package/dist/src/schema/query.d.ts +876 -0
- package/dist/src/schema/query.js +185 -0
- package/dist/src/schema/query.js.map +1 -0
- package/dist/src/schema/status.d.ts +66 -0
- package/dist/src/schema/status.js +49 -0
- package/dist/src/schema/status.js.map +1 -0
- package/dist/src/service/pubg-domain-service.d.ts +192 -0
- package/dist/src/service/pubg-domain-service.js +1598 -0
- package/dist/src/service/pubg-domain-service.js.map +1 -0
- package/dist/src/storage/repository-port.d.ts +84 -0
- package/dist/src/storage/repository-port.js +2 -0
- package/dist/src/storage/repository-port.js.map +1 -0
- package/dist/src/storage/sqlite-repository-adapter.d.ts +33 -0
- package/dist/src/storage/sqlite-repository-adapter.js +66 -0
- package/dist/src/storage/sqlite-repository-adapter.js.map +1 -0
- package/dist/src/storage/sqlite-repository.d.ts +73 -0
- package/dist/src/storage/sqlite-repository.js +652 -0
- package/dist/src/storage/sqlite-repository.js.map +1 -0
- package/dist/src/time/selector-resolver.d.ts +34 -0
- package/dist/src/time/selector-resolver.js +364 -0
- package/dist/src/time/selector-resolver.js.map +1 -0
- package/package.json +42 -3
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
import type { NormalizedMatch, QueryRow, StructuredResult } from '../data/model.js';
|
|
2
|
+
import type { MatchRankMetric } from '../schema/query.js';
|
|
3
|
+
import type { NormalizedTelemetryEvent, TelemetryEventPhase } from './telemetry-events.js';
|
|
4
|
+
export type ReviewFactKind = 'FACT' | 'DERIVED' | 'ANALYSIS' | 'FUN';
|
|
5
|
+
export interface ReviewEvidence {
|
|
6
|
+
id: string;
|
|
7
|
+
kind: ReviewFactKind;
|
|
8
|
+
source: 'match_store' | 'telemetry';
|
|
9
|
+
eventIds: string[];
|
|
10
|
+
description: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ReviewMatchSummary {
|
|
13
|
+
matchId: string;
|
|
14
|
+
ordinal: number;
|
|
15
|
+
startedAt: string | null;
|
|
16
|
+
mapName: string;
|
|
17
|
+
gameMode: string;
|
|
18
|
+
duration: number;
|
|
19
|
+
placement: number | null;
|
|
20
|
+
patchVersion: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ReviewSquadSummary {
|
|
23
|
+
playerIds: string[];
|
|
24
|
+
kills: number;
|
|
25
|
+
assists: number;
|
|
26
|
+
damage: number;
|
|
27
|
+
knocks: number;
|
|
28
|
+
revives: number;
|
|
29
|
+
placement: number | null;
|
|
30
|
+
}
|
|
31
|
+
export interface VehicleStats {
|
|
32
|
+
/** Stable fact ID; optional for compatibility with pre-V3.3 cached facts. */
|
|
33
|
+
id?: string;
|
|
34
|
+
playerId: string;
|
|
35
|
+
rideDistance: number;
|
|
36
|
+
driveDistance: number;
|
|
37
|
+
maxSpeed: number;
|
|
38
|
+
vehicleDamage: number;
|
|
39
|
+
vehiclesDestroyed: number;
|
|
40
|
+
driver: boolean;
|
|
41
|
+
passenger: boolean;
|
|
42
|
+
driverConfirmed: boolean;
|
|
43
|
+
passengerConfirmed: boolean;
|
|
44
|
+
evidenceIds: string[];
|
|
45
|
+
}
|
|
46
|
+
export interface HeavyWeaponStats {
|
|
47
|
+
playerId: string;
|
|
48
|
+
weapon: string;
|
|
49
|
+
pickupEvents: number;
|
|
50
|
+
dropEvents: number;
|
|
51
|
+
shots: number;
|
|
52
|
+
hits: number;
|
|
53
|
+
playerDamage: number;
|
|
54
|
+
vehicleDamage: number;
|
|
55
|
+
knocks: number;
|
|
56
|
+
kills: number;
|
|
57
|
+
vehiclesDestroyed: number;
|
|
58
|
+
evidenceIds: string[];
|
|
59
|
+
}
|
|
60
|
+
export interface StunGunStats {
|
|
61
|
+
id: string;
|
|
62
|
+
playerId: string;
|
|
63
|
+
pickups: number;
|
|
64
|
+
shots: number;
|
|
65
|
+
confirmedHits: number;
|
|
66
|
+
teammateHits: number;
|
|
67
|
+
enemyHits: number;
|
|
68
|
+
unknownOutcomes: number;
|
|
69
|
+
evidenceIds: string[];
|
|
70
|
+
}
|
|
71
|
+
export interface RecoveryStats {
|
|
72
|
+
id: string;
|
|
73
|
+
playerId: string;
|
|
74
|
+
bandages: number;
|
|
75
|
+
firstAids: number;
|
|
76
|
+
medKits: number;
|
|
77
|
+
adrenaline: number;
|
|
78
|
+
energyDrinks: number;
|
|
79
|
+
painkillers: number;
|
|
80
|
+
otherUses: number;
|
|
81
|
+
/** Raw heal ticks are retained for diagnostics, not rendered as item uses. */
|
|
82
|
+
healingAmount: number;
|
|
83
|
+
evidenceIds: string[];
|
|
84
|
+
}
|
|
85
|
+
export interface LootStats {
|
|
86
|
+
id: string;
|
|
87
|
+
playerId: string;
|
|
88
|
+
lootBoxPickups: number;
|
|
89
|
+
weapons: number;
|
|
90
|
+
throwables: number;
|
|
91
|
+
ammunition: number;
|
|
92
|
+
healing: number;
|
|
93
|
+
boosts: number;
|
|
94
|
+
armor: number;
|
|
95
|
+
attachments: number;
|
|
96
|
+
notableItems: string[];
|
|
97
|
+
evidenceIds: string[];
|
|
98
|
+
}
|
|
99
|
+
/** Item movement is separate from death-box loot so raw pickup counts stay readable. */
|
|
100
|
+
export interface LootActivityStats {
|
|
101
|
+
id: string;
|
|
102
|
+
playerId: string;
|
|
103
|
+
pickupEvents: number;
|
|
104
|
+
dropEvents: number;
|
|
105
|
+
lootBoxPickups: number;
|
|
106
|
+
pickupWeapons: number;
|
|
107
|
+
pickupThrowables: number;
|
|
108
|
+
pickupAmmunition: number;
|
|
109
|
+
pickupHealing: number;
|
|
110
|
+
pickupBoosts: number;
|
|
111
|
+
pickupArmor: number;
|
|
112
|
+
pickupAttachments: number;
|
|
113
|
+
dropWeapons: number;
|
|
114
|
+
dropThrowables: number;
|
|
115
|
+
dropAmmunition: number;
|
|
116
|
+
dropHealing: number;
|
|
117
|
+
dropBoosts: number;
|
|
118
|
+
dropArmor: number;
|
|
119
|
+
dropAttachments: number;
|
|
120
|
+
/** Only explicit item-event metadata counts; settlement skin IDs are ignored. */
|
|
121
|
+
cosmeticPickups: number;
|
|
122
|
+
clothingPickups: number;
|
|
123
|
+
notableItems: string[];
|
|
124
|
+
evidenceIds: string[];
|
|
125
|
+
}
|
|
126
|
+
export type VehicleTrunkDirection = 'PUT' | 'PICKUP';
|
|
127
|
+
export interface VehicleTrunkTransfer {
|
|
128
|
+
id: string;
|
|
129
|
+
direction: VehicleTrunkDirection;
|
|
130
|
+
playerId: string;
|
|
131
|
+
item: string;
|
|
132
|
+
itemCategory?: string;
|
|
133
|
+
itemSubCategory?: string;
|
|
134
|
+
vehicleId: string | null;
|
|
135
|
+
vehicleType: string | null;
|
|
136
|
+
stackCount: number | null;
|
|
137
|
+
time: number | null;
|
|
138
|
+
evidenceIds: string[];
|
|
139
|
+
}
|
|
140
|
+
export interface EnvironmentStats {
|
|
141
|
+
id: string;
|
|
142
|
+
playerId: string;
|
|
143
|
+
doorOpens: number;
|
|
144
|
+
doorCloses: number;
|
|
145
|
+
windowsDestroyed: number;
|
|
146
|
+
fencesDestroyed: number;
|
|
147
|
+
vaults: number;
|
|
148
|
+
ledgeGrabs: number;
|
|
149
|
+
vaultsOnVehicle: number;
|
|
150
|
+
/** Raw object names are retained instead of guessing a destruction cause. */
|
|
151
|
+
destroyedObjects?: Array<{
|
|
152
|
+
objectType: string;
|
|
153
|
+
count: number;
|
|
154
|
+
}>;
|
|
155
|
+
/** Counted only when the telemetry explicitly names a terrain/dig action. */
|
|
156
|
+
terrainActions?: number;
|
|
157
|
+
eventTimes: number[];
|
|
158
|
+
evidenceIds: string[];
|
|
159
|
+
}
|
|
160
|
+
export type ArmorBreakFollowUp = 'KNOCK' | 'KILL' | null;
|
|
161
|
+
export interface ArmorBreakFact {
|
|
162
|
+
id: string;
|
|
163
|
+
actorPlayerId: string;
|
|
164
|
+
victimPlayerId: string | null;
|
|
165
|
+
armorItem: string | null;
|
|
166
|
+
armorSlot: string | null;
|
|
167
|
+
weapon: string | null;
|
|
168
|
+
damageReason: string | null;
|
|
169
|
+
distanceMeters: number | null;
|
|
170
|
+
attackId: string | null;
|
|
171
|
+
time: number | null;
|
|
172
|
+
followUp: ArmorBreakFollowUp;
|
|
173
|
+
evidenceIds: string[];
|
|
174
|
+
}
|
|
175
|
+
export interface VehicleImpactFact {
|
|
176
|
+
id: string;
|
|
177
|
+
playerId: string;
|
|
178
|
+
attackId: string;
|
|
179
|
+
vehicleId: string | null;
|
|
180
|
+
vehicleType: string | null;
|
|
181
|
+
wheelsDestroyed: number;
|
|
182
|
+
vehicleDamage: number;
|
|
183
|
+
playerDamage: number;
|
|
184
|
+
knocks: number;
|
|
185
|
+
kills: number;
|
|
186
|
+
vehicleDestroyed: number;
|
|
187
|
+
time: number | null;
|
|
188
|
+
evidenceIds: string[];
|
|
189
|
+
}
|
|
190
|
+
export type TeamDamageSource = 'MELEE' | 'GUN' | 'VEHICLE' | 'EXPLOSIVE';
|
|
191
|
+
export interface TeamDamageFact {
|
|
192
|
+
id: string;
|
|
193
|
+
actorPlayerId: string;
|
|
194
|
+
victimPlayerId: string;
|
|
195
|
+
hitCount: number;
|
|
196
|
+
damage: number;
|
|
197
|
+
source: TeamDamageSource;
|
|
198
|
+
timestamp: number | null;
|
|
199
|
+
timestamps: number[];
|
|
200
|
+
weapon?: string;
|
|
201
|
+
damageTypeCategory?: string;
|
|
202
|
+
/** Explicit melee action classification; absent on pre-V3.4 cached facts. */
|
|
203
|
+
meleeKind?: 'PUNCH' | 'KICK' | 'OTHER';
|
|
204
|
+
vehicleId?: string;
|
|
205
|
+
/** Reliable phase is kept separate so pre-match friendly fire is not mixed with in-match facts. */
|
|
206
|
+
phase?: TelemetryEventPhase;
|
|
207
|
+
evidenceIds: string[];
|
|
208
|
+
}
|
|
209
|
+
export type TeamVehicleEventType = 'HIT' | 'KNOCK' | 'KILL';
|
|
210
|
+
export interface TeamVehicleEvent {
|
|
211
|
+
id: string;
|
|
212
|
+
type: TeamVehicleEventType;
|
|
213
|
+
actorPlayerId: string;
|
|
214
|
+
victimPlayerId: string;
|
|
215
|
+
damage: number;
|
|
216
|
+
timestamp: number | null;
|
|
217
|
+
vehicleId: string | null;
|
|
218
|
+
driverConfirmed: boolean;
|
|
219
|
+
phase?: TelemetryEventPhase;
|
|
220
|
+
evidenceIds: string[];
|
|
221
|
+
}
|
|
222
|
+
export interface FlashStats {
|
|
223
|
+
/** Stable fact ID; optional for compatibility with pre-V3.3 cached facts. */
|
|
224
|
+
id?: string;
|
|
225
|
+
playerId: string;
|
|
226
|
+
uses: number;
|
|
227
|
+
evidenceIds: string[];
|
|
228
|
+
}
|
|
229
|
+
export interface WeaponStats {
|
|
230
|
+
playerId: string;
|
|
231
|
+
weapon: string;
|
|
232
|
+
shots: number;
|
|
233
|
+
hits: number;
|
|
234
|
+
damage: number;
|
|
235
|
+
knocks: number;
|
|
236
|
+
kills: number;
|
|
237
|
+
evidenceIds: string[];
|
|
238
|
+
}
|
|
239
|
+
export type FightResult = 'WIN' | 'LOSS' | 'TRADE' | 'UNKNOWN';
|
|
240
|
+
export interface Fight {
|
|
241
|
+
id: string;
|
|
242
|
+
start: number;
|
|
243
|
+
end: number;
|
|
244
|
+
participants: string[];
|
|
245
|
+
damage: number;
|
|
246
|
+
knocks: number;
|
|
247
|
+
kills: number;
|
|
248
|
+
revives: number;
|
|
249
|
+
teamDamage: number;
|
|
250
|
+
teamKnocks: number;
|
|
251
|
+
teamKills: number;
|
|
252
|
+
teamRevives: number;
|
|
253
|
+
receivedDamage: number;
|
|
254
|
+
receivedKnocks: number;
|
|
255
|
+
receivedKills: number;
|
|
256
|
+
receivedRevives: number;
|
|
257
|
+
opponentTeamIds: string[];
|
|
258
|
+
eventCount: number;
|
|
259
|
+
result: FightResult;
|
|
260
|
+
importanceScore: number;
|
|
261
|
+
keyPlayers: string[];
|
|
262
|
+
location?: string;
|
|
263
|
+
evidenceIds: string[];
|
|
264
|
+
}
|
|
265
|
+
export type KeyOperationType = 'ENTRY' | 'MULTI_KNOCK' | 'CLUTCH' | 'FLANK' | 'TRADE' | 'SUPPORT' | 'REVIVE' | 'DAMAGE' | 'POSITIONING_RISK' | 'MISTAKE' | 'VEHICLE' | 'HEAVY_WEAPON';
|
|
266
|
+
export interface KeyOperation {
|
|
267
|
+
id: string;
|
|
268
|
+
playerId: string;
|
|
269
|
+
time: number | null;
|
|
270
|
+
type: KeyOperationType;
|
|
271
|
+
impact: string;
|
|
272
|
+
impactScore: number;
|
|
273
|
+
facts: Record<string, number | string | boolean | null>;
|
|
274
|
+
evidenceIds: string[];
|
|
275
|
+
}
|
|
276
|
+
export interface ReviewPlayerFacts {
|
|
277
|
+
playerId: string;
|
|
278
|
+
playerName: string;
|
|
279
|
+
/** Match Store may omit a configured player from a match row. Missing is not zero contribution. */
|
|
280
|
+
matchPresence?: 'recorded' | 'not_recorded';
|
|
281
|
+
rank: number | null;
|
|
282
|
+
kills: number;
|
|
283
|
+
assists: number;
|
|
284
|
+
damage: number;
|
|
285
|
+
dbnos: number;
|
|
286
|
+
revives: number;
|
|
287
|
+
matchRole?: string;
|
|
288
|
+
roleConfidence: 'high' | 'medium' | 'low' | 'none';
|
|
289
|
+
keyOperations: KeyOperation[];
|
|
290
|
+
vehicle?: VehicleStats;
|
|
291
|
+
heavyWeapons: HeavyWeaponStats[];
|
|
292
|
+
}
|
|
293
|
+
export interface MatchReviewFacts {
|
|
294
|
+
schemaVersion: 1;
|
|
295
|
+
match: ReviewMatchSummary;
|
|
296
|
+
squad: ReviewSquadSummary;
|
|
297
|
+
players: ReviewPlayerFacts[];
|
|
298
|
+
combat: {
|
|
299
|
+
eventCount: number;
|
|
300
|
+
damage: number;
|
|
301
|
+
knocks: number;
|
|
302
|
+
kills: number;
|
|
303
|
+
revives: number;
|
|
304
|
+
opponentDamage: number;
|
|
305
|
+
opponentKnocks: number;
|
|
306
|
+
opponentKills: number;
|
|
307
|
+
opponentRevives: number;
|
|
308
|
+
events: NormalizedTelemetryEvent[];
|
|
309
|
+
};
|
|
310
|
+
fights: Fight[];
|
|
311
|
+
fightIntegrity: FightIntegrityResult;
|
|
312
|
+
weapons: WeaponStats[];
|
|
313
|
+
vehicles: VehicleStats[];
|
|
314
|
+
heavyWeapons: HeavyWeaponStats[];
|
|
315
|
+
specialEvents: SpecialEvent[];
|
|
316
|
+
evidence: ReviewEvidence[];
|
|
317
|
+
/** Derived friendly-fire facts; absent only in pre-V3.3 cached records. */
|
|
318
|
+
teamDamage?: TeamDamageFact[];
|
|
319
|
+
/** Vehicle collision facts retain driver certainty separately. */
|
|
320
|
+
teamVehicleEvents?: TeamVehicleEvent[];
|
|
321
|
+
/** Flash use is countable; flash victims are intentionally not inferred. */
|
|
322
|
+
flash?: FlashStats[];
|
|
323
|
+
/** Supplemental telemetry facts used by the v1 report template. */
|
|
324
|
+
stunGuns?: StunGunStats[];
|
|
325
|
+
recovery?: RecoveryStats[];
|
|
326
|
+
loot?: LootStats[];
|
|
327
|
+
lootActivity?: LootActivityStats[];
|
|
328
|
+
vehicleTrunk?: VehicleTrunkTransfer[];
|
|
329
|
+
environment?: EnvironmentStats[];
|
|
330
|
+
armorBreaks?: ArmorBreakFact[];
|
|
331
|
+
vehicleImpacts?: VehicleImpactFact[];
|
|
332
|
+
}
|
|
333
|
+
export type SpecialEventType = 'MULTI_KNOCK' | 'CLUTCH' | 'REVIVE_CHAIN' | 'ROCKET_UNUSED' | 'ROCKET_MISS' | 'ROCKET_HIT' | 'ROCKET_VEHICLE_DESTROY' | 'ROCKET_MULTI_KILL' | 'ROCKET_VEHICLE_MULTI_KILL' | 'ROCKET_ALL_MISS' | 'VEHICLE_LONG_DRIVE' | 'VEHICLE_DESTROY' | 'VEHICLE_KILL';
|
|
334
|
+
export interface SpecialEvent {
|
|
335
|
+
id: string;
|
|
336
|
+
type: SpecialEventType;
|
|
337
|
+
playerId?: string;
|
|
338
|
+
time: number | null;
|
|
339
|
+
impact: string;
|
|
340
|
+
impactScore: number;
|
|
341
|
+
facts: Record<string, number | string | boolean | null>;
|
|
342
|
+
evidenceIds: string[];
|
|
343
|
+
}
|
|
344
|
+
export interface PlayerCommentary {
|
|
345
|
+
playerId: string;
|
|
346
|
+
role?: string;
|
|
347
|
+
roleConfidence: 'high' | 'medium' | 'low' | 'none';
|
|
348
|
+
text: string;
|
|
349
|
+
strengths: string[];
|
|
350
|
+
improvements: string[];
|
|
351
|
+
operationIds: string[];
|
|
352
|
+
}
|
|
353
|
+
export interface ReviewAward {
|
|
354
|
+
playerId: string;
|
|
355
|
+
title: string;
|
|
356
|
+
text: string;
|
|
357
|
+
evidenceIds: string[];
|
|
358
|
+
}
|
|
359
|
+
export type ReviewTurningPointType = 'POWER_SPIKE' | 'CLEAN_WIN' | 'FINAL_LOSS' | 'TEAMWORK_RISK';
|
|
360
|
+
export interface ReviewTurningPoint {
|
|
361
|
+
id: string;
|
|
362
|
+
type: ReviewTurningPointType;
|
|
363
|
+
time: number | null;
|
|
364
|
+
title: string;
|
|
365
|
+
text: string;
|
|
366
|
+
impact: 'positive' | 'negative' | 'neutral';
|
|
367
|
+
facts: Record<string, number | string | boolean | null>;
|
|
368
|
+
evidenceIds: string[];
|
|
369
|
+
}
|
|
370
|
+
export interface ReviewAnalysis {
|
|
371
|
+
summary: string;
|
|
372
|
+
teamStory?: string;
|
|
373
|
+
turningPoints?: ReviewTurningPoint[];
|
|
374
|
+
actionPlan?: string[];
|
|
375
|
+
playerCommentary: PlayerCommentary[];
|
|
376
|
+
keyFights: Fight[];
|
|
377
|
+
good: string[];
|
|
378
|
+
improvements: string[];
|
|
379
|
+
keyPlayers: string[];
|
|
380
|
+
awards?: ReviewAward[];
|
|
381
|
+
fun: string[];
|
|
382
|
+
funCandidates?: FunCandidate[];
|
|
383
|
+
funEvents?: FunEvent[];
|
|
384
|
+
}
|
|
385
|
+
export type FunCandidateType = 'ROCKET_UNUSED' | 'ROCKET_MISS' | 'ROCKET_MULTI_KILL' | 'ROCKET_VEHICLE_MULTI_KILL' | 'TOP_DRIVER' | 'TOP_PASSENGER' | 'LONGEST_RIDE' | 'MOST_REVIVES' | 'MOST_ASSISTS' | 'HIGH_KNOCK_LOW_CONVERSION' | 'NO_COMBAT_PRESENCE' | 'HIGH_DAMAGE' | 'LOW_DAMAGE' | 'SPECIAL_EVENT';
|
|
386
|
+
export interface FunCandidate {
|
|
387
|
+
id: string;
|
|
388
|
+
type: FunCandidateType;
|
|
389
|
+
playerId?: string;
|
|
390
|
+
title: string;
|
|
391
|
+
text: string;
|
|
392
|
+
impactScore: number;
|
|
393
|
+
facts: Record<string, number | string | boolean | null>;
|
|
394
|
+
evidenceIds: string[];
|
|
395
|
+
}
|
|
396
|
+
export type FunConfidence = 'CONFIRMED' | 'DERIVED' | 'HEURISTIC';
|
|
397
|
+
/** Structured, evidence-backed fun output. Rendering must not derive facts from text. */
|
|
398
|
+
export interface FunEvent {
|
|
399
|
+
id: string;
|
|
400
|
+
type: string;
|
|
401
|
+
actorPlayerId?: string;
|
|
402
|
+
targetPlayerIds: string[];
|
|
403
|
+
factIds: string[];
|
|
404
|
+
evidenceIds: string[];
|
|
405
|
+
confidence: FunConfidence;
|
|
406
|
+
funScore: number;
|
|
407
|
+
category: string;
|
|
408
|
+
title: string;
|
|
409
|
+
text: string;
|
|
410
|
+
facts: Record<string, number | string | boolean | null>;
|
|
411
|
+
tags: string[];
|
|
412
|
+
dedupGroup?: string;
|
|
413
|
+
suppresses?: string[];
|
|
414
|
+
}
|
|
415
|
+
export interface MatchReviewResult {
|
|
416
|
+
schemaVersion: 1;
|
|
417
|
+
match: ReviewMatchSummary;
|
|
418
|
+
facts: MatchReviewFacts;
|
|
419
|
+
analysis: ReviewAnalysis;
|
|
420
|
+
telemetry: {
|
|
421
|
+
status: 'HIT' | 'FETCHED' | 'UNAVAILABLE';
|
|
422
|
+
cacheStatus: 'HIT' | 'FETCHED' | 'UNAVAILABLE';
|
|
423
|
+
cacheLookup: 'HIT' | 'MISS';
|
|
424
|
+
availability: 'AVAILABLE' | 'UNAVAILABLE';
|
|
425
|
+
parserVersion: string;
|
|
426
|
+
featureVersion: string;
|
|
427
|
+
error?: string;
|
|
428
|
+
};
|
|
429
|
+
sourceMatchResultSetId?: string | null;
|
|
430
|
+
activeReviewResultSetId?: string | null;
|
|
431
|
+
}
|
|
432
|
+
export interface FightIntegrityFightDiagnostic {
|
|
433
|
+
id: string;
|
|
434
|
+
duration: number;
|
|
435
|
+
opponentTeamIds: string[];
|
|
436
|
+
eventCount: number;
|
|
437
|
+
teamKills: number;
|
|
438
|
+
teamKnocks: number;
|
|
439
|
+
teamDamage: number;
|
|
440
|
+
receivedDamage: number;
|
|
441
|
+
integrityPass: boolean;
|
|
442
|
+
}
|
|
443
|
+
export interface FightIntegrityDiagnostics {
|
|
444
|
+
matchTeamKills: number;
|
|
445
|
+
matchTeamDamage: number;
|
|
446
|
+
matchTeamDBNOs: number;
|
|
447
|
+
candidateCombatEvents: number;
|
|
448
|
+
trackedRelevantEvents: number;
|
|
449
|
+
ignoredGlobalEvents: number;
|
|
450
|
+
fightCount: number;
|
|
451
|
+
damageTolerance: number;
|
|
452
|
+
fights: FightIntegrityFightDiagnostic[];
|
|
453
|
+
}
|
|
454
|
+
export interface FightIntegrityResult {
|
|
455
|
+
pass: boolean;
|
|
456
|
+
/** Explicit status lets renderers and traces distinguish invalid analytics from missing telemetry. */
|
|
457
|
+
status: 'FIGHT_ANALYTICS_VALID' | 'FIGHT_ANALYTICS_INVALID';
|
|
458
|
+
diagnostics: FightIntegrityDiagnostics;
|
|
459
|
+
errors: string[];
|
|
460
|
+
}
|
|
461
|
+
export interface MatchPickerCandidate {
|
|
462
|
+
ordinal: number;
|
|
463
|
+
match: NormalizedMatch;
|
|
464
|
+
row: QueryRow;
|
|
465
|
+
}
|
|
466
|
+
export interface MatchPickerButton {
|
|
467
|
+
text: string;
|
|
468
|
+
callbackData: string;
|
|
469
|
+
ordinal: number;
|
|
470
|
+
}
|
|
471
|
+
export interface MatchPickerModel {
|
|
472
|
+
selectorLabel: string;
|
|
473
|
+
candidateCount: number;
|
|
474
|
+
candidates: MatchPickerCandidate[];
|
|
475
|
+
buttons: MatchPickerButton[];
|
|
476
|
+
}
|
|
477
|
+
export interface MatchSelectionRecord {
|
|
478
|
+
token: string;
|
|
479
|
+
platform: string;
|
|
480
|
+
chatId: string;
|
|
481
|
+
sessionId: string;
|
|
482
|
+
matchId: string;
|
|
483
|
+
resultSetId: string;
|
|
484
|
+
ordinal: number;
|
|
485
|
+
createdAt: string;
|
|
486
|
+
expiresAt: string;
|
|
487
|
+
query: import('../schema/query.js').CanonicalQuery;
|
|
488
|
+
}
|
|
489
|
+
export interface MatchSelectionRequest {
|
|
490
|
+
platform: string;
|
|
491
|
+
chatId: string;
|
|
492
|
+
now?: Date;
|
|
493
|
+
}
|
|
494
|
+
export interface ReviewExecution {
|
|
495
|
+
result: StructuredResult;
|
|
496
|
+
candidates: MatchPickerCandidate[];
|
|
497
|
+
selected: MatchPickerCandidate | null;
|
|
498
|
+
matchSelector: import('../schema/query.js').MatchSelector | null;
|
|
499
|
+
sourceMatchResultSetId: string | null;
|
|
500
|
+
rankedMetric?: MatchRankMetric;
|
|
501
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/review/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
function addDistance(previous, current) {
|
|
2
|
+
const location = current.location;
|
|
3
|
+
if (!previous || !location || location.x === null || location.y === null)
|
|
4
|
+
return 0;
|
|
5
|
+
const z = location.z ?? previous.z;
|
|
6
|
+
// PUBG position coordinates are centimetres; explicit rideDistance wins.
|
|
7
|
+
return Math.hypot(location.x - previous.x, location.y - previous.y, z - previous.z) / 100;
|
|
8
|
+
}
|
|
9
|
+
function excludedVehicle(event) {
|
|
10
|
+
const value = `${event.vehicleType ?? ''} ${event.vehicleId ?? ''}`.toLowerCase();
|
|
11
|
+
return /aircraft|transportaircraft|parachute|plane/u.test(value);
|
|
12
|
+
}
|
|
13
|
+
function hasVehicle(event) {
|
|
14
|
+
return Boolean(event.vehicleId || event.vehicleType) && !excludedVehicle(event);
|
|
15
|
+
}
|
|
16
|
+
function vehicleKey(event) {
|
|
17
|
+
// A type-only fallback keeps old/synthetic telemetry usable without
|
|
18
|
+
// pretending that a vehicle model is a globally unique vehicle ID.
|
|
19
|
+
return event.vehicleId ?? (event.vehicleType ? `type:${event.vehicleType}` : null);
|
|
20
|
+
}
|
|
21
|
+
export function extractVehicleStats(events, teamIds) {
|
|
22
|
+
const stats = new Map();
|
|
23
|
+
const segments = new Map();
|
|
24
|
+
const get = (playerId) => {
|
|
25
|
+
const existing = stats.get(playerId);
|
|
26
|
+
if (existing)
|
|
27
|
+
return existing;
|
|
28
|
+
const created = {
|
|
29
|
+
playerId,
|
|
30
|
+
id: `vehicle-${playerId}`,
|
|
31
|
+
rideDistance: 0,
|
|
32
|
+
driveDistance: 0,
|
|
33
|
+
maxSpeed: 0,
|
|
34
|
+
vehicleDamage: 0,
|
|
35
|
+
vehiclesDestroyed: 0,
|
|
36
|
+
driver: false,
|
|
37
|
+
passenger: false,
|
|
38
|
+
driverConfirmed: false,
|
|
39
|
+
passengerConfirmed: false,
|
|
40
|
+
evidenceIds: [],
|
|
41
|
+
};
|
|
42
|
+
stats.set(playerId, created);
|
|
43
|
+
return created;
|
|
44
|
+
};
|
|
45
|
+
const segmentFor = (event) => {
|
|
46
|
+
if (!event.actorId)
|
|
47
|
+
return null;
|
|
48
|
+
const id = vehicleKey(event);
|
|
49
|
+
if (!id)
|
|
50
|
+
return null;
|
|
51
|
+
const key = `${event.actorId}:${id}`;
|
|
52
|
+
const segment = segments.get(key) ?? {
|
|
53
|
+
positionDistance: 0,
|
|
54
|
+
explicitDistance: null,
|
|
55
|
+
driverConfirmed: false,
|
|
56
|
+
};
|
|
57
|
+
segments.set(key, segment);
|
|
58
|
+
return segment;
|
|
59
|
+
};
|
|
60
|
+
const finalizeSegment = (playerId, vehicleKeyValue, event) => {
|
|
61
|
+
const key = `${playerId}:${vehicleKeyValue}`;
|
|
62
|
+
const segment = segments.get(key);
|
|
63
|
+
if (!segment)
|
|
64
|
+
return;
|
|
65
|
+
const current = get(playerId);
|
|
66
|
+
const distance = segment.explicitDistance ?? segment.positionDistance;
|
|
67
|
+
current.rideDistance += distance;
|
|
68
|
+
if (segment.driverConfirmed)
|
|
69
|
+
current.driveDistance += distance;
|
|
70
|
+
if (event?.speed !== null && event?.speed !== undefined)
|
|
71
|
+
current.maxSpeed = Math.max(current.maxSpeed, event.speed);
|
|
72
|
+
segments.delete(key);
|
|
73
|
+
};
|
|
74
|
+
for (const event of events) {
|
|
75
|
+
const actorId = event.actorId;
|
|
76
|
+
if (!actorId || !teamIds.has(actorId))
|
|
77
|
+
continue;
|
|
78
|
+
if (!['VEHICLE_RIDE', 'VEHICLE_LEAVE', 'VEHICLE_DAMAGE', 'VEHICLE_DESTROY', 'POSITION'].includes(event.type))
|
|
79
|
+
continue;
|
|
80
|
+
if (!hasVehicle(event))
|
|
81
|
+
continue;
|
|
82
|
+
const current = get(actorId);
|
|
83
|
+
current.evidenceIds.push(event.id);
|
|
84
|
+
if (event.speed !== null)
|
|
85
|
+
current.maxSpeed = Math.max(current.maxSpeed, event.speed);
|
|
86
|
+
if (event.driverConfirmed === true) {
|
|
87
|
+
current.driverConfirmed = true;
|
|
88
|
+
current.driver = true;
|
|
89
|
+
// A source may confirm the driver on a collision/destroy record rather
|
|
90
|
+
// than on the ride record. Propagate that fact to the open segment for
|
|
91
|
+
// the same vehicle without inferring anything from seatIndex.
|
|
92
|
+
const roleSegment = segmentFor(event);
|
|
93
|
+
if (roleSegment)
|
|
94
|
+
roleSegment.driverConfirmed = true;
|
|
95
|
+
}
|
|
96
|
+
if (event.passengerConfirmed === true) {
|
|
97
|
+
current.passengerConfirmed = true;
|
|
98
|
+
current.passenger = true;
|
|
99
|
+
}
|
|
100
|
+
if (event.type === 'VEHICLE_RIDE') {
|
|
101
|
+
const segment = segmentFor(event);
|
|
102
|
+
if (segment && event.distanceMeters !== null && event.distanceMeters > 0)
|
|
103
|
+
segment.explicitDistance = event.distanceMeters;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (event.type === 'VEHICLE_LEAVE') {
|
|
107
|
+
const segment = segmentFor(event);
|
|
108
|
+
if (segment && event.distanceMeters !== null && event.distanceMeters > 0)
|
|
109
|
+
segment.explicitDistance = event.distanceMeters;
|
|
110
|
+
const id = vehicleKey(event);
|
|
111
|
+
if (id)
|
|
112
|
+
finalizeSegment(actorId, id, event);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (event.type === 'VEHICLE_DAMAGE') {
|
|
116
|
+
current.vehicleDamage += event.vehicleDamage || event.damage;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (event.type === 'VEHICLE_DESTROY') {
|
|
120
|
+
current.vehiclesDestroyed += 1;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const segment = segmentFor(event);
|
|
124
|
+
if (!segment || !event.location || event.location.x === null || event.location.y === null)
|
|
125
|
+
continue;
|
|
126
|
+
const point = { x: event.location.x, y: event.location.y, z: event.location.z ?? 0 };
|
|
127
|
+
segment.positionDistance += addDistance(segment.lastPoint, event);
|
|
128
|
+
segment.lastPoint = point;
|
|
129
|
+
}
|
|
130
|
+
for (const key of segments.keys()) {
|
|
131
|
+
const separator = key.indexOf(':');
|
|
132
|
+
if (separator < 0)
|
|
133
|
+
continue;
|
|
134
|
+
finalizeSegment(key.slice(0, separator), key.slice(separator + 1));
|
|
135
|
+
}
|
|
136
|
+
return [...stats.values()]
|
|
137
|
+
.map((item) => ({
|
|
138
|
+
...item,
|
|
139
|
+
// Seat index is retained in normalized events, but is not treated as a
|
|
140
|
+
// driver mapping until the source explicitly confirms the role.
|
|
141
|
+
driver: item.driverConfirmed,
|
|
142
|
+
passenger: item.passengerConfirmed,
|
|
143
|
+
evidenceIds: [...new Set(item.evidenceIds)],
|
|
144
|
+
}))
|
|
145
|
+
.filter((item) => item.evidenceIds.length > 0)
|
|
146
|
+
.sort((left, right) => left.playerId.localeCompare(right.playerId));
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=vehicle-intelligence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vehicle-intelligence.js","sourceRoot":"","sources":["../../../src/review/vehicle-intelligence.ts"],"names":[],"mappings":"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"}
|