1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5pub use crate::game_mechanics::pets::PetId;
7use crate::{
8 game_mechanics::{skills::SkillId, specializations::SpecializationId, traits::TraitId},
9 items::{itemstats::StatsId, recipes::RecipeId, skins::SkinId, AttributeType, ItemId},
10 misc::{colors::ColorId, titles::TitleId},
11 pvp::amulets::AmuletId,
12 wvw::abilities::AbilityId,
13 BulkEndpoint, Endpoint, EndpointWithId, TimeStamp,
14};
15
16pub type Age = u64;
17pub type CharacterId = String;
18pub type BackStoryId = String;
19
20#[derive(Clone, Debug, Serialize, Deserialize)]
21#[cfg_attr(test, serde(deny_unknown_fields))]
22pub struct Backstory {
23 pub backstory: Vec<BackStoryId>,
24}
25
26#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
27#[cfg_attr(test, serde(deny_unknown_fields))]
28pub enum Race {
29 Asura,
30 Charr,
31 Human,
32 Norn,
33 Sylvari,
34}
35
36#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
37#[cfg_attr(test, serde(deny_unknown_fields))]
38pub enum Gender {
39 Male,
40 Female,
41}
42
43#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
44#[cfg_attr(test, serde(deny_unknown_fields))]
45pub enum Profession {
46 Elementalist,
47 Engineer,
48 Guardian,
49 Mesmer,
50 Necromancer,
51 Ranger,
52 Revenant,
53 Thief,
54 Warrior,
55}
56
57#[derive(Clone, Debug, Serialize, Deserialize)]
58#[cfg_attr(test, serde(deny_unknown_fields))]
59pub struct Core {
60 pub name: CharacterId,
61 pub race: Race,
62 pub gender: Gender,
63 pub profession: Profession,
64 pub level: u8,
65 pub guild: Option<String>,
66 pub age: Age,
67 pub created: TimeStamp,
68 pub last_modified: TimeStamp,
69 pub deaths: u32,
70 pub title: Option<TitleId>,
71}
72
73#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
74#[cfg_attr(test, serde(deny_unknown_fields))]
75pub enum Discipline {
76 Armorsmith,
77 Artificer,
78 Chef,
79 Huntsman,
80 Jeweler,
81 Leatherworker,
82 Scribe,
83 Tailor,
84 Weaponsmith,
85 Homesteader,
86}
87
88#[derive(Clone, Debug, Serialize, Deserialize)]
89#[cfg_attr(test, serde(deny_unknown_fields))]
90pub struct Craft {
91 pub discipline: Discipline,
92 pub rating: u16,
93 pub active: bool,
94}
95
96#[derive(Clone, Debug, Serialize, Deserialize)]
97#[cfg_attr(test, serde(deny_unknown_fields))]
98pub struct Crafting {
99 pub crafting: Vec<Craft>,
100}
101
102#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
103#[cfg_attr(test, serde(deny_unknown_fields))]
104pub enum Slot {
105 HelmAquatic,
106 Backpack,
107 Coat,
108 Boots,
109 Gloves,
110 Helm,
111 Leggings,
112 Shoulders,
113 Accessory1,
114 Accessory2,
115 Ring1,
116 Ring2,
117 Amulet,
118 WeaponAquaticA,
119 WeaponAquaticB,
120 WeaponA1,
121 WeaponA2,
122 WeaponB1,
123 WeaponB2,
124 Sickle,
125 Axe,
126 Pick,
127 FishingRod,
128 FishingBait,
129 FishingLure,
130 PowerCore,
131 SensoryArray,
132 ServiceChip,
133 Relic,
134}
135
136#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Eq)]
137#[cfg_attr(test, serde(deny_unknown_fields))]
138pub struct Stats {
139 pub id: StatsId,
140 pub attributes: HashMap<AttributeType, u16>,
141}
142
143#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Eq)]
144#[cfg_attr(test, serde(deny_unknown_fields))]
145pub enum Binding {
146 Character,
147 Account,
148}
149
150#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
151#[cfg_attr(test, serde(deny_unknown_fields))]
152pub enum Location {
153 Equipped,
154 Armory,
155 EquippedFromLegendaryArmory,
156 LegendaryArmory,
157}
158
159#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Eq)]
160#[cfg_attr(test, serde(deny_unknown_fields))]
161pub struct Equip {
162 pub id: ItemId,
163 pub slot: Option<Slot>,
164 pub count: Option<usize>,
166 pub infusions: Option<Vec<ItemId>>,
167 pub upgrades: Option<Vec<ItemId>>,
168 pub skin: Option<SkinId>,
169 pub stats: Option<Stats>,
170 pub binding: Option<Binding>,
171 pub location: Location,
172 pub charges: Option<u16>,
173 pub bound_to: Option<String>,
174 pub dyes: Option<Vec<Option<ColorId>>>,
175 pub tabs: Option<Vec<usize>>,
177}
178
179#[derive(Clone, Debug, Serialize, Deserialize)]
180#[cfg_attr(test, serde(deny_unknown_fields))]
181pub struct Equipment {
182 pub equipment: Vec<Equip>,
183}
184
185#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Eq)]
186#[cfg_attr(test, serde(deny_unknown_fields))]
187pub struct InventoryItem {
188 pub id: ItemId,
189 pub count: u8,
190 pub charges: Option<u8>,
191 pub infusions: Option<Vec<ItemId>>,
192 pub upgrades: Option<Vec<ItemId>>,
193 pub upgrade_slot_indices: Option<Vec<usize>>,
194 pub skin: Option<SkinId>,
195 pub stats: Option<Stats>,
196 pub binding: Option<Binding>,
197 pub bound_to: Option<String>,
198 pub dyes: Option<Vec<ColorId>>,
199}
200
201#[derive(Clone, Debug, Serialize, Deserialize)]
202#[cfg_attr(test, serde(deny_unknown_fields))]
203pub struct InventoryBag {
204 pub id: ItemId,
205 pub size: u8,
206 pub inventory: Vec<Option<InventoryItem>>,
207}
208
209#[derive(Clone, Debug, Serialize, Deserialize)]
210#[cfg_attr(test, serde(deny_unknown_fields))]
211pub struct Inventory {
212 pub bags: Vec<Option<InventoryBag>>,
213}
214
215pub type Utilities = [Option<SkillId>; 3];
216
217#[derive(Clone, Debug, Serialize, Deserialize)]
218#[cfg_attr(test, serde(deny_unknown_fields))]
219pub struct Skillset {
220 pub heal: Option<SkillId>,
221 pub utilities: Utilities,
222 pub elite: Option<SkillId>,
223 pub legends: Option<Vec<String>>,
225}
226
227#[derive(Clone, Debug, Serialize, Deserialize)]
228#[cfg_attr(test, serde(deny_unknown_fields))]
229pub struct SkillDataSet {
230 pub pve: Skillset,
231 pub pvp: Skillset,
232 pub wvw: Skillset,
233}
234
235pub type TraitSet = [Option<TraitId>; 3];
236
237#[derive(Clone, Debug, Serialize, Deserialize)]
238#[cfg_attr(test, serde(deny_unknown_fields))]
239pub struct TraitLine {
240 pub id: Option<SpecializationId>,
241 pub traits: Option<TraitSet>,
242}
243
244pub type Specialization = [Option<TraitLine>; 3];
245
246#[derive(Clone, Debug, Serialize, Deserialize)]
247#[cfg_attr(test, serde(deny_unknown_fields))]
248pub struct SpecializationSet {
249 pub pve: Specialization,
250 pub pvp: Specialization,
251 pub wvw: Specialization,
252}
253
254#[derive(Clone, Debug, Serialize, Deserialize)]
255#[cfg_attr(test, serde(deny_unknown_fields))]
256pub struct TrainingSet {
257 pub id: u64,
259 pub spent: u16,
260 pub done: bool,
261}
262
263#[derive(Clone, Debug, Serialize, Deserialize)]
264#[cfg_attr(test, serde(deny_unknown_fields))]
265pub struct Training {
266 pub training: Vec<TrainingSet>,
267}
268
269#[derive(Clone, Debug, Serialize, Deserialize)]
270#[cfg_attr(test, serde(deny_unknown_fields))]
271pub struct Recipes {
272 pub recipes: Vec<RecipeId>,
273}
274
275#[derive(Clone, Debug, Serialize, Deserialize)]
276#[cfg_attr(test, serde(deny_unknown_fields))]
277pub struct WvwAbility {
278 pub id: AbilityId,
279 pub rank: u8,
280}
281
282#[derive(Clone, Debug, Serialize, Deserialize)]
283#[cfg_attr(test, serde(deny_unknown_fields))]
284pub struct EquipmentPvp {
285 pub amulet: Option<AmuletId>,
286 pub rune: Option<ItemId>,
287 pub sigils: (
288 Option<ItemId>,
289 Option<ItemId>,
290 Option<ItemId>,
291 Option<ItemId>,
292 ),
293}
294
295#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
296#[cfg_attr(test, serde(deny_unknown_fields))]
297pub enum Flags {
298 Beta,
299}
300
301#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
302#[cfg_attr(test, serde(deny_unknown_fields))]
303pub struct BuildPets {
304 pub terrestrial: [Option<PetId>; 2],
305 pub aquatic: [Option<PetId>; 2],
306}
307
308#[derive(Clone, Debug, Serialize, Deserialize)]
309#[cfg_attr(test, serde(deny_unknown_fields))]
310pub struct BuildLegends {
311 pub legends: LegendSlots,
312 pub aquatic_legends: LegendSlots,
313}
314
315pub type LegendId = String;
316pub type LegendSlots = [Option<LegendId>; 2];
317
318#[derive(Clone, Debug, Serialize, Deserialize)]
319#[cfg_attr(test, serde(deny_unknown_fields))]
320pub struct BuildTemplate {
321 pub name: Option<String>,
322 pub profession: Option<Profession>,
323 pub specializations: [TraitLine; 3],
324 pub skills: Skillset,
325 pub aquatic_skills: Skillset,
326 pub pets: Option<BuildPets>,
327 pub legends: Option<LegendSlots>,
328 pub aquatic_legends: Option<LegendSlots>,
329}
330
331#[derive(Clone, Debug, Serialize, Deserialize)]
332#[cfg_attr(test, serde(deny_unknown_fields))]
333pub struct BuildTab {
334 pub tab: usize,
336 pub is_active: bool,
337 pub build: BuildTemplate,
338}
339
340#[derive(Clone, Debug, Serialize, Deserialize)]
341#[cfg_attr(test, serde(deny_unknown_fields))]
342pub struct EquipmentTab {
343 pub tab: usize,
345 pub name: String,
346 pub is_active: bool,
347 pub equipment: Vec<Equip>,
348 pub equipment_pvp: Option<EquipmentPvp>,
349}
350
351#[derive(Clone, Debug, Serialize, Deserialize)]
352#[cfg_attr(test, serde(deny_unknown_fields))]
353pub struct Character {
354 pub backstory: Vec<BackStoryId>,
355 #[serde(flatten)]
356 pub core: Core,
357 pub crafting: Vec<Craft>,
358 #[serde(default)]
359 pub equipment: Vec<Equip>,
360 #[serde(default)]
361 pub bags: Vec<Option<InventoryBag>>,
362 #[serde(default)]
363 pub recipes: Vec<RecipeId>,
364 #[serde(default)]
365 pub training: Vec<TrainingSet>,
366 #[serde(default)]
367 pub build_tabs: Vec<BuildTab>,
368 pub build_tabs_unlocked: Option<usize>,
369 pub active_build_tab: Option<usize>,
370 #[serde(default)]
371 pub equipment_tabs: Vec<EquipmentTab>,
372 pub equipment_tabs_unlocked: Option<usize>,
373 pub active_equipment_tab: Option<usize>,
374 #[serde(default)]
375 pub wvw_abilities: Vec<WvwAbility>,
376 pub flags: Vec<Flags>,
377}
378
379impl EndpointWithId for Character {
380 type IdType = CharacterId;
381}
382
383impl Endpoint for Character {
384 const AUTHENTICATED: bool = true;
385 const LOCALE: bool = false;
386 const URL: &'static str = "v2/characters";
387 const VERSION: &'static str = "2022-06-14T00:00:00.000Z";
388}
389
390impl BulkEndpoint for Character {
391 const ALL: bool = true;
392
393 fn id(&self) -> &Self::IdType {
394 &self.core.name
395 }
396}
397
398impl EndpointWithId for Core {
399 type IdType = CharacterId;
400
401 fn format_url(id: &str) -> String {
402 format!("{}/{}/core", Self::URL, id)
403 }
404}
405
406impl Endpoint for Core {
407 const AUTHENTICATED: bool = true;
408 const LOCALE: bool = false;
409 const URL: &'static str = "v2/characters";
410 const VERSION: &'static str = "2022-06-14T00:00:00.000Z";
411}
412
413impl EndpointWithId for Backstory {
414 type IdType = CharacterId;
415
416 fn format_url(id: &str) -> String {
417 format!("{}/{}/backstory", Self::URL, id)
418 }
419}
420
421impl Endpoint for Backstory {
422 const AUTHENTICATED: bool = true;
423 const LOCALE: bool = false;
424 const URL: &'static str = "v2/characters";
425 const VERSION: &'static str = "2022-06-14T00:00:00.000Z";
426}
427
428impl EndpointWithId for Crafting {
429 type IdType = CharacterId;
430
431 fn format_url(id: &str) -> String {
432 format!("{}/{}/crafting", Self::URL, id)
433 }
434}
435
436impl Endpoint for Crafting {
437 const AUTHENTICATED: bool = true;
438 const LOCALE: bool = false;
439 const URL: &'static str = "v2/characters";
440 const VERSION: &'static str = "2022-06-14T00:00:00.000Z";
441}
442
443impl EndpointWithId for Equipment {
444 type IdType = CharacterId;
445
446 fn format_url(id: &str) -> String {
447 format!("{}/{}/equipment", Self::URL, id)
448 }
449}
450
451impl Endpoint for Equipment {
452 const AUTHENTICATED: bool = true;
453 const LOCALE: bool = false;
454 const URL: &'static str = "v2/characters";
455 const VERSION: &'static str = "2022-06-14T00:00:00.000Z";
456}
457
458impl EndpointWithId for Inventory {
459 type IdType = CharacterId;
460
461 fn format_url(id: &str) -> String {
462 format!("{}/{}/inventory", Self::URL, id)
463 }
464}
465
466impl Endpoint for Inventory {
467 const AUTHENTICATED: bool = true;
468 const LOCALE: bool = false;
469 const URL: &'static str = "v2/characters";
470 const VERSION: &'static str = "2022-06-14T00:00:00.000Z";
471}
472
473impl EndpointWithId for Recipes {
474 type IdType = CharacterId;
475
476 fn format_url(id: &str) -> String {
477 format!("{}/{}/recipes", Self::URL, id)
478 }
479}
480
481impl Endpoint for Recipes {
482 const AUTHENTICATED: bool = true;
483 const LOCALE: bool = false;
484 const URL: &'static str = "v2/characters";
485 const VERSION: &'static str = "2022-06-14T00:00:00.000Z";
486}
487
488impl EndpointWithId for Training {
489 type IdType = CharacterId;
490
491 fn format_url(id: &str) -> String {
492 format!("{}/{}/training", Self::URL, id)
493 }
494}
495
496impl Endpoint for Training {
497 const AUTHENTICATED: bool = true;
498 const LOCALE: bool = false;
499 const URL: &'static str = "v2/characters";
500 const VERSION: &'static str = "2022-06-14T00:00:00.000Z";
501}