jake
4 years ago
7 changed files with 288 additions and 13 deletions
-
63src/entity/gateway/postgres/models.rs
-
5src/entity/item/mod.rs
-
18src/ship/items/manager.rs
-
0src/ship/packet/builder/trade.rs
-
1src/ship/packet/handler/mod.rs
-
181src/ship/packet/handler/trade.rs
-
31src/ship/ship.rs
@ -0,0 +1,181 @@ |
|||||
|
use std::convert::TryInto;
|
||||
|
use log::warn;
|
||||
|
use rand::Rng;
|
||||
|
use rand::seq::SliceRandom;
|
||||
|
use libpso::packet::ship::*;
|
||||
|
use libpso::packet::messages::*;
|
||||
|
use crate::common::leveltable::CharacterLevelTable;
|
||||
|
use crate::common::serverstate::ClientId;
|
||||
|
use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms, ItemShops, TradeItem};
|
||||
|
use crate::ship::location::{ClientLocation, ClientLocationError};
|
||||
|
use crate::ship::drops::ItemDrop;
|
||||
|
use crate::ship::items::{ItemManager, ItemManagerError, ClientItemId, TriggerCreateItem, FloorItem, FloorType};
|
||||
|
use crate::ship::items::inventory::InventoryItem;
|
||||
|
use crate::entity::gateway::EntityGateway;
|
||||
|
use crate::entity::item;
|
||||
|
use libpso::utf8_to_utf16_array;
|
||||
|
use crate::ship::packet::builder;
|
||||
|
use crate::ship::shops::{ShopItem, ToolShopItem, ArmorShopItem};
|
||||
|
|
||||
|
#[derive(thiserror::Error, Debug)]
|
||||
|
#[error("")]
|
||||
|
pub enum TradeError {
|
||||
|
CouldNotFindTradePartner,
|
||||
|
ClientItemIdDidNotMatchItem(ClientItemId, [u8; 16]),
|
||||
|
InvalidStackAmount(ClientItemId, usize),
|
||||
|
NotInTradeMenu,
|
||||
|
}
|
||||
|
|
||||
|
|
||||
|
|
||||
|
pub async fn inner_items_to_trade<EG>(id: ClientId,
|
||||
|
items_to_trade: &ItemsToTrade,
|
||||
|
entity_gateway: &mut EG,
|
||||
|
client_location: &ClientLocation,
|
||||
|
clients: &mut Clients,
|
||||
|
item_manager: &mut ItemManager)
|
||||
|
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
|
||||
|
where
|
||||
|
EG: EntityGateway
|
||||
|
{
|
||||
|
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
|
let inventory = item_manager.get_character_inventory_mut(&client.character)?;
|
||||
|
let trade_partner = client_location.get_client_neighbors(id)?;
|
||||
|
let trade_partner = trade_partner
|
||||
|
.iter()
|
||||
|
.filter(|ac| {
|
||||
|
ac.local_client.id() == items_to_trade.trade_target
|
||||
|
})
|
||||
|
.nth(0)
|
||||
|
.ok_or(TradeError::CouldNotFindTradePartner)?;
|
||||
|
|
||||
|
|
||||
|
let item_blobs = items_to_trade.items.iter().take(items_to_trade.count as usize);
|
||||
|
let trade_items = item_blobs
|
||||
|
.map(|item| {
|
||||
|
// TOOD: meseta?
|
||||
|
let real_item = inventory.get_item_handle_by_id(ClientItemId(item.item_id))
|
||||
|
.ok_or(ItemManagerError::NoSuchItemId(ClientItemId(item.item_id)))?;
|
||||
|
let real_item = real_item
|
||||
|
.item()
|
||||
|
.ok_or(ItemManagerError::NoSuchItemId(ClientItemId(item.item_id)))?;
|
||||
|
let trade_item_bytes: [u8; 16] = item.item_data.iter()
|
||||
|
.chain(item.item_data2.iter())
|
||||
|
.cloned().collect::<Vec<u8>>()
|
||||
|
.try_into()
|
||||
|
.unwrap();
|
||||
|
if real_item.as_client_bytes() == trade_item_bytes {
|
||||
|
match real_item {
|
||||
|
InventoryItem::Individual(individual_inventory_item) => {
|
||||
|
Ok(TradeItem::Individual(individual_inventory_item.item_id))
|
||||
|
},
|
||||
|
InventoryItem::Stacked(stacked_inventory_item) => {
|
||||
|
let amount = trade_item_bytes[5] as usize;
|
||||
|
if amount > stacked_inventory_item.entity_ids.len() {
|
||||
|
Ok(TradeItem::Stacked(stacked_inventory_item.item_id, amount))
|
||||
|
}
|
||||
|
else {
|
||||
|
Err(TradeError::InvalidStackAmount(stacked_inventory_item.item_id, amount).into())
|
||||
|
}
|
||||
|
}
|
||||
|
}
|
||||
|
}
|
||||
|
else {
|
||||
|
Err(TradeError::ClientItemIdDidNotMatchItem(ClientItemId(item.item_id), trade_item_bytes).into())
|
||||
|
}
|
||||
|
})
|
||||
|
.collect::<Result<Vec<_>, anyhow::Error>>()?;
|
||||
|
|
||||
|
// TODO: check room in inventory for items
|
||||
|
client.trade = Some((trade_partner.client, trade_items));
|
||||
|
|
||||
|
Ok(Box::new(vec![(trade_partner.client, SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))].into_iter()))
|
||||
|
}
|
||||
|
|
||||
|
pub async fn items_to_trade<EG>(id: ClientId,
|
||||
|
items_to_trade_pkt: &ItemsToTrade,
|
||||
|
entity_gateway: &mut EG,
|
||||
|
client_location: &ClientLocation,
|
||||
|
clients: &mut Clients,
|
||||
|
item_manager: &mut ItemManager)
|
||||
|
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
|
||||
|
where
|
||||
|
EG: EntityGateway
|
||||
|
{
|
||||
|
let t = inner_items_to_trade(id, items_to_trade_pkt, entity_gateway, client_location, clients, item_manager).await;
|
||||
|
match t {
|
||||
|
Ok(p) => Ok(p),
|
||||
|
Err(err) => {
|
||||
|
let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
|
let trade_partner = client.trade.as_ref()
|
||||
|
.and_then(|(trade_partner, _)| {
|
||||
|
client_location.get_local_client(*trade_partner).ok()
|
||||
|
})
|
||||
|
.map(|trade_partner| {
|
||||
|
(trade_partner.client, SendShipPacket::CancelTrade(CancelTrade {}))
|
||||
|
});
|
||||
|
|
||||
|
log::warn!("error in trading: {:?}", err);
|
||||
|
Ok(Box::new(vec![(id, SendShipPacket::CancelTrade(CancelTrade {}))]
|
||||
|
.into_iter()
|
||||
|
.chain(trade_partner.into_iter())))
|
||||
|
}
|
||||
|
}
|
||||
|
}
|
||||
|
|
||||
|
// 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,
|
||||
|
entity_gateway: &mut EG,
|
||||
|
client_location: &ClientLocation,
|
||||
|
clients: &mut Clients,
|
||||
|
item_manager: &mut ItemManager)
|
||||
|
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error>
|
||||
|
where
|
||||
|
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))?;
|
||||
|
this_client.confirmed_trade = true;
|
||||
|
}
|
||||
|
|
||||
|
let both_confirmed = {
|
||||
|
let this_client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
|
let other_client = clients.get(&other_client_id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
|
this_client.confirmed_trade && other_client.confirmed_trade
|
||||
|
};
|
||||
|
|
||||
|
if both_confirmed {
|
||||
|
{
|
||||
|
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))?;
|
||||
|
this_client.trade = None;
|
||||
|
}
|
||||
|
{
|
||||
|
let other_client = clients.get_mut(&other_client_id).ok_or(ShipError::ClientNotFound(id))?;
|
||||
|
other_client.trade = None;
|
||||
|
}
|
||||
|
|
||||
|
Ok(Box::new(None.into_iter()))
|
||||
|
}
|
||||
|
else {
|
||||
|
Ok(Box::new(None.into_iter()))
|
||||
|
}
|
||||
|
}
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue