1use std::{
2 collections::HashMap,
3 fmt::{Display, Formatter},
4};
5
6use serde::{Deserialize, Serialize};
7use serde_tuple::{Deserialize_tuple, Serialize_tuple};
8
9use crate::{
10 maps::{
11 continents::{ContinentId, Dimensions},
12 MapId,
13 },
14 Endpoint, EndpointWithId,
15};
16
17pub type FloorId = i16;
18pub type RegionId = u8;
19pub type MasteryPointId = u16;
20pub type PointOfInterestId = u16;
21pub type GodShrineId = u8;
22pub type TaskId = u16;
23pub type SectorId = u16;
24
25#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)]
26pub struct ContinentFloorId {
27 pub continent: ContinentId,
28 pub floor: FloorId,
29}
30
31impl From<(ContinentId, FloorId)> for ContinentFloorId {
32 fn from(value: (ContinentId, FloorId)) -> Self {
33 Self {
34 continent: value.0,
35 floor: value.1,
36 }
37 }
38}
39
40impl Display for ContinentFloorId {
41 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
42 write!(f, "{}/floors/{}", self.continent, self.floor)
43 }
44}
45
46#[derive(Clone, Debug, PartialOrd, PartialEq, Serialize_tuple, Deserialize_tuple)]
47#[cfg_attr(test, serde(deny_unknown_fields))]
48pub struct Coordinates {
49 pub x: f32,
50 pub y: f32,
51}
52
53#[derive(Clone, Debug, PartialOrd, PartialEq, Serialize_tuple, Deserialize_tuple)]
54#[cfg_attr(test, serde(deny_unknown_fields))]
55pub struct ContinentRectangle {
56 pub top_left: Coordinates,
57 pub bottom_right: Coordinates,
58}
59
60#[derive(Clone, Debug, PartialOrd, PartialEq, Serialize_tuple, Deserialize_tuple)]
61#[cfg_attr(test, serde(deny_unknown_fields))]
62pub struct MapRectangle {
63 pub bottom_left: Coordinates,
64 pub top_right: Coordinates,
65}
66
67#[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Serialize, Deserialize)]
68#[serde(rename_all = "lowercase")]
69#[cfg_attr(test, serde(deny_unknown_fields))]
70pub enum PointOfInterestType {
71 Landmark,
72 Waypoint,
73 Vista,
74 Unlock,
75}
76
77#[derive(Clone, Debug, Serialize, Deserialize)]
78#[cfg_attr(test, serde(deny_unknown_fields))]
79pub struct PointOfInterest {
80 pub id: PointOfInterestId,
82 pub name: Option<String>,
84 #[serde(rename = "type")]
86 pub _type: PointOfInterestType,
87 pub floor: FloorId,
89 pub coord: Coordinates,
91 pub chat_link: String,
93 pub icon: Option<String>,
96}
97
98#[derive(Clone, Debug, Serialize, Deserialize)]
99#[cfg_attr(test, serde(deny_unknown_fields))]
100pub struct GodShrine {
101 pub id: GodShrineId,
103 pub name: String,
105 pub name_contested: String,
107 pub coord: Coordinates,
109 pub poi_id: PointOfInterestId,
111 pub icon: String,
113 pub icon_contested: String,
115}
116
117#[derive(Clone, Debug, Serialize, Deserialize)]
118#[cfg_attr(test, serde(deny_unknown_fields))]
119pub struct Task {
120 pub id: TaskId,
122 pub objective: String,
124 pub level: u8,
126 pub coord: Coordinates,
128 pub bounds: Vec<Coordinates>,
130 pub chat_link: String,
133}
134
135#[derive(Clone, Debug, Serialize, Deserialize)]
136#[cfg_attr(test, serde(deny_unknown_fields))]
137pub struct SkillChallenge {
138 pub id: Option<String>,
147 pub coord: Coordinates,
149}
150
151#[derive(Clone, Debug, Serialize, Deserialize)]
152#[cfg_attr(test, serde(deny_unknown_fields))]
153pub struct Sector {
154 pub id: SectorId,
156 pub name: Option<String>,
158 pub level: u8,
160 pub coord: Coordinates,
162 pub bounds: Vec<Coordinates>,
164 pub chat_link: String,
167}
168
169#[derive(Clone, Debug, Serialize, Deserialize)]
170#[cfg_attr(test, serde(deny_unknown_fields))]
171pub struct Adventure {
172 pub id: String,
174 pub name: String,
176 pub description: String,
178 pub coord: Coordinates,
180}
181
182#[derive(Clone, PartialEq, Eq, PartialOrd, Debug, Serialize, Deserialize)]
183#[cfg_attr(test, serde(deny_unknown_fields))]
184pub enum MasteryPointRegion {
185 Tyria,
187 Maguuma,
189 Desert,
191 Tundra,
193 Jade,
195 Sky,
197 #[serde(alias = "Unknown")]
199 Janthir,
200}
201
202#[derive(Clone, Debug, Serialize, Deserialize)]
203#[cfg_attr(test, serde(deny_unknown_fields))]
204pub struct MasteryPoint {
205 pub id: MasteryPointId,
207 pub region: MasteryPointRegion,
209 pub coord: Coordinates,
211}
212
213#[derive(Clone, Debug, Serialize, Deserialize)]
214#[cfg_attr(test, serde(deny_unknown_fields))]
215pub struct Map {
216 pub id: MapId,
218 pub name: String,
220 pub min_level: u8,
222 pub max_level: u8,
224 pub default_floor: FloorId,
226 pub label_coord: Option<Coordinates>,
228 pub map_rect: MapRectangle,
230 pub continent_rect: ContinentRectangle,
232 pub points_of_interest: HashMap<PointOfInterestId, PointOfInterest>,
235 pub god_shrines: Option<Vec<GodShrine>>,
236 pub tasks: HashMap<TaskId, Task>,
238 pub skill_challenges: Vec<SkillChallenge>,
240 pub sectors: HashMap<SectorId, Sector>,
242 pub adventures: Vec<Adventure>,
244 pub mastery_points: Vec<MasteryPoint>,
246}
247
248#[derive(Clone, Debug, Serialize, Deserialize)]
249#[cfg_attr(test, serde(deny_unknown_fields))]
250pub struct Region {
251 pub id: RegionId,
253 pub name: String,
255 pub label_coord: Coordinates,
257 pub continent_rect: ContinentRectangle,
259 pub maps: HashMap<MapId, Map>,
261}
262
263#[derive(Clone, Debug, Serialize, Deserialize)]
264#[cfg_attr(test, serde(deny_unknown_fields))]
265pub struct Floor {
266 pub id: FloorId,
267 pub texture_dims: Dimensions,
269 pub clamped_view: Option<ContinentRectangle>,
273 pub regions: HashMap<RegionId, Region>,
275}
276
277impl EndpointWithId for Floor {
278 type IdType = ContinentFloorId;
279
280 fn format_id(id: &Self::IdType) -> String {
281 id.to_string()
282 }
283}
284
285impl Endpoint for Floor {
286 const AUTHENTICATED: bool = false;
287 const LOCALE: bool = true;
288 const URL: &'static str = "v2/continents";
289 const VERSION: &'static str = "2023-03-31T00:00:00.000Z";
290}