flatland3 0.2.32

Flatland3 terminal play client and account CLI
Documentation
//! List property deeds from character inventory (plan 40 P0).

use uuid::Uuid;

use crate::api::ControlPlaneClient;
use crate::config::SessionConfig;
use crate::inventory::{InventoryItem, InventoryOutput};

#[derive(Debug, clap::Subcommand)]
pub enum PlotCommand {
    /// List property deeds in character inventory
    Deeds {
        #[arg(long)]
        character_id: Option<Uuid>,
    },
}

pub async fn run(command: PlotCommand, json: bool) -> anyhow::Result<()> {
    match command {
        PlotCommand::Deeds { character_id } => list_deeds(character_id, json).await,
    }
}

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

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

    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 deeds: Vec<&InventoryItem> = inv
        .items
        .iter()
        .filter(|i| i.template_id == "property_deed")
        .collect();

    if json {
        let data = InventoryOutput {
            character_id: inv.character_id,
            items: deeds.into_iter().cloned().collect(),
        };
        println!(
            "{}",
            serde_json::to_string_pretty(&serde_json::json!({
                "ok": true,
                "data": data
            }))?
        );
    } else if deeds.is_empty() {
        println!(
            "No property deeds for {} — claim a plot in gfx (f on free property land).",
            inv.character_id
        );
    } else {
        println!("Property deeds for {}:", inv.character_id);
        for d in deeds {
            println!("  {} ({})", d.template_id, d.item_instance_id);
        }
        println!("Buy/sell plots in-game via claim mode (see docs/property-plots.md).");
    }
    Ok(())
}