Skip to main content

roblox_api/api/avatar/
v1.rs

1use serde::{Deserialize, Serialize};
2use strum_macros::{Display, EnumString, FromRepr};
3
4use crate::{Paging, endpoint};
5
6pub const URL: &str = "https://avatar.roblox.com/v1";
7
8pub type ColorId = u8;
9
10#[repr(u8)]
11#[derive(
12    Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Display, EnumString, FromRepr,
13)]
14pub enum AvatarType {
15    R6 = 1,
16    R15 = 2,
17}
18
19#[repr(u8)]
20#[derive(
21    Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Display, EnumString, FromRepr,
22)]
23pub enum MorphAvatarType {
24    MorphR6 = 1,
25    MorphR15 = 2,
26}
27
28#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
29#[serde(rename_all = "camelCase")]
30pub struct AvatarScales {
31    pub height: f32,
32    pub width: f32,
33    pub head: f32,
34    pub depth: f32,
35    pub proportion: f32,
36    pub body_type: f32,
37}
38
39#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
40pub struct BodyColors {
41    #[serde(rename = "headColorId")]
42    pub head: ColorId,
43    #[serde(rename = "torsoColorId")]
44    pub torso: ColorId,
45    #[serde(rename = "rightArmColorId")]
46    pub right_arm: ColorId,
47    #[serde(rename = "leftArmColorId")]
48    pub left_arm: ColorId,
49    #[serde(rename = "rightLegColorId")]
50    pub right_leg: ColorId,
51    #[serde(rename = "leftLegColorId")]
52    pub left_leg: ColorId,
53}
54
55#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
56pub struct AssetType {
57    pub id: u8,
58    pub name: String,
59}
60
61#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
62pub struct AssetMeta {
63    pub version: u8,
64
65    pub order: u16,
66    pub puffiness: Option<f32>,
67}
68
69#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
70#[serde(rename_all = "camelCase")]
71pub struct Asset {
72    pub id: u64,
73    pub name: String,
74    #[serde(rename = "assetType")]
75    pub kind: AssetType,
76    pub current_version_id: u64,
77    pub meta: Option<AssetMeta>,
78}
79
80#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
81#[serde(rename_all = "camelCase")]
82pub struct Emote {
83    #[serde(rename = "assetId")]
84    pub id: u64,
85    #[serde(rename = "assetName")]
86    pub name: String,
87    pub position: u8,
88}
89
90#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
91#[serde(rename_all = "camelCase")]
92pub struct Outfit {
93    pub id: u64,
94    pub name: String,
95    pub is_editable: bool,
96    pub outfit_type: Option<()>,
97}
98
99#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
100#[serde(rename_all = "camelCase")]
101pub struct AvatarResponse {
102    #[serde(rename = "playerAvatarType")]
103    pub kind: AvatarType,
104    pub assets: Vec<Asset>,
105    pub scales: AvatarScales,
106    pub body_colors: BodyColors,
107    pub default_pants_applied: bool,
108    pub default_shirt_applied: bool,
109    pub emotes: Vec<Emote>,
110}
111
112#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
113#[serde(rename_all = "camelCase")]
114pub struct OutfitsResponse {
115    #[serde(rename = "data")]
116    pub outfits: Vec<Outfit>,
117    pub total: u64,
118    pub filtered_count: u64,
119}
120
121#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
122#[serde(rename_all = "camelCase")]
123pub struct OutfitDetails {
124    pub id: u64,
125    pub name: String,
126    pub universe_id: u64,
127    pub assets: Vec<Asset>,
128    pub body_colors: BodyColors,
129    #[serde(rename = "scale")]
130    pub scales: AvatarScales,
131    #[serde(rename = "playerAvatarType")]
132    pub avatar_type: AvatarType,
133    pub outfit_type: String,
134    pub is_editable: bool,
135    pub moderation_status: Option<String>,
136}
137
138#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
139#[serde(rename_all = "camelCase")]
140pub struct UniverseAvatarSettings {
141    #[serde(rename = "gameAvatarType")]
142    pub avatar_type: MorphAvatarType,
143    pub avatar_body_type: String,
144    pub avatar_collision_type: String,
145    pub joint_positioning_type: String,
146
147    pub avatar_min_scales: AvatarScales,
148    pub avatar_max_scales: AvatarScales,
149    pub avatar_asset_overrides: Vec<Option<()>>,
150
151    pub message: String,
152    pub moderation_status: Option<String>,
153
154    pub allow_custom_animations: String,
155}
156
157endpoint! {
158    /// Returns details about a specified user's avatar
159    user_avatar(id: u64) -> AvatarResponse {
160        GET "{URL}/users/{id}/avatar";
161    }
162
163    /// Gets a list of asset ids that the user is currently wearing
164    user_currently_wearing(id: u64) -> Vec<u64> {
165        GET "{URL}/users/{id}/currently-wearing";
166        types {
167            Response {
168                ids("assetIds"): Vec<u64>,
169            }
170        }
171        map |r: Response| r.ids
172    }
173
174    /// Sets the avatar's current assets to the list - Flagged as obsolete, does not support layered clothing meta params.
175    ///
176    /// Warning: Deprecated
177    /// Only allows items that you own, are not expired, and are wearable asset types.
178    /// Any assets being worn before this method is called are automatically removed.
179    avatar_set_wearing_assets(assets: Vec<u64>) -> bool {
180        POST "{URL}/avatar/set-wearing-assets";
181        types {
182            Request<'a> {
183                asset_ids("assetIds"): &'a [u64],
184            }
185            Response {
186                success: bool,
187            }
188        }
189        body_serialize {
190            &Request { asset_ids: &assets }
191        }
192        map |r: Response| r.success
193    }
194
195    /// Sets the authenticated user's player avatar type (e.g. R6 or R15).
196    avatar_set_type(kind: AvatarType) -> bool {
197        POST "{URL}/avatar/set-player-avatar-type";
198        types {
199            Request {
200                avatar_type("playerAvatarType"): AvatarType,
201            }
202            Response {
203                success: bool,
204            }
205        }
206        body_serialize {
207            &Request { avatar_type: kind }
208        }
209        map |r: Response| r.success
210    }
211
212    /// Sets the authenticated user's body colors.
213    avatar_set_body_colors(colors: BodyColors) -> bool {
214        POST "{URL}/avatar/set-body-colors";
215        types {
216            Response {
217                success: bool,
218            }
219        }
220        body_serialize {
221            &colors
222        }
223        map |r: Response| r.success
224    }
225
226    /// Sets the authenticated user's body scales.
227    avatar_set_scales(scales: AvatarScales) -> bool {
228        POST "{URL}/avatar/set-scales";
229        types {
230            Response {
231                success: bool,
232            }
233        }
234        body_serialize {
235            &scales
236        }
237        map |r: Response| r.success
238    }
239
240    /// Deprecated, use v2. Gets a list of outfits for the specified user.
241    user_outfits(
242        id: u64, paging: Paging<'_>, is_editable: Option<bool>
243    ) -> OutfitsResponse {
244        GET "{URL}/users/{id}/outfits";
245        prelude {
246            let limit = paging.limit.unwrap_or(25).to_string();
247            let cursor = paging.cursor.unwrap_or("1");
248            let is_editable = match is_editable {
249                Some(editable) => editable.to_string(),
250                None => String::new(),
251            };
252        }
253        query {
254            "page" => cursor,
255            "itemsPerPage" => &limit,
256            "isEditable" => &is_editable,
257        }
258    }
259
260    /// Gets details about the contents of an outfit.
261    outfit_details(id: u64) -> OutfitDetails {
262        GET "{URL}/outfits/{id}/details";
263    }
264
265    /// Deletes the outfit.
266    remove_outfit(id: u64) -> bool {
267        POST "{URL}/outfits/{id}/delete";
268        types {
269            Response {
270                success: bool,
271            }
272        }
273        map |r: Response| r.success
274    }
275
276    /// The server will call this on game server start to request general information about the universe.
277    /// This is version 1.1, which returns an entry from the UniverseAvatarType enum.
278    /// During mixed mode this may return unreliable results
279    universe_avatar_settings(id: u64) -> UniverseAvatarSettings {
280        GET "{URL}/users/{id}/avatar";
281    }
282}