@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 CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@cs2dak/contract",
3
- "version": "0.2.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": "github:Starfie1d1272/rival-rating#5d862eb",
10
+ "@rivalhub/rival-rating": "^0.1.0",
11
11
  "cs2-demo-format": "^2.2.0",
12
12
  "zod": "^3.25.0"
13
13
  },
@@ -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>;