@cs2dak/contract 0.2.0 → 1.0.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/package.json +2 -2
- package/src/analysis.ts +222 -0
- package/src/cohort.ts +59 -0
- package/src/contract.test.ts +559 -0
- package/src/demo-package.ts +38 -0
- package/src/index.ts +11 -599
- package/src/leaderboard.ts +102 -0
- package/src/player.ts +96 -0
- package/src/qa.ts +21 -0
- package/src/scoring.ts +79 -0
- package/src/series.ts +77 -0
- package/src/team.ts +72 -0
- package/src/upstream.ts +90 -0
- package/src/workspace.ts +167 -0
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cs2dak/contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./src/index.ts"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@rivalhub/rival-rating": "
|
|
10
|
+
"@rivalhub/rival-rating": "^0.1.0",
|
|
11
11
|
"cs2-demo-format": "^2.2.0",
|
|
12
12
|
"zod": "^3.25.0"
|
|
13
13
|
},
|
package/src/analysis.ts
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import type { RRResult, PrismResult } from "@rivalhub/rival-rating";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { teamKeySchema, sideSchema, economyTypeSchema, teamEconomySchema, grenadeTypeSchema } from "cs2-demo-format";
|
|
4
|
+
import { qaReportSchema } from "./qa.js";
|
|
5
|
+
import { rrIndicatorsSchema } from "./scoring.js";
|
|
6
|
+
|
|
7
|
+
export const playerRoundFactSchema = z.object({
|
|
8
|
+
roundNumber: z.number().int().positive(),
|
|
9
|
+
steamId64: z.string(),
|
|
10
|
+
name: z.string(),
|
|
11
|
+
teamKey: teamKeySchema,
|
|
12
|
+
side: sideSchema,
|
|
13
|
+
survived: z.boolean(),
|
|
14
|
+
kills: z.number().int().nonnegative(),
|
|
15
|
+
deaths: z.number().int().nonnegative(),
|
|
16
|
+
assists: z.number().int().nonnegative(),
|
|
17
|
+
damage: z.number().int().nonnegative(),
|
|
18
|
+
utilityDamage: z.number().int().nonnegative(),
|
|
19
|
+
flashAssists: z.number().int().nonnegative(),
|
|
20
|
+
tradeKills: z.number().int().nonnegative(),
|
|
21
|
+
tradedDeaths: z.number().int().nonnegative(),
|
|
22
|
+
openingDuel: z.enum(["none", "won", "lost"]),
|
|
23
|
+
kastTags: z.array(z.enum(["kill", "assist", "survive", "trade"])),
|
|
24
|
+
equipmentValue: z.number().int().nonnegative().nullable(),
|
|
25
|
+
economyType: economyTypeSchema.nullable()
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const playerIndicatorRowSchema = z.object({
|
|
29
|
+
steamId64: z.string(),
|
|
30
|
+
name: z.string(),
|
|
31
|
+
teamKey: teamKeySchema,
|
|
32
|
+
indicators: rrIndicatorsSchema,
|
|
33
|
+
rr: z.custom<RRResult>(),
|
|
34
|
+
rrPercentile: z.number().min(0).max(100),
|
|
35
|
+
prism: z.custom<PrismResult>().nullable()
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export const playerScoreboardRowSchema = z.object({
|
|
39
|
+
steamId64: z.string(),
|
|
40
|
+
name: z.string(),
|
|
41
|
+
teamKey: teamKeySchema,
|
|
42
|
+
kills: z.number().int().nonnegative(),
|
|
43
|
+
deaths: z.number().int().nonnegative(),
|
|
44
|
+
assists: z.number().int().nonnegative(),
|
|
45
|
+
adr: z.number().nonnegative(),
|
|
46
|
+
kast: z.number().min(0).max(100),
|
|
47
|
+
headshotPercent: z.number().min(0).max(100),
|
|
48
|
+
entryKills: z.number().int().nonnegative(),
|
|
49
|
+
tradeKills: z.number().int().nonnegative(),
|
|
50
|
+
awpKills: z.number().int().nonnegative(),
|
|
51
|
+
utilityDamage: z.number().int().nonnegative(),
|
|
52
|
+
combatDeathCount: z.number().int().nonnegative().nullable(),
|
|
53
|
+
bombDeathCount: z.number().int().nonnegative().nullable(),
|
|
54
|
+
wallbangKillCount: z.number().int().nonnegative().nullable(),
|
|
55
|
+
noScopeKillCount: z.number().int().nonnegative().nullable(),
|
|
56
|
+
throughSmokeKillCount: z.number().int().nonnegative().nullable(),
|
|
57
|
+
collateralKillCount: z.number().int().nonnegative().nullable(),
|
|
58
|
+
bombPlantCount: z.number().int().nonnegative().nullable(),
|
|
59
|
+
bombDefuseCount: z.number().int().nonnegative().nullable(),
|
|
60
|
+
confidence: z.number().min(0).max(1),
|
|
61
|
+
fieldAvailability: z.object({
|
|
62
|
+
playerStats: z.enum(["available", "missing"]),
|
|
63
|
+
economy: z.enum(["available", "missing"]),
|
|
64
|
+
rounds: z.enum(["available", "missing"]),
|
|
65
|
+
richKills: z.enum(["available", "partial", "missing"]),
|
|
66
|
+
damages: z.enum(["available", "missing"]),
|
|
67
|
+
bombs: z.enum(["available", "missing"])
|
|
68
|
+
}),
|
|
69
|
+
ratingSeed: z.number().nonnegative(),
|
|
70
|
+
rr: z.number().nonnegative(),
|
|
71
|
+
rrPercentile: z.number().min(0).max(100),
|
|
72
|
+
/** RR v2 账户分。锚定后:1.00 = 本场联赛均值(per-match league mean)。 */
|
|
73
|
+
accountRR: z.number().nonnegative(),
|
|
74
|
+
/** 锚定/clamp 前的原始账户分(调试用)。 */
|
|
75
|
+
accountRRRaw: z.number(),
|
|
76
|
+
/** Combat 击杀项的 context 乘子(1.0 = context 未生效 / 已降级)。 */
|
|
77
|
+
accountCombatContextFactor: z.number(),
|
|
78
|
+
/** 五账户对 RR 的加权贡献(解释面板用;和为 accountRRRaw − intercept)。 */
|
|
79
|
+
accountBreakdown: z.object({
|
|
80
|
+
combat: z.number(),
|
|
81
|
+
trade: z.number(),
|
|
82
|
+
clutch: z.number(),
|
|
83
|
+
objective: z.number(),
|
|
84
|
+
utility: z.number()
|
|
85
|
+
}),
|
|
86
|
+
/**
|
|
87
|
+
* Combat context 分桶的可用性。
|
|
88
|
+
* "available" = 采集到数据源(即使无相关样本,分桶为 0 也算 available);
|
|
89
|
+
* "missing" = 数据源缺失(parser 未产出),乘子已降级为 1.0,前端应显示"未启用"。
|
|
90
|
+
*/
|
|
91
|
+
accountContextStatus: z.object({
|
|
92
|
+
buyDelta: z.enum(["available", "missing"]),
|
|
93
|
+
manState: z.enum(["available", "missing"])
|
|
94
|
+
})
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
export const weaponKillRowSchema = z.object({
|
|
98
|
+
weapon: z.string(),
|
|
99
|
+
kills: z.number().int().nonnegative(),
|
|
100
|
+
headshotKills: z.number().int().nonnegative(),
|
|
101
|
+
tradeKills: z.number().int().nonnegative(),
|
|
102
|
+
noScopeKills: z.number().int().nonnegative(),
|
|
103
|
+
throughSmokeKills: z.number().int().nonnegative(),
|
|
104
|
+
wallbangKills: z.number().int().nonnegative(),
|
|
105
|
+
penetratedObjects: z.number().int().nonnegative()
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
export const playerWeaponHighlightFactsSchema = z.object({
|
|
109
|
+
steamId64: z.string(),
|
|
110
|
+
totalKills: z.number().int().nonnegative(),
|
|
111
|
+
weapons: z.array(weaponKillRowSchema),
|
|
112
|
+
highlights: z.object({
|
|
113
|
+
wallbangKills: z.number().int().nonnegative().nullable(),
|
|
114
|
+
noScopeKills: z.number().int().nonnegative().nullable(),
|
|
115
|
+
throughSmokeKills: z.number().int().nonnegative().nullable(),
|
|
116
|
+
collateralKills: z.number().int().nonnegative().nullable()
|
|
117
|
+
})
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
export const accountContextAvailabilitySchema = z.enum(["available", "partial", "missing"]);
|
|
121
|
+
|
|
122
|
+
export const timelineEventSchema = z.object({
|
|
123
|
+
id: z.string(),
|
|
124
|
+
roundNumber: z.number().int().positive(),
|
|
125
|
+
tick: z.number().int().positive(),
|
|
126
|
+
timeSeconds: z.number().nonnegative(),
|
|
127
|
+
clockPhase: z.enum(["freeze", "round", "bomb", "round-end"]),
|
|
128
|
+
clockSeconds: z.number().nonnegative(),
|
|
129
|
+
clockLabel: z.string(),
|
|
130
|
+
type: z.enum(["kill", "bomb", "grenade", "round-end"]),
|
|
131
|
+
label: z.string(),
|
|
132
|
+
teamKey: teamKeySchema.nullable()
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
export const economyPointSchema = z.object({
|
|
136
|
+
roundNumber: z.number().int().positive(),
|
|
137
|
+
teamA: z.number().int().nonnegative(),
|
|
138
|
+
teamB: z.number().int().nonnegative(),
|
|
139
|
+
advantage: z.number().int(),
|
|
140
|
+
teamAEconomy: teamEconomySchema,
|
|
141
|
+
teamBEconomy: teamEconomySchema,
|
|
142
|
+
winnerTeamKey: teamKeySchema
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
export const heatmapPointSchema = z.object({
|
|
146
|
+
x: z.number(),
|
|
147
|
+
y: z.number(),
|
|
148
|
+
z: z.number(),
|
|
149
|
+
roundNumber: z.number().int().positive(),
|
|
150
|
+
teamKey: teamKeySchema.nullable(),
|
|
151
|
+
steamId64: z.string().nullable(),
|
|
152
|
+
side: sideSchema.nullable(),
|
|
153
|
+
kind: z.enum(["kill", "death", "grenade"]),
|
|
154
|
+
grenadeType: grenadeTypeSchema.nullable()
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
export const mapViewSchema = z.object({
|
|
158
|
+
name: z.string(),
|
|
159
|
+
radarImageUrl: z.string().nullable(),
|
|
160
|
+
calibrated: z.boolean()
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
export const analysisProvenanceSchema = z.object({
|
|
164
|
+
analysisVersion: z.string(),
|
|
165
|
+
sourceSchemaVersion: z.literal("cs2-demo-format/2.0"),
|
|
166
|
+
sourceDemoHash: z.string().nullable(),
|
|
167
|
+
exporter: z.object({ name: z.string(), version: z.string() }),
|
|
168
|
+
parser: z.object({ name: z.string(), version: z.string() }),
|
|
169
|
+
ratingVersions: z.object({
|
|
170
|
+
rr: z.string().nullable(),
|
|
171
|
+
valueAccounts: z.string().nullable()
|
|
172
|
+
})
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
export const analysisBundleSchema = z.object({
|
|
176
|
+
version: z.literal("cs2-demo-analysis-kit/1.0"),
|
|
177
|
+
sourceSchemaVersion: z.literal("cs2-demo-format/2.0"),
|
|
178
|
+
provenance: analysisProvenanceSchema,
|
|
179
|
+
mapName: z.string(),
|
|
180
|
+
tickrate: z.number().int().positive(),
|
|
181
|
+
teams: z.object({
|
|
182
|
+
teamA: z.object({ name: z.string(), score: z.number().int().nonnegative() }),
|
|
183
|
+
teamB: z.object({ name: z.string(), score: z.number().int().nonnegative() })
|
|
184
|
+
}),
|
|
185
|
+
scoreboard: z.array(playerScoreboardRowSchema),
|
|
186
|
+
playerWeaponHighlights: z.array(playerWeaponHighlightFactsSchema),
|
|
187
|
+
playerIndicators: z.array(playerIndicatorRowSchema),
|
|
188
|
+
playerRoundFacts: z.array(playerRoundFactSchema),
|
|
189
|
+
timeline: z.array(timelineEventSchema),
|
|
190
|
+
economy: z.array(economyPointSchema),
|
|
191
|
+
heatmap: z.array(heatmapPointSchema),
|
|
192
|
+
qa: qaReportSchema
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
export const demoViewModelSchema = z.object({
|
|
196
|
+
title: z.string(),
|
|
197
|
+
subtitle: z.string(),
|
|
198
|
+
map: mapViewSchema,
|
|
199
|
+
scoreline: z.string(),
|
|
200
|
+
teams: analysisBundleSchema.shape.teams,
|
|
201
|
+
scoreboard: z.array(playerScoreboardRowSchema),
|
|
202
|
+
playerIndicators: z.array(playerIndicatorRowSchema),
|
|
203
|
+
playerRoundFacts: z.array(playerRoundFactSchema),
|
|
204
|
+
timeline: z.array(timelineEventSchema),
|
|
205
|
+
economy: z.array(economyPointSchema),
|
|
206
|
+
heatmap: z.array(heatmapPointSchema),
|
|
207
|
+
qa: qaReportSchema
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
export type PlayerRoundFact = z.infer<typeof playerRoundFactSchema>;
|
|
211
|
+
export type PlayerIndicatorRow = z.infer<typeof playerIndicatorRowSchema>;
|
|
212
|
+
export type PlayerScoreboardRow = z.infer<typeof playerScoreboardRowSchema>;
|
|
213
|
+
export type WeaponKillRow = z.infer<typeof weaponKillRowSchema>;
|
|
214
|
+
export type PlayerWeaponHighlightFacts = z.infer<typeof playerWeaponHighlightFactsSchema>;
|
|
215
|
+
export type AccountContextAvailability = z.infer<typeof accountContextAvailabilitySchema>;
|
|
216
|
+
export type TimelineEvent = z.infer<typeof timelineEventSchema>;
|
|
217
|
+
export type EconomyPoint = z.infer<typeof economyPointSchema>;
|
|
218
|
+
export type GrenadeType = z.infer<typeof grenadeTypeSchema>;
|
|
219
|
+
export type HeatmapPoint = z.infer<typeof heatmapPointSchema>;
|
|
220
|
+
export type AnalysisBundle = z.infer<typeof analysisBundleSchema>;
|
|
221
|
+
export type AnalysisProvenance = z.infer<typeof analysisProvenanceSchema>;
|
|
222
|
+
export type DemoViewModel = z.infer<typeof demoViewModelSchema>;
|
package/src/cohort.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { PrismResult } from "@rivalhub/rival-rating";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { teamKeySchema } from "cs2-demo-format";
|
|
4
|
+
import { accountContextAvailabilitySchema } from "./analysis.js";
|
|
5
|
+
import { rrIndicatorsSchema } from "./scoring.js";
|
|
6
|
+
import { playerWeaponHighlightFactsSchema } from "./analysis.js";
|
|
7
|
+
|
|
8
|
+
export const seasonPlayerRowSchema = z.object({
|
|
9
|
+
playerKey: z.string(),
|
|
10
|
+
steamIds: z.array(z.string()),
|
|
11
|
+
primarySteamId64: z.string(),
|
|
12
|
+
externalUserId: z.string().nullable(),
|
|
13
|
+
name: z.string(),
|
|
14
|
+
teamKeys: z.array(teamKeySchema),
|
|
15
|
+
mapCount: z.number().int().positive(),
|
|
16
|
+
rrV1: z.number().nonnegative(),
|
|
17
|
+
rrV1Percentile: z.number().min(0).max(100),
|
|
18
|
+
indicators: rrIndicatorsSchema,
|
|
19
|
+
weaponHighlights: playerWeaponHighlightFactsSchema,
|
|
20
|
+
accountRR: z.number().nonnegative(),
|
|
21
|
+
accountRRRaw: z.number(),
|
|
22
|
+
accountBreakdown: z.object({
|
|
23
|
+
combat: z.number(),
|
|
24
|
+
trade: z.number(),
|
|
25
|
+
clutch: z.number(),
|
|
26
|
+
objective: z.number(),
|
|
27
|
+
utility: z.number()
|
|
28
|
+
}),
|
|
29
|
+
accountContextStatus: z.object({
|
|
30
|
+
buyDelta: accountContextAvailabilitySchema,
|
|
31
|
+
manState: accountContextAvailabilitySchema
|
|
32
|
+
}),
|
|
33
|
+
prism: z.custom<PrismResult>().nullable(),
|
|
34
|
+
confidence: z.number().min(0).max(1),
|
|
35
|
+
perMatch: z.array(z.object({
|
|
36
|
+
matchId: z.string(),
|
|
37
|
+
steamId64: z.string(),
|
|
38
|
+
accountRR: z.number().nonnegative(),
|
|
39
|
+
rrV1: z.number().nonnegative()
|
|
40
|
+
}))
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export const seasonCohortBundleSchema = z.object({
|
|
44
|
+
version: z.literal("cs2-demo-analysis-kit/cohort-1.0"),
|
|
45
|
+
matchCount: z.number().int().nonnegative(),
|
|
46
|
+
players: z.array(seasonPlayerRowSchema),
|
|
47
|
+
weightsVersion: z.string(),
|
|
48
|
+
provenance: z.object({
|
|
49
|
+
cohortVersion: z.literal("cs2-demo-analysis-kit/cohort-1.0"),
|
|
50
|
+
sourceSchemaVersion: z.literal("cs2-demo-format/2.0"),
|
|
51
|
+
matches: z.array(z.object({
|
|
52
|
+
matchId: z.string(),
|
|
53
|
+
sourceDemoHash: z.string().nullable()
|
|
54
|
+
}))
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
export type SeasonPlayerRow = z.infer<typeof seasonPlayerRowSchema>;
|
|
59
|
+
export type SeasonCohortBundle = z.infer<typeof seasonCohortBundleSchema>;
|