1use chrono::DateTime;
2use chrono::{serde::ts_seconds, Utc};
3use serde::Deserialize;
4#[cfg(feature = "serialize")]
5use serde::Serialize;
6use serde_repr::{Deserialize_repr, Serialize_repr};
7use uuid::Uuid;
8
9use crate::types::Time;
10use crate::types::{Elo, EloChange, MatchId, Rank, Season};
11use crate::user::UserProfile;
12
13pub mod requests;
14#[cfg(test)]
15mod tests;
16pub mod versus;
17
18#[cfg_attr(feature = "serialize", derive(Serialize))]
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
20#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
21pub enum MatchCategory {
22 Any,
23 Custom,
24 High,
25 KillAllBosses,
26 KillWither,
27 KillElderGuardian,
28 AllAdvancements,
29 Half,
30 PoglootQuater,
31 HowDidWeGetHere,
32 HeroOfTheVillage,
33 Arbalistic,
34 CoverMeInDebris,
35 EnterNether,
36 EnterEnd,
37 AllSwords,
38 AllMinerals,
39 #[serde(rename = "FULL_IA_15_LVL")]
40 FullIa15Lvl,
41 AllWorkstations,
42 FullInv,
43 StackOfLimeWool,
44 AllPortals,
45 AllBlocks,
46 MineAChunk,
47}
48
49#[cfg_attr(feature = "serialize", derive(Serialize))]
50#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
51pub struct MatchSeedInfo {
52 pub id: Option<Box<str>>,
54 pub overworld: Option<OverworldType>,
55 pub bastion: Option<BastionType>,
56 pub variations: Box<[Box<str>]>,
57}
58impl MatchSeedInfo {
59 pub fn id(&self) -> Option<&str> {
61 self.id.as_ref().map(AsRef::as_ref)
62 }
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize_repr, Serialize_repr)]
66#[repr(u8)]
67pub enum MatchType {
68 Causal = 1,
69 Ranked = 2,
70 Private = 3,
71 Event = 4,
72}
73
74#[cfg_attr(feature = "serialize", derive(Serialize))]
75#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
76#[serde(rename_all = "camelCase")]
77pub struct MatchOutcome {
78 #[serde(rename = "uuid")]
79 pub winner_uuid: Option<Uuid>,
80 pub time: Time,
81}
82
83#[cfg_attr(feature = "serialize", derive(Serialize))]
85#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
86#[serde(rename_all = "camelCase")]
87pub struct MatchRank {
88 pub season: Option<Rank>,
89 pub all_time: Option<Rank>,
90}
91
92#[cfg_attr(feature = "serialize", derive(Serialize))]
94#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
95#[serde(rename_all = "camelCase")]
96pub struct MatchEloUpdate {
97 #[serde(rename = "uuid")]
98 pub player_uuid: Uuid,
99 pub change: Option<EloChange>,
100 #[serde(rename = "eloRate")]
101 pub elo: Option<Elo>,
102}
103
104#[cfg_attr(feature = "serialize", derive(Serialize))]
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
107#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
108pub enum OverworldType {
109 Village,
110 BuriedTreasure,
111 Shipwreck,
112 RuinedPortal,
113 DesertTemple,
114}
115
116#[cfg_attr(feature = "serialize", derive(Serialize))]
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
119#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
120pub enum BastionType {
121 Housing,
122 Treasure,
123 Bridge,
124 Stables,
125}
126
127#[cfg_attr(feature = "serialize", derive(Serialize))]
129#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
130#[serde(rename_all = "camelCase")]
131pub struct MatchCompletion {
132 #[serde(rename = "uuid")]
133 pub player_uuid: Uuid,
134 pub time: Time,
135}
136
137#[cfg_attr(feature = "serialize", derive(Serialize))]
139#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
140#[serde(rename_all = "camelCase")]
141pub struct MatchTimelineEvent {
142 #[serde(rename = "uuid")]
143 pub player_uuid: Uuid,
144 pub time: Time,
145 #[serde(rename = "type")]
146 pub id: Box<str>,
147}
148impl MatchTimelineEvent {
149 pub fn id(&self) -> &str {
150 &self.id
151 }
152}
153
154#[cfg_attr(feature = "serialize", derive(Serialize))]
156#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
157#[serde(rename_all = "camelCase")]
158pub struct MatchInfo {
159 pub id: MatchId,
160 #[serde(rename = "type")]
161 pub kind: MatchType,
162 pub season: Season,
163 pub category: Option<MatchCategory>,
164 #[serde(with = "ts_seconds")]
165 pub date: DateTime<Utc>,
166 pub players: Box<[UserProfile]>,
167 pub spectators: Box<[UserProfile]>,
168 pub seed: Option<MatchSeedInfo>,
169 pub result: MatchOutcome,
170 pub forfeited: bool,
171 pub decayed: bool,
172 pub rank: MatchRank,
173 #[serde(rename = "changes")]
174 pub elo_updates: Box<[MatchEloUpdate]>,
175}
176impl MatchInfo {
177 pub fn players(&self) -> &[UserProfile] {
179 &self.players
180 }
181 pub fn spectators(&self) -> &[UserProfile] {
183 &self.spectators
184 }
185 pub fn elo_updates(&self) -> &[MatchEloUpdate] {
187 &self.elo_updates
188 }
189}
190
191#[cfg_attr(feature = "serialize", derive(Serialize))]
193#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
194#[serde(rename_all = "camelCase")]
195pub struct AdvancedMatchInfo {
196 #[serde(flatten)]
198 info: MatchInfo,
199 completions: Box<[MatchCompletion]>,
201 #[serde(rename = "timelines")]
202 timeline_events: Box<[MatchTimelineEvent]>,
204 #[serde(rename = "replayExist")]
205 replay_exists: bool,
206}
207impl AdvancedMatchInfo {
208 pub fn completions(&self) -> &[MatchCompletion] {
210 &self.completions
211 }
212 pub fn timeline_events(&self) -> &[MatchTimelineEvent] {
214 &self.timeline_events
215 }
216}