You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
3.5 KiB
133 lines
3.5 KiB
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)
|
|
}
|
|
}
|