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