1use chrono::DateTime;
2use chrono::{serde::ts_seconds, Utc};
3use serde::Deserialize;
4use serde_repr::{Deserialize_repr, Serialize_repr};
5use uuid::Uuid;
6
7use crate::types::Time;
8use crate::types::{Elo, EloChange, MatchId, Rank, Season};
9use crate::user::UserProfile;
10
11pub mod requests;
12#[cfg(test)]
13mod tests;
14pub mod versus;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
17#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
18pub enum MatchCategory {
19 Any,
20 Custom,
21 High,
22 KillAllBosses,
23 KillWither,
24 KillElderGuardian,
25 AllAdvancements,
26 Half,
27 PoglootQuater,
28 HowDidWeGetHere,
29 HeroOfTheVillage,
30 Arbalistic,
31 CoverMeInDebris,
32 EnterNether,
33 EnterEnd,
34 AllSwords,
35 AllMinerals,
36 #[serde(rename = "FULL_IA_15_LVL")]
37 FullIa15Lvl,
38 AllWorkstations,
39 FullInv,
40 StackOfLimeWool,
41 AllPortals,
42 AllBlocks,
43 MineAChunk,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
47pub struct MatchSeedInfo {
48 id: Option<Box<str>>,
49 overworld: Option<OverworldType>,
50 bastion: Option<BastionType>,
51 variations: Box<[Box<str>]>,
52}
53impl MatchSeedInfo {
54 pub fn id(&self) -> Option<&str> {
56 self.id.as_ref().map(AsRef::as_ref)
57 }
58 pub fn overworld(&self) -> Option<OverworldType> {
60 self.overworld
61 }
62 pub fn bastion(&self) -> Option<BastionType> {
64 self.bastion
65 }
66 pub fn variations(&self) -> &[Box<str>] {
68 &self.variations
69 }
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize_repr, Serialize_repr)]
73#[repr(u8)]
74pub enum MatchType {
75 Causal = 1,
76 Ranked = 2,
77 Private = 3,
78 Event = 4,
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
82#[serde(rename_all = "camelCase")]
83pub struct MatchOutcome {
84 #[serde(rename = "uuid")]
85 winner_uuid: Option<Uuid>,
86 time: Time,
87}
88impl MatchOutcome {
89 pub fn winner_uuid(&self) -> Option<Uuid> {
90 self.winner_uuid
91 }
92 pub fn time(&self) -> Time {
93 self.time
94 }
95}
96
97#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
99#[serde(rename_all = "camelCase")]
100pub struct MatchRank {
101 season: Option<Rank>,
102 all_time: Option<Rank>,
103}
104impl MatchRank {
105 pub fn season(&self) -> Option<Rank> {
107 self.season
108 }
109 pub fn all_time(&self) -> Option<Rank> {
111 self.all_time
112 }
113}
114
115#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
117#[serde(rename_all = "camelCase")]
118pub struct MatchEloUpdate {
119 #[serde(rename = "uuid")]
120 player_uuid: Uuid,
121 change: Option<EloChange>,
122 #[serde(rename = "eloRate")]
123 elo: Option<Elo>,
124}
125impl MatchEloUpdate {
126 pub fn player_uuid(&self) -> Uuid {
128 self.player_uuid
129 }
130 pub fn elo_change(&self) -> Option<EloChange> {
132 self.change
133 }
134 pub fn elo(&self) -> Option<Elo> {
136 self.elo
137 }
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
142#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
143pub enum OverworldType {
144 Village,
145 BuriedTreasure,
146 Shipwreck,
147 RuinedPortal,
148 DesertTemple,
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
153#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
154pub enum BastionType {
155 Housing,
156 Treasure,
157 Bridge,
158 Stables,
159}
160
161#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
163#[serde(rename_all = "camelCase")]
164pub struct MatchCompletion {
165 #[serde(rename = "uuid")]
166 player_uuid: Uuid,
167 time: Time,
168}
169impl MatchCompletion {
170 pub fn player_uuid(&self) -> Uuid {
172 self.player_uuid
173 }
174 pub fn time(&self) -> Time {
176 self.time
177 }
178}
179
180#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
182#[serde(rename_all = "camelCase")]
183pub struct MatchTimelineEvent {
184 #[serde(rename = "uuid")]
185 player_uuid: Uuid,
186 time: Time,
187 #[serde(rename = "type")]
188 id: Box<str>,
189}
190impl MatchTimelineEvent {
191 pub fn player_uuid(&self) -> Uuid {
192 self.player_uuid
193 }
194 pub fn time(&self) -> Time {
195 self.time
196 }
197 pub fn id(&self) -> &str {
198 &self.id
199 }
200}
201
202#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
204#[serde(rename_all = "camelCase")]
205pub struct MatchInfo {
206 id: MatchId,
207 #[serde(rename = "type")]
208 kind: MatchType,
209 season: Season,
210 category: MatchCategory,
211 #[serde(with = "ts_seconds")]
212 date: DateTime<Utc>,
213 players: Box<[UserProfile]>,
214 spectators: Box<[UserProfile]>,
215 seed: MatchSeedInfo,
216 result: MatchOutcome,
217 forfeited: bool,
218 decayed: bool,
219 rank: MatchRank,
220 changes: Box<[MatchEloUpdate]>,
221}
222impl MatchInfo {
223 pub fn id(&self) -> MatchId {
225 self.id
226 }
227 pub fn kind(&self) -> MatchType {
229 self.kind
230 }
231 pub fn season(&self) -> Season {
233 self.season
234 }
235 pub fn category(&self) -> MatchCategory {
237 self.category
238 }
239 pub fn date(&self) -> DateTime<Utc> {
241 self.date
242 }
243 pub fn players(&self) -> &[UserProfile] {
245 &self.players
246 }
247 pub fn spectators(&self) -> &[UserProfile] {
249 &self.spectators
250 }
251 pub fn seed_info(&self) -> &MatchSeedInfo {
253 &self.seed
254 }
255 pub fn result(&self) -> &MatchOutcome {
257 &self.result
258 }
259 pub fn forfeited(&self) -> bool {
261 self.forfeited
262 }
263 pub fn decayed(&self) -> bool {
265 self.decayed
266 }
267 pub fn rank(&self) -> &MatchRank {
269 &self.rank
270 }
271 pub fn elo_updates(&self) -> &[MatchEloUpdate] {
273 &self.changes
274 }
275}
276
277#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
279#[serde(rename_all = "camelCase")]
280pub struct AdvancedMatchInfo {
281 #[serde(flatten)]
282 info: MatchInfo,
283 completions: Box<[MatchCompletion]>,
284 timelines: Box<[MatchTimelineEvent]>,
285 replay_exist: bool,
286}
287impl AdvancedMatchInfo {
288 pub fn completions(&self) -> &[MatchCompletion] {
290 &self.completions
291 }
292 pub fn timeline_events(&self) -> &[MatchTimelineEvent] {
294 &self.timelines
295 }
296 pub fn replay_exists(&self) -> bool {
298 self.replay_exist
299 }
300}