flatland3 0.2.0

Flatland3 terminal play client and account CLI
use uuid::Uuid;

use crate::api::ControlPlaneClient;
use crate::config::SessionConfig;

#[derive(serde::Deserialize)]
struct CharacterList {
    characters: Vec<CharacterRow>,
}

#[derive(serde::Deserialize)]
struct CharacterRow {
    id: Uuid,
    #[serde(rename = "name")]
    _name: String,
}

#[derive(Debug, serde::Serialize)]
pub struct InventoryOutput {
    pub character_id: Uuid,
    pub items: Vec<InventoryItem>,
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct InventoryItem {
    pub item_instance_id: Uuid,
    pub template_id: String,
    pub quantity: i32,
}

pub async fn run(character_id: Option<Uuid>, json: bool) -> anyhow::Result<()> {
    let session = SessionConfig::load()?;
    let client = ControlPlaneClient::new(&session.api_base);

    let character_id = match character_id {
        Some(id) => id,
        None => {
            let list: CharacterList = client
                .get("/v1/characters", &session.session_token)
                .await?;
            list.characters
                .first()
                .map(|c| c.id)
                .ok_or_else(|| {
                    anyhow::anyhow!("no characters — run flatland3 auth register")
                })?
        }
    };

    #[derive(serde::Deserialize)]
    struct InventoryResponse {
        character_id: Uuid,
        items: Vec<InventoryItem>,
    }

    let inv: InventoryResponse = client
        .get(
            &format!("/v1/characters/{character_id}/inventory"),
            &session.session_token,
        )
        .await?;

    let output = InventoryOutput {
        character_id: inv.character_id,
        items: inv.items,
    };

    if json {
        println!(
            "{}",
            serde_json::to_string_pretty(&serde_json::json!({
                "ok": true,
                "data": output
            }))?
        );
    } else if output.items.is_empty() {
        println!("Inventory empty for character {}", output.character_id);
    } else {
        println!("Inventory for {}:", output.character_id);
        for item in &output.items {
            println!(
                "  {} x{} ({})",
                item.template_id, item.quantity, item.item_instance_id
            );
        }
    }
    Ok(())
}