chunkedge_protocol/
profile.rs

1use base64::prelude::*;
2use chunkedge_binary::{Decode, Encode};
3use serde::{Deserialize, Serialize};
4use url::Url;
5
6/// A property from the game profile.
7#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode)]
8pub struct Property<S = String> {
9    pub name: S,
10    pub value: S,
11    pub signature: Option<S>,
12}
13
14/// Contains URLs to the skin and cape of a player.
15#[derive(Clone, PartialEq, Eq, Debug)]
16pub struct PlayerTextures {
17    /// URL to the player's skin texture.
18    pub skin: Url,
19    /// URL to the player's cape texture. May be absent if the player does not
20    /// have a cape.
21    pub cape: Option<Url>,
22}
23
24impl PlayerTextures {
25    /// Constructs player textures from the "textures" property of the game
26    /// profile.
27    ///
28    /// "textures" is a base64 string of JSON data.
29    pub fn try_from_textures(textures: &str) -> anyhow::Result<Self> {
30        #[derive(Debug, Deserialize)]
31        struct Textures {
32            textures: PlayerTexturesPayload,
33        }
34
35        #[derive(Debug, Deserialize)]
36        #[serde(rename_all = "UPPERCASE")]
37        struct PlayerTexturesPayload {
38            skin: TextureUrl,
39            #[serde(default)]
40            cape: Option<TextureUrl>,
41        }
42
43        #[derive(Debug, Deserialize)]
44        struct TextureUrl {
45            url: Url,
46        }
47
48        let decoded = BASE64_STANDARD.decode(textures.as_bytes())?;
49
50        let Textures { textures } = serde_json::from_slice(&decoded)?;
51
52        Ok(Self {
53            skin: textures.skin.url,
54            cape: textures.cape.map(|t| t.url),
55        })
56    }
57}