earthmc 2.0.5

Async client for interacting with the EarthMC API
Documentation
use std::collections::BTreeMap;

use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::model::{
    color::{RgbaColor, rgba_hex},
    location::WorldLocation,
    named_uuid::NamedUuid,
    timestamp::Timestamp,
};

#[derive(Clone, Deserialize, Serialize, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Nation {
    pub name: String,
    pub uuid: Uuid,
    pub board: Option<String>,
    #[serde(with = "rgba_hex")]
    pub dynmap_colour: RgbaColor,
    #[serde(with = "rgba_hex")]
    pub dynmap_outline: RgbaColor,
    pub wiki: Option<String>,
    #[serde(rename = "king")]
    pub leader: NamedUuid,
    pub capital: NamedUuid,
    pub timestamps: NationTimestamps,
    pub status: NationStatus,
    pub stats: NationStats,
    pub coordinates: NationCoordinates,
    pub residents: Vec<NamedUuid>,
    pub towns: Vec<NamedUuid>,
    pub allies: Vec<NamedUuid>,
    pub enemies: Vec<NamedUuid>,
    pub sanctioned: Vec<NamedUuid>,
    pub ranks: BTreeMap<NationRankKind, Vec<NamedUuid>>,
}

#[derive(Clone, Deserialize, Serialize, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct NationTimestamps {
    /// Creation time.
    #[cfg_attr(
        feature = "chrono",
        serde(with = "crate::model::timestamp::seconds")
    )]
    pub registered: Timestamp,
}

#[derive(Clone, Deserialize, Serialize, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct NationStatus {
    pub is_public: bool,
    /// Invite-less joining is enabled.
    pub is_open: bool,
    pub is_neutral: bool,
}

#[derive(Clone, Deserialize, Serialize, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct NationStats {
    pub num_town_blocks: i32,
    pub num_residents: i32,
    pub num_towns: i32,
    pub num_allies: i32,
    pub num_enemies: i32,
    /// Shown on `/n` in-game.
    pub balance: f64,
}

#[derive(Clone, Deserialize, Serialize, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct NationCoordinates {
    pub spawn: WorldLocation,
}

#[derive(
    Clone, Deserialize, Serialize, PartialEq, Eq, Hash, PartialOrd, Ord, Debug,
)]
#[serde(rename_all = "PascalCase")]
pub enum NationRankKind {
    Chancellor,
    Colonist,
    Diplomat,
    Treasurer,
    #[serde(untagged)]
    Other(String),
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;

    use serde_json::json;
    use uuid::Uuid;

    use super::Nation;
    use crate::model::{
        color::RgbaColor, location::WorldLocation, named_uuid::NamedUuid,
    };

    #[test]
    fn deserializes_dynmap_colours_from_rgba_hex_strings() {
        let nation: Nation = serde_json::from_value(json!({
            "name": "Test",
            "uuid": "00000000-0000-0000-0000-000000000000",
            "board": null,
            "dynmapColour": "11223344",
            "dynmapOutline": "aabbccdd",
            "wiki": null,
            "king": {
                "name": "Leader",
                "uuid": "00000000-0000-0000-0000-000000000000"
            },
            "capital": {
                "name": "Capital",
                "uuid": "00000000-0000-0000-0000-000000000000"
            },
            "timestamps": {
                "registered": 0
            },
            "status": {
                "isPublic": true,
                "isOpen": false,
                "isNeutral": true
            },
            "stats": {
                "numTownBlocks": 0,
                "numResidents": 0,
                "numTowns": 0,
                "numAllies": 0,
                "numEnemies": 0,
                "balance": 0.0
            },
            "coordinates": {
                "spawn": {
                    "world": "world",
                    "x": 0.0,
                    "y": 64.0,
                    "z": 0.0,
                    "pitch": 0.0,
                    "yaw": 0.0
                }
            },
            "residents": [],
            "towns": [],
            "allies": [],
            "enemies": [],
            "sanctioned": [],
            "ranks": {}
        }))
        .unwrap();

        assert_eq!(
            nation.dynmap_colour,
            RgbaColor::new(0x11, 0x22, 0x33, 0x44)
        );
        assert_eq!(
            nation.dynmap_outline,
            RgbaColor::new(0xaa, 0xbb, 0xcc, 0xdd)
        );
    }

    #[test]
    fn serializes_dynmap_colours_as_rgba_hex_strings() {
        let nation = Nation {
            name: "Test".to_string(),
            uuid: Uuid::nil(),
            board: None,
            dynmap_colour: RgbaColor::new(0x11, 0x22, 0x33, 0x44),
            dynmap_outline: RgbaColor::new(0xaa, 0xbb, 0xcc, 0xdd),
            wiki: None,
            leader: NamedUuid {
                name: "Leader".to_string(),
                uuid: Uuid::nil(),
            },
            capital: NamedUuid {
                name: "Capital".to_string(),
                uuid: Uuid::nil(),
            },
            timestamps: super::NationTimestamps { registered: 0 },
            status: super::NationStatus {
                is_public: true,
                is_open: false,
                is_neutral: true,
            },
            stats: super::NationStats {
                num_town_blocks: 0,
                num_residents: 0,
                num_towns: 0,
                num_allies: 0,
                num_enemies: 0,
                balance: 0.0,
            },
            coordinates: super::NationCoordinates {
                spawn: WorldLocation {
                    world: "world".to_string(),
                    x: 0.0,
                    y: 64.0,
                    z: 0.0,
                    pitch: 0.0,
                    yaw: 0.0,
                },
            },
            residents: vec![],
            towns: vec![],
            allies: vec![],
            enemies: vec![],
            sanctioned: vec![],
            ranks: BTreeMap::new(),
        };

        let value = serde_json::to_value(nation).unwrap();

        assert_eq!(value["dynmapColour"], "11223344");
        assert_eq!(value["dynmapOutline"], "aabbccdd");
    }
}