1use crate::scheme::DDSTATS_BASE_URL;
2use crate::util::prelude::{encode, seconds_to_hours, slugify2};
3use serde::{Deserialize, Serialize};
4
5#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
6pub struct Player {
7 pub points_graph: Vec<PointsGraph>,
8 pub recent_finishes: Vec<RecentFinish>,
9 pub favourite_teammates: Vec<FavouriteTeammate>,
10 pub profile: Profile,
11 pub is_mapper: bool,
12 pub finishes: Vec<Finish>,
13 pub unfinished_maps: Vec<UnfinishedMap>,
14 pub points: Points,
15 #[serde(default)]
16 pub completion_progress: Vec<CompletionProgress>,
17 pub recent_activity: Vec<RecentActivity>,
18 pub recent_player_info: Vec<RecentPlayerInfo>,
19 pub most_played_maps: Vec<MostPlayedMap>,
20 pub most_played_gametypes: Vec<MostPlayed>,
21 pub most_played_categories: Vec<MostPlayed>,
22 pub most_played_locations: Vec<MostPlayed>,
23 pub playtime_per_month: Vec<PlaytimePerMonth>,
24 pub general_activity: Option<GeneralActivity>,
25 pub favourite_rank1s_teammates: Vec<FavouriteRank1sTeammates>,
26 pub all_top_10s: Vec<AllTop10>,
27 pub recent_top_10s: Vec<RecentTop10>,
28}
29
30#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
31pub struct CompletionProgress {
32 pub category: String,
33 pub maps_finished: u64,
34 pub maps_total: u64,
35}
36
37impl Player {
38 pub fn url(&self) -> String {
39 format!(
40 "https://{}/player/{}",
41 DDSTATS_BASE_URL,
42 encode(&self.profile.name)
43 )
44 }
45
46 pub fn url_with_name(player: &str) -> String {
47 format!("https://{}/player/{}", DDSTATS_BASE_URL, encode(player))
48 }
49
50 pub fn api(player: &str) -> String {
51 format!(
52 "https://{}/player/json?player={}",
53 DDSTATS_BASE_URL,
54 encode(player)
55 )
56 }
57}
58
59#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
60pub struct PointsGraph {
61 pub date: String,
62 pub points: i64,
63 pub rank_points: i64,
64 pub team_points: i64,
65}
66
67#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
68pub struct RecentFinish {
69 pub map: StatsMap,
70 pub name: String,
71 pub time: f64,
72 pub timestamp: String,
73 pub server: String,
74 pub cp1: f64,
75 pub cp2: f64,
76 pub cp3: f64,
77 pub cp4: f64,
78 pub cp5: f64,
79 pub cp6: f64,
80 pub cp7: f64,
81 pub cp8: f64,
82 pub cp9: f64,
83 pub cp10: f64,
84 pub cp11: f64,
85 pub cp12: f64,
86 pub cp13: f64,
87 pub cp14: f64,
88 pub cp15: f64,
89 pub cp16: f64,
90 pub cp17: f64,
91 pub cp18: f64,
92 pub cp19: f64,
93 pub cp20: f64,
94 pub cp21: f64,
95 pub cp22: f64,
96 pub cp23: f64,
97 pub cp24: f64,
98 pub cp25: f64,
99}
100
101#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
102pub struct StatsMap {
103 pub map: String,
104 pub server: String,
105 pub points: u8,
106 pub stars: u8,
107 pub mapper: String,
108 pub timestamp: Option<String>,
109}
110
111impl StatsMap {
112 pub fn url(&self) -> String {
113 format!(
114 "https://{}/map/{}",
115 DDSTATS_BASE_URL,
116 encode(&slugify2(&self.map))
117 )
118 }
119
120 pub fn url_with_name(map: &str) -> String {
121 format!(
122 "https://{}/map/{}",
123 DDSTATS_BASE_URL,
124 encode(&slugify2(map))
125 )
126 }
127
128 pub fn api() -> String {
129 format!("https://{}/maps/json", DDSTATS_BASE_URL)
130 }
131}
132
133#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
134pub struct FavouriteTeammate {
135 pub name: String,
136 pub ranks_together: i64,
137}
138
139#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
140pub struct Profile {
141 pub name: String,
142 pub points: i32,
143 pub clan: Option<String>,
144 pub country: Option<i32>,
145 pub skin_name: Option<String>,
146 pub skin_color_body: Option<i32>,
147 pub skin_color_feet: Option<i32>,
148 pub most_played_location: Option<String>,
149}
150
151impl Profile {
152 pub fn url(&self) -> String {
153 format!("https://{}/player/{}", DDSTATS_BASE_URL, encode(&self.name))
154 }
155
156 pub fn url_with_name(player: &str) -> String {
157 format!("https://{}/player/{}", DDSTATS_BASE_URL, encode(player))
158 }
159
160 pub fn api(player: &str) -> String {
161 format!(
162 "https://{}/profile/json?player={}",
163 DDSTATS_BASE_URL,
164 encode(player)
165 )
166 }
167}
168
169#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
170pub struct Finish {
171 pub map: StatsMap,
172 pub name: String,
173 pub time: f64,
174 pub timestamp: String,
175 pub server: String,
176 pub rank: u64,
177 pub team_rank: Option<u64>,
178 pub seconds_played: Option<u64>,
179}
180
181#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
182pub struct UnfinishedMap {
183 pub map: StatsMap,
184 pub finishes: u64,
185 pub finishes_rank: Option<u64>,
186 pub median_time: Option<f64>,
187}
188
189#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
190pub struct Points {
191 pub weekly_points: Option<PPoints>,
192 pub monthly_points: Option<PPoints>,
193 pub yearly_points: Option<PPoints>,
194 pub points: StatsPoints,
195 pub rank_points: StatsPoints,
196 pub team_points: StatsPoints,
197}
198
199#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
200pub struct PPoints {
201 pub points: i64,
202 pub rank: i64,
203}
204
205#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
206#[serde(rename_all = "PascalCase")]
207pub struct StatsPoints {
208 pub moderate: Option<Type>,
209 pub insane: Option<Type>,
210 pub oldschool: Option<Type>,
211 pub fun: Option<Type>,
212 pub race: Option<Type>,
213 pub total: Option<Type>,
214 #[serde(rename = "DDmaX.Easy")]
215 pub ddmax_easy: Option<Type>,
216 pub novice: Option<Type>,
217 pub dummy: Option<Type>,
218 #[serde(rename = "DDmaX.Pro")]
219 pub ddmax_pro: Option<Type>,
220 pub brutal: Option<Type>,
221 #[serde(rename = "DDmaX.Nut")]
222 pub ddmax_nut: Option<Type>,
223 pub solo: Option<Type>,
224 #[serde(rename = "DDmaX.Next")]
225 pub ddmax_next: Option<Type>,
226}
227
228#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
229pub struct Type {
230 pub points: i64,
231 pub rank: i64,
232}
233
234#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
235pub struct RecentActivity {
236 pub name: String,
237 pub date: String,
238 pub map_name: String,
239 pub map: Option<StatsMap>,
240 pub seconds_played: i64,
241}
242
243#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
244pub struct RecentPlayerInfo {
245 pub name: String,
246 pub clan: String,
247 pub country: i32,
248 pub skin_name: Option<String>,
249 pub skin_color_body: Option<u64>,
250 pub skin_color_feet: Option<u64>,
251 pub last_seen: String,
252 pub seconds_played: u64,
253}
254
255#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
256pub struct MostPlayedMap {
257 pub map_name: String,
258 pub seconds_played: u64,
259 pub map: Option<StatsMap>,
260}
261
262#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
263pub struct MostPlayed {
264 pub key: String,
265 pub seconds_played: u64,
266}
267
268#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
269pub struct PlaytimePerMonth {
270 pub year_month: String,
271 pub month: String,
272 pub seconds_played: u64,
273}
274
275#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
276pub struct GeneralActivity {
277 pub total_seconds_played: u64,
278 pub start_of_playtime: String,
279 pub average_seconds_played: u64,
280}
281
282impl GeneralActivity {
283 pub fn total_seconds_played_to_hours(&self) -> f64 {
284 seconds_to_hours(self.total_seconds_played as f64)
285 }
286
287 pub fn average_seconds_played_to_hours(&self) -> f64 {
288 seconds_to_hours(self.average_seconds_played as f64)
289 }
290}
291
292#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
293pub struct FavouriteRank1sTeammates {
294 pub name: String,
295 pub ranks_together: u64,
296}
297
298#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
299pub struct AllTop10 {
300 pub map: StatsMap,
301 pub name: String,
302 pub time: f64,
303 pub rank: u64,
304 pub team_rank: Option<u64>,
305 pub team_time: Option<f64>,
306}
307
308#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
309pub struct RecentTop10 {
310 pub rank_type: String,
311 pub map: String,
312 pub time: f64,
313 pub rank: u64,
314 pub timestamp: String,
315 pub server: String,
316}
317
318#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
319pub struct InfoSMap {
320 pub map: StatsMap,
321 pub finishes: u64,
322 pub finishes_rank: u64,
323 pub median_time: f64,
324}
325
326#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
327pub struct RankingSMap {
328 pub rank: u64,
329 pub timestamp: Option<String>,
330 pub name: String,
331 pub time: f64,
332 pub map: String,
333 pub server: String,
334}
335
336#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
337pub struct TeamRankingSMap {
338 pub rank: u64,
339 pub timestamp: Option<String>,
340 pub id: Vec<u64>,
341 pub players: Vec<String>,
342 pub time: f64,
343 pub map: String,
344 pub server: String,
345}
346
347#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
348pub struct TimeCpsSMap {
349 pub name: String,
350 pub cp1: f64,
351 pub cp2: f64,
352 pub cp3: f64,
353 pub cp4: f64,
354 pub cp5: f64,
355 pub cp6: f64,
356 pub cp7: f64,
357 pub cp8: f64,
358 pub cp9: f64,
359 pub cp10: f64,
360 pub cp11: f64,
361 pub cp12: f64,
362 pub cp13: f64,
363 pub cp14: f64,
364 pub cp15: f64,
365 pub cp16: f64,
366 pub cp17: f64,
367 pub cp18: f64,
368 pub cp19: f64,
369 pub cp20: f64,
370 pub cp21: f64,
371 pub cp22: f64,
372 pub cp23: f64,
373 pub cp24: f64,
374 pub cp25: f64,
375 pub time: f64,
376}
377
378#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
379pub struct PlaytimeSMap {
380 pub name: String,
381 pub seconds_played: u64,
382}
383
384#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
385pub struct Map {
386 pub info: InfoSMap,
387 pub rankings: Vec<RankingSMap>,
388 pub team_rankings: Vec<TeamRankingSMap>,
389 pub time_cps: Vec<TimeCpsSMap>,
390 pub playtime: Vec<PlaytimeSMap>,
391}
392
393impl Map {
394 pub fn url(&self) -> String {
395 format!(
396 "https://{}/map/{}",
397 DDSTATS_BASE_URL,
398 encode(&self.info.map.map)
399 )
400 }
401
402 pub fn url_with_name(map: &str) -> String {
403 format!("https://{}/map/{}", DDSTATS_BASE_URL, encode(map))
404 }
405
406 pub fn api(map: &str) -> String {
407 format!("https://{}/map/json?map={}", DDSTATS_BASE_URL, encode(map))
408 }
409}