use crate::prelude::*;
pub struct CosmeticsGroup<'a> {
pub(crate) esi: &'a Esi,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PatternBlendMode {
Normal,
Subtract,
Exclusion,
Nested,
NestedInverted,
#[serde(other)]
Unrecognized,
}
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
#[allow(missing_docs)]
pub struct Vector3 {
pub x: f64,
pub y: f64,
pub z: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
#[allow(missing_docs)]
pub struct Vector4 {
pub w: f64,
pub x: f64,
pub y: f64,
pub z: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[allow(missing_docs)]
pub struct PatternProjection {
pub slot1: bool,
pub slot2: bool,
pub slot3: bool,
pub slot4: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
#[allow(missing_docs)]
pub struct PatternTransform {
pub position: Vector3,
pub rotation: Vector4,
pub scaling: Vector3,
}
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
#[allow(missing_docs)]
pub struct PatternConfiguration {
pub mirrored: bool,
pub projection: PatternProjection,
pub transform: PatternTransform,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[allow(missing_docs)]
pub struct NanocoatingComponent {
pub id: i64,
}
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
#[allow(missing_docs)]
pub struct PatternComponent {
pub configuration: PatternConfiguration,
pub id: i64,
}
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
#[serde(untagged)]
#[allow(missing_docs)]
pub enum SlotConfiguration {
Nanocoating { nanocoating: NanocoatingComponent },
Pattern { pattern: PatternComponent },
}
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
#[allow(missing_docs)]
pub struct SkinrSlot {
pub configuration: SlotConfiguration,
pub id: i64,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[allow(missing_docs)]
pub struct SkinrLayout {
pub pattern_blend_mode: PatternBlendMode,
pub slots: Vec<SkinrSlot>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[allow(missing_docs)]
pub struct SkinrTier {
pub level: i64,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[allow(missing_docs)]
pub struct Skinr {
pub creator_id: i64,
pub id: String,
pub layout: SkinrLayout,
pub line: Option<String>,
pub name: String,
pub ship_type_id: i64,
pub tier: SkinrTier,
}
impl CosmeticsGroup<'_> {
api_get!(
get_skinr,
"GetCosmeticsSkinr",
RequestType::Public,
Skinr,
(skinr_id: &str) => "{skinr_id}"
);
}
#[cfg(test)]
mod tests {
use super::{Skinr, SlotConfiguration};
use serde_json::json;
#[test]
fn test_parse_skinr_with_both_slot_kinds() {
let vec3 = json!({"x": 0.0, "y": 0.0, "z": 0.0});
let value = json!({
"creator_id": 2_112_000_000_i64,
"id": "abc",
"name": "Design",
"ship_type_id": 587,
"tier": {"level": 2},
"layout": {
"pattern_blend_mode": "nested_inverted",
"slots": [
{"id": 1, "configuration": {"nanocoating": {"id": 10}}},
{"id": 2, "configuration": {"pattern": {
"id": 20,
"configuration": {
"mirrored": false,
"projection": {
"slot1": true, "slot2": false, "slot3": false, "slot4": false
},
"transform": {
"position": vec3,
"scaling": vec3,
"rotation": {"w": 1.0, "x": 0.0, "y": 0.0, "z": 0.0}
}
}
}}}
]
}
});
let skinr: Skinr = serde_json::from_value(value).unwrap();
assert!(skinr.line.is_none());
assert!(matches!(
skinr.layout.slots[0].configuration,
SlotConfiguration::Nanocoating { .. }
));
assert!(matches!(
skinr.layout.slots[1].configuration,
SlotConfiguration::Pattern { .. }
));
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct CharacterSkinrLicense {
pub activated: bool,
pub skinr_id: String,
pub unactivated: i64,
}
#[derive(Debug, Deserialize)]
struct SkinrLicenses {
licenses: Vec<CharacterSkinrLicense>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum SkinrComponentType {
Nanocoating,
Pattern,
#[serde(other)]
Unrecognized,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct ComponentRuns {
pub remaining: Option<i64>,
pub unlimited: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[allow(missing_docs)]
pub struct SkinrComponentLicense {
pub component_id: i64,
pub runs: ComponentRuns,
#[serde(rename = "type")]
pub component_type: SkinrComponentType,
}
#[derive(Debug, Deserialize)]
struct SkinrComponentLicenses {
licenses: Vec<SkinrComponentLicense>,
}
impl CosmeticsGroup<'_> {
pub async fn get_character_skinr(
&self,
character_id: i64,
) -> EsiResult<Vec<CharacterSkinrLicense>> {
let path = self
.esi
.get_endpoint_for_op_id("GetCharactersCosmeticsSkinr")?
.replace("{character_id}", &character_id.to_string());
let wrapper: SkinrLicenses = self
.esi
.query("GET", RequestType::Authenticated, &path, None, None)
.await?;
Ok(wrapper.licenses)
}
pub async fn get_character_skinr_components(
&self,
character_id: i64,
) -> EsiResult<Vec<SkinrComponentLicense>> {
let path = self
.esi
.get_endpoint_for_op_id("GetCharactersCosmeticsSkinrComponents")?
.replace("{character_id}", &character_id.to_string());
let wrapper: SkinrComponentLicenses = self
.esi
.query("GET", RequestType::Authenticated, &path, None, None)
.await?;
Ok(wrapper.licenses)
}
}
#[cfg(test)]
mod license_tests {
use super::*;
#[test]
fn test_parse_component_licenses() {
let w: SkinrComponentLicenses = serde_json::from_str(
r#"{"licenses":[{"component_id":1,"type":"pattern","runs":{"unlimited":true}},
{"component_id":2,"type":"x","runs":{"remaining":3}}]}"#,
)
.unwrap();
assert_eq!(w.licenses[0].runs.unlimited, Some(true));
assert_eq!(w.licenses[1].runs.remaining, Some(3));
assert_eq!(
w.licenses[1].component_type,
SkinrComponentType::Unrecognized
);
}
}