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 api(player: &str) -> String {
127 format!("https://ddstats.tw/profile/json?player={}", encode(player))
128 }
129}
130
131#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
132pub struct Finish {
133 pub map: StatsMap,
134 pub name: String,
135 pub time: f64,
136 pub timestamp: String,
137 pub server: String,
138 pub rank: u64,
139 pub team_rank: Option<u64>,
140 pub seconds_played: Option<u64>,
141}
142
143#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
144pub struct UnfinishedMap {
145 pub map: StatsMap,
146 pub finishes: u64,
147 pub finishes_rank: Option<u64>,
148 pub median_time: Option<f64>,
149}
150
151#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
152pub struct Points {
153 pub weekly_points: Option<PPoints>,
154 pub monthly_points: Option<PPoints>,
155 pub yearly_points: Option<PPoints>,
156 pub points: StatsPoints,
157 pub rank_points: StatsPoints,
158 pub team_points: StatsPoints,
159}
160
161#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
162pub struct PPoints {
163 pub points: i64,
164 pub rank: i64,
165}
166
167#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
168#[serde(rename_all = "PascalCase")]
169pub struct StatsPoints {
170 pub moderate: Option<Type>,
171 pub insane: Option<Type>,
172 pub oldschool: Option<Type>,
173 pub fun: Option<Type>,
174 pub race: Option<Type>,
175 pub total: Option<Type>,
176 #[serde(rename = "DDmaX.Easy")]
177 pub ddmax_easy: Option<Type>,
178 pub novice: Option<Type>,
179 pub dummy: Option<Type>,
180 #[serde(rename = "DDmaX.Pro")]
181 pub ddmax_pro: Option<Type>,
182 pub brutal: Option<Type>,
183 #[serde(rename = "DDmaX.Nut")]
184 pub ddmax_nut: Option<Type>,
185 pub solo: Option<Type>,
186 #[serde(rename = "DDmaX.Next")]
187 pub ddmax_next: Option<Type>,
188}
189
190#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
191pub struct Type {
192 pub points: i64,
193 pub rank: i64,
194}
195
196#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
197pub struct RecentActivity {
198 pub name: String,
199 pub date: String,
200 pub map_name: String,
201 pub map: Option<StatsMap>,
202 pub seconds_played: i64,
203}
204
205#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
206pub struct RecentPlayerInfo {
207 pub name: String,
208 pub clan: String,
209 pub country: i16,
210 pub skin_name: Option<String>,
211 pub skin_color_body: Option<u64>,
212 pub skin_color_feet: Option<u64>,
213 pub last_seen: String,
214 pub seconds_played: u64,
215}
216
217#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
218pub struct MostPlayedMap {
219 pub map_name: String,
220 pub seconds_played: u64,
221 pub map: Option<StatsMap>,
222}
223
224#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
225pub struct MostPlayed {
226 pub key: String,
227 pub seconds_played: u64,
228}
229
230#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
231pub struct PlaytimePerMonth {
232 pub year_month: String,
233 pub month: String,
234 pub seconds_played: u64,
235}
236
237#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
238pub struct GeneralActivity {
239 pub total_seconds_played: u64,
240 pub start_of_playtime: String,
241 pub average_seconds_played: u64,
242}
243
244impl GeneralActivity {
245 pub fn total_seconds_played_to_hours(&self) -> f64 {
246 seconds_to_hours(self.total_seconds_played)
247 }
248
249 pub fn average_seconds_played_to_hours(&self) -> f64 {
250 seconds_to_hours(self.average_seconds_played)
251 }
252}
253
254#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
255pub struct FavouriteRank1sTeammates {
256 pub name: String,
257 pub ranks_together: u64,
258}
259
260#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
261pub struct AllTop10 {
262 pub map: StatsMap,
263 pub name: String,
264 pub time: f64,
265 pub rank: u64,
266 pub team_rank: Option<u64>,
267 pub team_time: Option<f64>,
268}
269
270#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
271pub struct RecentTop10 {
272 pub rank_type: String,
273 pub map: String,
274 pub time: f64,
275 pub rank: u64,
276 pub timestamp: String,
277 pub server: String,
278}
279
280#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
281pub struct InfoSMap {
282 pub map: StatsMap,
283 pub finishes: u64,
284 pub finishes_rank: u64,
285 pub median_time: f64,
286}
287
288#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
289pub struct RankingSMap {
290 pub rank: u64,
291 pub timestamp: Option<String>,
292 pub name: String,
293 pub time: f64,
294 pub map: String,
295 pub server: String,
296}
297
298#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
299pub struct TeamRankingSMap {
300 pub rank: u64,
301 pub timestamp: Option<String>,
302 pub id: Vec<u64>,
303 pub players: Vec<String>,
304 pub time: f64,
305 pub map: String,
306 pub server: String,
307}
308
309#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
310pub struct TimeCpsSMap {
311 pub name: String,
312 pub cp1: f64,
313 pub cp2: f64,
314 pub cp3: f64,
315 pub cp4: f64,
316 pub cp5: f64,
317 pub cp6: f64,
318 pub cp7: f64,
319 pub cp8: f64,
320 pub cp9: f64,
321 pub cp10: f64,
322 pub cp11: f64,
323 pub cp12: f64,
324 pub cp13: f64,
325 pub cp14: f64,
326 pub cp15: f64,
327 pub cp16: f64,
328 pub cp17: f64,
329 pub cp18: f64,
330 pub cp19: f64,
331 pub cp20: f64,
332 pub cp21: f64,
333 pub cp22: f64,
334 pub cp23: f64,
335 pub cp24: f64,
336 pub cp25: f64,
337 pub time: f64,
338}
339
340#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
341pub struct PlaytimeSMap {
342 pub name: String,
343 pub seconds_played: u64,
344}
345
346#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
347pub struct Map {
348 pub info: InfoSMap,
349 pub rankings: Vec<RankingSMap>,
350 pub team_rankings: Vec<TeamRankingSMap>,
351 pub time_cps: Vec<TimeCpsSMap>,
352 pub playtime: Vec<PlaytimeSMap>,
353}
354
355impl Map {
356 pub fn api(map: &str) -> String {
357 format!("https://ddstats.tw/map/json?map={}", encode(map))
358 }
359}