|
|
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<TradeItem>,
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<ClientId, RefCell<ClientTradeState>>,
}
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<T, F> (&self, client: &ClientId, func: F) -> Result<T, TradeStateError>
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<ClientTradeState>, Option<ClientTradeState>) {
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)
}
}
|