use std::collections::HashMap; use std::cell::RefCell; use crate::common::serverstate::ClientId; use crate::ship::items; #[derive(Debug, Clone)] pub enum TradeItem { Individual(items::ClientItemId), Stacked(items::ClientItemId, usize), } impl TradeItem { pub fn stacked(&self) -> Option<(items::ClientItemId, usize)> { match self { TradeItem::Stacked(item_id, amount) => Some((*item_id, *amount)), _ => None } } pub fn stacked_mut(&mut self) -> Option<(items::ClientItemId, &mut usize)> { match self { TradeItem::Stacked(item_id, ref mut amount) => Some((*item_id, amount)), _ => None } } pub fn item_id(&self) -> items::ClientItemId { match self { TradeItem::Individual(item_id) => *item_id, TradeItem::Stacked(item_id, _) => *item_id, } } } #[derive(Debug, Clone, Eq, PartialEq)] pub enum TradeStatus { SentRequest, ReceivedRequest, Trading, Confirmed, FinalConfirm, ItemsChecked, TradeComplete, } #[derive(Debug, Clone)] pub struct ClientTradeState { client: ClientId, other_client: ClientId, pub items: Vec, pub meseta: usize, pub status: TradeStatus, } impl ClientTradeState { pub fn client(&self) -> ClientId { self.client } pub fn other_client(&self) -> ClientId { self.other_client } } #[derive(thiserror::Error, Debug)] #[error("")] pub enum TradeStateError { ClientNotInTrade(ClientId), MismatchedTrade(ClientId, ClientId), } #[derive(Default, Debug)] pub struct TradeState { trades: HashMap>, } impl TradeState { pub fn new_trade(&mut self, sender: &ClientId, receiver: &ClientId) { let state = ClientTradeState { client: *sender, other_client: *receiver, items: Default::default(), meseta: 0, status: TradeStatus::SentRequest, }; self.trades.insert(*sender, RefCell::new(state)); let state = ClientTradeState { client: *receiver, other_client: *sender, items: Default::default(), meseta: 0, status: TradeStatus::ReceivedRequest, }; self.trades.insert(*receiver, RefCell::new(state)); } pub fn in_trade(&self, client: &ClientId) -> bool { self.trades.contains_key(client) } pub fn with (&self, client: &ClientId, func: F) -> Result where F: Fn(&mut ClientTradeState, &mut ClientTradeState) -> T { let mut c1 = self.trades.get(client).ok_or(TradeStateError::ClientNotInTrade(*client))?.borrow_mut(); let mut c2 = self.trades.get(&c1.other_client).ok_or(TradeStateError::ClientNotInTrade(c1.other_client))?.borrow_mut(); // sanity check if c1.client != c2.other_client { return Err(TradeStateError::MismatchedTrade(c1.client, c2.client)); } Ok(func(&mut *c1, &mut *c2)) } // TODO: is it possible for this to not return Options? pub fn remove_trade(&mut self, client: &ClientId) -> (Option, Option) { let c1 = self.trades.remove(client).map(|c| c.into_inner()); let c2 = if let Some(ref state) = c1 { self.trades.remove(&state.other_client).map(|c| c.into_inner()) } else { None }; (c1, c2) } }