This commit is contained in:
parent
98260308e8
commit
b80f30ef9d
@ -960,6 +960,125 @@ impl ItemManager {
|
|||||||
Ok(weapon)
|
Ok(weapon)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn trade_items<EG: EntityGateway>(&mut self,
|
||||||
|
entity_gateway: &mut EG,
|
||||||
|
p1: (&AreaClient, &CharacterEntity, &Vec<TradeItem>),
|
||||||
|
p2: (&AreaClient, &CharacterEntity, &Vec<TradeItem>))
|
||||||
|
-> Result<Vec<ItemToTrade>, anyhow::Error> {
|
||||||
|
let it = ItemTransaction::new(&self, (p1, p2))
|
||||||
|
.act(|it, (p1, p2)| -> Result<_, anyhow::Error> {
|
||||||
|
let p1_inventory = it.manager.get_character_inventory(p1.1)?;
|
||||||
|
let p2_inventory = it.manager.get_character_inventory(p2.1)?;
|
||||||
|
|
||||||
|
//TODO: inv-selftrade+othertrade <= 30
|
||||||
|
//if p1_inventory
|
||||||
|
|
||||||
|
let trade_items = [(p1, p2, p1_inventory), (p2, p1, p2_inventory)]
|
||||||
|
.map(|((src_client, dest_client, src_inventory))| {
|
||||||
|
src_client.2.iter()
|
||||||
|
.map(|item| -> Option<(Option<ItemToTrade>, Vec<Box<dyn ItemAction<EG>>>)> {
|
||||||
|
match item {
|
||||||
|
TradeItem::Individual(item_id) => {
|
||||||
|
let item = src_inventory.get_item_by_id(*item_id)?.individual()?;
|
||||||
|
Some((
|
||||||
|
Some(ItemToTrade {
|
||||||
|
add_to: *dest_client.0,
|
||||||
|
remove_from: *src_client.0,
|
||||||
|
item_id: *item_id,
|
||||||
|
item_detail: ItemToTradeDetail::Individual(item.item.clone())
|
||||||
|
}),
|
||||||
|
vec![
|
||||||
|
Box::new(AddIndividualItemToInventory {
|
||||||
|
character_id: dest_client.1.id,
|
||||||
|
item_id: item.entity_id,
|
||||||
|
}),
|
||||||
|
Box::new(RemoveIndividualItemFromInventory {
|
||||||
|
character_id: src_client.1.id,
|
||||||
|
item_id: item.entity_id,
|
||||||
|
})
|
||||||
|
]
|
||||||
|
))
|
||||||
|
},
|
||||||
|
TradeItem::Stacked(item_id, amount) => {
|
||||||
|
let item = src_inventory.get_item_by_id(*item_id)?.stacked()?;
|
||||||
|
if item.count() < *amount {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Some((
|
||||||
|
Some(ItemToTrade {
|
||||||
|
add_to: *dest_client.0,
|
||||||
|
remove_from: *src_client.0,
|
||||||
|
item_id: *item_id,
|
||||||
|
item_detail: ItemToTradeDetail::Stacked(item.tool, *amount)
|
||||||
|
}),
|
||||||
|
vec![
|
||||||
|
Box::new(AddStackedItemToInventory {
|
||||||
|
character_id: dest_client.1.id,
|
||||||
|
item_ids: item.entity_ids.iter().cloned().take(*amount).collect(),
|
||||||
|
}),
|
||||||
|
Box::new(RemoveStackedItemFromInventory {
|
||||||
|
character_id: src_client.1.id,
|
||||||
|
item_ids: item.entity_ids.iter().cloned().take(*amount).collect(),
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TradeItem::Meseta(amount) => {
|
||||||
|
Some((None,
|
||||||
|
vec![
|
||||||
|
Box::new(AddMesetaToInventory {
|
||||||
|
character_id: dest_client.1.id,
|
||||||
|
amount: *amount,
|
||||||
|
}),
|
||||||
|
Box::new(RemoveMesetaFromInventory {
|
||||||
|
character_id: src_client.1.id,
|
||||||
|
amount: *amount,
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Option<Vec<_>>>()
|
||||||
|
});
|
||||||
|
|
||||||
|
if let [Some(p1_trades), Some(p2_trades)] = trade_items {
|
||||||
|
let (p1_item_trades, p1_item_actions): (Vec<Option<ItemToTrade>>, Vec<Vec<Box<dyn ItemAction<EG>>>>) = p1_trades.into_iter().unzip();
|
||||||
|
let (p2_item_trades, p2_item_actions): (Vec<Option<ItemToTrade>>, Vec<Vec<Box<dyn ItemAction<EG>>>>) = p2_trades.into_iter().unzip();
|
||||||
|
let item_trades = p1_item_trades.into_iter().flatten().chain(p2_item_trades.into_iter().flatten());
|
||||||
|
let item_actions = p1_item_actions.into_iter().flatten().chain(p2_item_actions.into_iter().flatten());
|
||||||
|
|
||||||
|
for action in item_actions {
|
||||||
|
it.action(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(item_trades.collect())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(ItemManagerError::InvalidTrade.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
it.commit(self, entity_gateway)
|
||||||
|
.await
|
||||||
|
.map_err(|err| err.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ItemToTradeDetail {
|
||||||
|
Individual(ItemDetail),
|
||||||
|
Stacked(Tool, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ItemToTrade {
|
||||||
|
pub add_to: AreaClient,
|
||||||
|
pub remove_from: AreaClient,
|
||||||
|
pub item_id: ClientItemId,
|
||||||
|
pub item_detail: ItemToTradeDetail,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct RemoveFromLocalFloor {
|
struct RemoveFromLocalFloor {
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
@ -1050,3 +1169,76 @@ impl<EG: EntityGateway> ItemAction<EG> for AddMesetaFloorItemToInventory {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct AddIndividualItemToInventory {
|
||||||
|
character_id: CharacterEntityId,
|
||||||
|
item_id: ItemEntityId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<EG: EntityGateway> ItemAction<EG> for AddIndividualItemToInventory {
|
||||||
|
async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AddStackedItemToInventory {
|
||||||
|
character_id: CharacterEntityId,
|
||||||
|
item_ids: Vec<ItemEntityId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<EG: EntityGateway> ItemAction<EG> for AddStackedItemToInventory {
|
||||||
|
async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RemoveIndividualItemFromInventory {
|
||||||
|
character_id: CharacterEntityId,
|
||||||
|
item_id: ItemEntityId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<EG: EntityGateway> ItemAction<EG> for RemoveIndividualItemFromInventory {
|
||||||
|
async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RemoveStackedItemFromInventory {
|
||||||
|
character_id: CharacterEntityId,
|
||||||
|
item_ids: Vec<ItemEntityId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<EG: EntityGateway> ItemAction<EG> for RemoveStackedItemFromInventory {
|
||||||
|
async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AddMesetaToInventory {
|
||||||
|
character_id: CharacterEntityId,
|
||||||
|
amount: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<EG: EntityGateway> ItemAction<EG> for AddMesetaToInventory {
|
||||||
|
async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RemoveMesetaFromInventory {
|
||||||
|
character_id: CharacterEntityId,
|
||||||
|
amount: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<EG: EntityGateway> ItemAction<EG> for RemoveMesetaFromInventory {
|
||||||
|
async fn commit(&self, _item_manager: &mut ItemManager, entity_gateway: &mut EG) -> Result<(), TransactionCommitError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -27,6 +27,7 @@ pub fn item_drop(client: u8, target: u8, item_drop: &FloorItem) -> Result<ItemDr
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this doesn't need to be a Result, just unwrap try_intos they are guaranteed to succeed
|
||||||
pub fn create_individual_item(area_client: AreaClient, item_id: ClientItemId, item: &item::ItemDetail) -> Result<CreateItem, ShipError> {
|
pub fn create_individual_item(area_client: AreaClient, item_id: ClientItemId, item: &item::ItemDetail) -> Result<CreateItem, ShipError> {
|
||||||
let bytes = item.as_client_bytes();
|
let bytes = item.as_client_bytes();
|
||||||
Ok(CreateItem {
|
Ok(CreateItem {
|
||||||
@ -39,6 +40,7 @@ pub fn create_individual_item(area_client: AreaClient, item_id: ClientItemId, it
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this doesn't need to be a Result, just unwrap try_intos they are guaranteed to succeed
|
||||||
pub fn create_stacked_item(area_client: AreaClient, item_id: ClientItemId, tool: &item::tool::Tool, amount: usize) -> Result<CreateItem, ShipError> {
|
pub fn create_stacked_item(area_client: AreaClient, item_id: ClientItemId, tool: &item::tool::Tool, amount: usize) -> Result<CreateItem, ShipError> {
|
||||||
let bytes = tool.as_stacked_bytes(amount);
|
let bytes = tool.as_stacked_bytes(amount);
|
||||||
Ok(CreateItem {
|
Ok(CreateItem {
|
||||||
|
@ -9,7 +9,7 @@ use crate::common::serverstate::ClientId;
|
|||||||
use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms, ItemShops, TradeItem, TradeState, TradeStatus};
|
use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms, ItemShops, TradeItem, TradeState, TradeStatus};
|
||||||
use crate::ship::location::{ClientLocation, ClientLocationError};
|
use crate::ship::location::{ClientLocation, ClientLocationError};
|
||||||
use crate::ship::drops::ItemDrop;
|
use crate::ship::drops::ItemDrop;
|
||||||
use crate::ship::items::{ItemManager, ItemManagerError, ClientItemId, TriggerCreateItem, FloorItem, FloorType};
|
use crate::ship::items::{ItemManager, ItemManagerError, ClientItemId, TriggerCreateItem, FloorItem, FloorType, ItemToTradeDetail};
|
||||||
use crate::ship::items::inventory::InventoryItem;
|
use crate::ship::items::inventory::InventoryItem;
|
||||||
use crate::entity::gateway::EntityGateway;
|
use crate::entity::gateway::EntityGateway;
|
||||||
use crate::entity::item;
|
use crate::entity::item;
|
||||||
@ -125,7 +125,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function is a shitshow due to not thinking of what would happen if I needed more than 1 client at a time
|
|
||||||
pub async fn trade_confirmed<EG>(id: ClientId,
|
pub async fn trade_confirmed<EG>(id: ClientId,
|
||||||
entity_gateway: &mut EG,
|
entity_gateway: &mut EG,
|
||||||
client_location: &ClientLocation,
|
client_location: &ClientLocation,
|
||||||
@ -135,47 +134,76 @@ pub async fn trade_confirmed<EG>(id: ClientId,
|
|||||||
where
|
where
|
||||||
EG: EntityGateway
|
EG: EntityGateway
|
||||||
{
|
{
|
||||||
let (this_client_confirmed, other_client_id) = {
|
|
||||||
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
|
||||||
(client.confirmed_trade, client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?.0)
|
|
||||||
};
|
|
||||||
let other_client_confirmed = {
|
|
||||||
let client = clients.get(&other_client_id).ok_or(ShipError::ClientNotFound(id))?;
|
|
||||||
client.confirmed_trade
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let this_client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
let this_client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||||
this_client.confirmed_trade = true;
|
this_client.trade.as_mut().ok_or(TradeError::NotInTradeMenu)?.status = TradeStatus::Confirmed;
|
||||||
}
|
}
|
||||||
|
|
||||||
let both_confirmed = {
|
let both_confirmed = {
|
||||||
let this_client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
let this_client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||||
let other_client = clients.get(&other_client_id).ok_or(ShipError::ClientNotFound(id))?;
|
let other_client_id = this_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?.other_client;
|
||||||
this_client.confirmed_trade && other_client.confirmed_trade
|
let other_client = clients.get(&other_client_id).ok_or(ShipError::ClientNotFound(other_client_id))?;
|
||||||
|
|
||||||
|
let this_client_trade = this_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?;
|
||||||
|
let other_client_trade = other_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?;
|
||||||
|
this_client_trade.status == TradeStatus::Confirmed && other_client_trade.status == TradeStatus::Confirmed
|
||||||
};
|
};
|
||||||
|
|
||||||
if both_confirmed {
|
if both_confirmed {
|
||||||
{
|
let this_client_trade = {
|
||||||
let this_client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
|
||||||
let other_client = clients.get(&other_client_id).ok_or(ShipError::ClientNotFound(id))?;
|
|
||||||
|
|
||||||
let this_character_items = &this_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?.1;
|
|
||||||
item_manager.send_items_to_other_player(entity_gateway, &this_client.character, &other_client.character, this_character_items).await?;
|
|
||||||
|
|
||||||
let other_character_items = &other_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?.1;
|
|
||||||
item_manager.send_items_to_other_player(entity_gateway, &other_client.character, &this_client.character, other_character_items).await?;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let this_client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
let this_client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||||
|
let this_client_trade = this_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?.clone();
|
||||||
this_client.trade = None;
|
this_client.trade = None;
|
||||||
}
|
this_client_trade
|
||||||
{
|
};
|
||||||
let other_client = clients.get_mut(&other_client_id).ok_or(ShipError::ClientNotFound(id))?;
|
let other_client_trade = {
|
||||||
|
let other_client = clients.get_mut(&this_client_trade.other_client).ok_or(ShipError::ClientNotFound(this_client_trade.other_client))?;
|
||||||
|
let other_client_trade = other_client.trade.as_ref().ok_or(TradeError::NotInTradeMenu)?.clone();
|
||||||
other_client.trade = None;
|
other_client.trade = None;
|
||||||
}
|
other_client_trade
|
||||||
|
};
|
||||||
|
let this_client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||||
|
let other_client = clients.get(&this_client_trade.other_client).ok_or(ShipError::ClientNotFound(this_client_trade.other_client))?;
|
||||||
|
|
||||||
Ok(Box::new(None.into_iter()))
|
let this_local_client = client_location.get_local_client(id)?;
|
||||||
|
let other_local_client = client_location.get_local_client(this_client_trade.other_client)?;
|
||||||
|
|
||||||
|
let traded_items = item_manager.trade_items(
|
||||||
|
entity_gateway,
|
||||||
|
(&this_local_client, &this_client.character, &this_client_trade.items),
|
||||||
|
(&other_local_client, &other_client.character, &other_client_trade.items)
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
let clients_in_room = client_location.get_all_clients_by_client(id)?;
|
||||||
|
let traded_item_packets = traded_items
|
||||||
|
.into_iter()
|
||||||
|
.map(|item| {
|
||||||
|
match item.item_detail {
|
||||||
|
ItemToTradeDetail::Individual(item_detail) => {
|
||||||
|
[
|
||||||
|
GameMessage::CreateItem(builder::message::create_individual_item(item.add_to, item.item_id, &item_detail).unwrap()),
|
||||||
|
GameMessage::PlayerNoLongerHasItem(builder::message::player_no_longer_has_item(item.remove_from, item.item_id, 1)) // TODO: amount = ?
|
||||||
|
]
|
||||||
|
},
|
||||||
|
ItemToTradeDetail::Stacked(tool, amount) => {
|
||||||
|
[
|
||||||
|
GameMessage::CreateItem(builder::message::create_stacked_item(item.add_to, item.item_id, &tool, amount).unwrap()),
|
||||||
|
GameMessage::PlayerNoLongerHasItem(builder::message::player_no_longer_has_item(item.remove_from, item.item_id, amount as u32))
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.map(move |packet| {
|
||||||
|
clients_in_room
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.map(move |client| {
|
||||||
|
(client.client, SendShipPacket::Message(Message::new(packet.clone())))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.flatten();
|
||||||
|
Ok(Box::new(traded_item_packets))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Ok(Box::new(None.into_iter()))
|
Ok(Box::new(None.into_iter()))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user