|
|
use std::convert::TryInto;
use elseware::common::serverstate::{ClientId, ServerState};
use elseware::entity::gateway::{EntityGateway, InMemoryGateway};
use elseware::entity::item;
use elseware::ship::ship::{ShipServerState, RecvShipPacket, SendShipPacket, ShipError};
use elseware::entity::item::{Meseta, ItemEntity};
use elseware::ship::packet::handler::trade::TradeError;
use libpso::packet::ship::*;
use libpso::packet::messages::*;
#[path = "common.rs"]
mod common;
use common::*;
async fn initialize_trade<EG: EntityGateway + Clone>(ship: &mut ShipServerState<EG>, client1: ClientId, client2: ClientId) {
ship.handle(client1, RecvShipPacket::DirectMessage(DirectMessage::new(client2.0 as u32 -1, GameMessage::TradeRequest(TradeRequest {
client: client1.0 as u8 -1,
target: 0,
trade: TradeRequestCommand::Initialize(TradeRequestInitializeCommand::Initialize, 0)
})))).await.unwrap();
ship.handle(client2, RecvShipPacket::DirectMessage(DirectMessage::new(client1.0 as u32 -1, GameMessage::TradeRequest(TradeRequest {
client: client2.0 as u8 -1,
target: 0,
trade: TradeRequestCommand::Initialize(TradeRequestInitializeCommand::Respond, 0)
})))).await.unwrap();
}
async fn confirm_trade<EG: EntityGateway + Clone>(ship: &mut ShipServerState<EG>, client1: ClientId, client2: ClientId) {
ship.handle(client1, RecvShipPacket::DirectMessage(DirectMessage::new(client2.0 as u32 -1, GameMessage::TradeRequest(TradeRequest {
client: client1.0 as u8 -1,
target: 0,
trade: TradeRequestCommand::Confirm
})))).await.unwrap();
ship.handle(client2, RecvShipPacket::DirectMessage(DirectMessage::new(client1.0 as u32 -1, GameMessage::TradeRequest(TradeRequest {
client: client2.0 as u8 -1,
target: 0,
trade: TradeRequestCommand::Confirm
})))).await.unwrap();
}
async fn finalconfirm_trade<EG: EntityGateway + Clone>(ship: &mut ShipServerState<EG>, client1: ClientId, client2: ClientId) {
ship.handle(client1, RecvShipPacket::DirectMessage(DirectMessage::new(client2.0 as u32 -1, GameMessage::TradeRequest(TradeRequest {
client: client1.0 as u8 -1,
target: 0,
trade: TradeRequestCommand::FinalConfirm
})))).await.unwrap();
ship.handle(client2, RecvShipPacket::DirectMessage(DirectMessage::new(client1.0 as u32 -1, GameMessage::TradeRequest(TradeRequest {
client: client2.0 as u8 -1,
target: 0,
trade: TradeRequestCommand::FinalConfirm
})))).await.unwrap();
}
#[derive(Default)]
struct TradeItemBuilder {
count: usize,
items: [TradeItem; 32],
}
impl TradeItemBuilder {
fn individual(mut self, item: &elseware::entity::item::InventoryItemEntity, item_id: u32) -> Self {
let idata = item.with_individual(|i| i.item.as_client_bytes()).unwrap();
self.items[self.count] = TradeItem {
item_data: idata[0..12].try_into().unwrap(),
item_id: item_id,
item_data2: idata[12..16].try_into().unwrap(),
};
self.count += 1;
self
}
fn stacked(mut self, item: &elseware::entity::item::InventoryItemEntity, item_id: u32, amount: u8) -> Self {
let idata = item
.with_stacked(|i| i[0].item.tool().unwrap().as_stacked_bytes(i.len()))
.map(|mut data| {
data[5] = amount;
data
})
.unwrap();
self.items[self.count] = TradeItem {
item_data: idata[0..12].try_into().unwrap(),
item_id: item_id,
item_data2: idata[12..16].try_into().unwrap(),
};
self.count += 1;
self
}
fn meseta(mut self, amount: usize) -> Self {
self.items[self.count] = TradeItem {
item_data: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
item_id: 0xFFFFFFFF,
item_data2: u32::to_le_bytes(amount as u32),
};
self.count += 1;
self
}
fn build(self) -> [TradeItem; 32] {
self.items
}
}
#[async_std::test]
async fn test_trade_one_individual_item() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let mut p1_inv = Vec::new();
p1_inv.push(entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap());
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10000)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 5);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {..}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 0);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
}
#[async_std::test]
async fn test_trade_player2_to_player1() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let mut p2_inv = Vec::new();
p2_inv.push(entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap());
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 0);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x210000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 0);
let titems = TradeItemBuilder::default()
.individual(&p2_items.items[0], 0x210000)
.build();
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 5);
assert!(matches!(ack[0], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {..}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
}
#[async_std::test]
async fn test_reverse_trade_ack_order() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let mut p1_inv = Vec::new();
p1_inv.push(entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap());
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(2), ClientId(1)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(2), ClientId(1)).await;
finalconfirm_trade(&mut ship, ClientId(2), ClientId(1)).await;
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 0);
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10000)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 5);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {..}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 0);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
}
#[async_std::test]
async fn test_trade_one_stacked_item() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 2)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[0], 0x10000, 2)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 5);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {..}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 0);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
}
#[async_std::test]
async fn test_trade_partial_stacked_item() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
assert_eq!(p1_items.items[0].with_stacked(|i| i.len()).unwrap(), 2);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[0], 0x10000, 1)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 5);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {..}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
assert_eq!(p1_items.items[0].with_stacked(|i| i.len()).unwrap(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
assert_eq!(p2_items.items[0].with_stacked(|i| i.len()).unwrap(), 1);
}
#[async_std::test]
async fn test_trade_individual_both() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_inv = vec![
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Saber,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap()];
let p2_inv = vec![
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap()];
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10000)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let titems = TradeItemBuilder::default()
.individual(&p2_items.items[0], 0x210000)
.build();
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 8);
assert!(matches!(ack[0], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 1,
item_id: 0x210000,
..
}),
..
}))));
assert!(matches!(ack[1], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 0,
item_id: 0x10000,
..
}),
..
}))));
assert!(matches!(ack[2], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[5], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[6], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[7], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
assert!(matches!(p1_items.items[0].with_individual(|i| i.clone()).unwrap(), item::ItemEntity{item: item::ItemDetail::Weapon(item::weapon::Weapon {weapon: item::weapon::WeaponType::Handgun, ..}), ..}));
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
assert!(matches!(p2_items.items[0].with_individual(|i| i.clone()).unwrap(), item::ItemEntity{item: item::ItemDetail::Weapon(item::weapon::Weapon {weapon: item::weapon::WeaponType::Saber, ..}), ..}));
}
#[async_std::test]
async fn test_trade_stacked_both() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p2_stack = futures::future::join_all((0..3).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monofluid,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 2)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210000, 3)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[0], 0x10000, 2)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let titems = TradeItemBuilder::default()
.stacked(&p2_items.items[0], 0x210000, 3)
.build();
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 8);
assert!(matches!(ack[0], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 1,
item_id: 0x210000,
..
}),
..
}))));
assert!(matches!(ack[1], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 0,
item_id: 0x10000,
..
}),
..
}))));
assert!(matches!(ack[2], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[5], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[6], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[7], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
assert_eq!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 3);
assert!(matches!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monofluid, ..}), ..}));
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
assert_eq!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 2);
assert!(matches!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monomate, ..}), ..}));
}
#[async_std::test]
async fn test_trade_partial_stack_both() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p2_stack = futures::future::join_all((0..3).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monofluid,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210000, 2)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[0], 0x10000, 1)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let titems = TradeItemBuilder::default()
.stacked(&p2_items.items[0], 0x210000, 2)
.build();
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 8);
assert!(matches!(ack[0], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 1,
item_id: 0x210000,
amount: 2,
..
}),
..
}))));
assert!(matches!(ack[1], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 0,
item_id: 0x10000,
amount: 1,
..
}),
..
}))));
assert!(matches!(ack[2], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[5], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[6], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[7], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 2);
assert_eq!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 1);
assert_eq!(p1_items.items[1].with_stacked(|i| i.clone()).unwrap().len(), 2);
assert!(matches!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monomate, ..}), ..}));
assert!(matches!(p1_items.items[1].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monofluid, ..}), ..}));
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 2);
assert_eq!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 1);
assert_eq!(p2_items.items[1].with_stacked(|i| i.clone()).unwrap().len(), 1);
assert!(matches!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monofluid, ..}), ..}));
assert!(matches!(p2_items.items[1].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monomate, ..}), ..}));
}
#[async_std::test]
async fn test_trade_same_stacked_item_to_eachother() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack = futures::future::join_all((0..3).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p2_stack = futures::future::join_all((0..4).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210000, 3)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[0], 0x10000, 1)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let titems = TradeItemBuilder::default()
.stacked(&p2_items.items[0], 0x210000, 3)
.build();
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 8);
assert!(matches!(ack[0], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 1,
item_id: 0x210000,
amount: 3,
..
}),
..
}))));
assert!(matches!(ack[1], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 0,
item_id: 0x10000,
amount: 1,
..
}),
..
}))));
assert!(matches!(ack[2], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[5], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[6], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[7], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
assert_eq!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 5);
assert!(matches!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monomate, ..}), ..}));
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
assert_eq!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 2);
assert!(matches!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monomate, ..}), ..}));
}
#[async_std::test]
async fn test_trade_stacked_when_already_have_partial_stack() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack = futures::future::join_all((0..3).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p2_stack = futures::future::join_all((0..3).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 2)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[0], 0x10000, 2)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 5);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 0,
item_id: 0x10000,
amount: 2,
..
}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_id: 0x810001,
item_data: [3, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0],
..
}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_id: 0x810001,
item_data: [3, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0],
..
}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
assert_eq!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 1);
assert!(matches!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monomate, ..}), ..}));
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
assert_eq!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 5);
assert!(matches!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monomate, ..}), ..}));
}
#[async_std::test]
async fn test_trade_individual_for_stacked() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_inv = vec![
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Saber,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap()];
let p2_stack = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210000, 2)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10000)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let titems = TradeItemBuilder::default()
.stacked(&p2_items.items[0], 0x210000, 2)
.build();
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 8);
assert!(matches!(ack[0], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 1,
item_id: 0x210000,
..
}),
..
}))));
assert!(matches!(ack[1], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 0,
item_id: 0x10000,
..
}),
..
}))));
assert!(matches!(ack[2], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_data: [3, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0],
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[5], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_data: [3, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0],
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[6], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[7], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
assert_eq!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 2);
assert!(matches!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monomate, ..}), ..}));
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
assert!(matches!(p2_items.items[0].with_individual(|i| i.clone()).unwrap(), item::ItemEntity{item: item::ItemDetail::Weapon(item::weapon::Weapon {weapon: item::weapon::WeaponType::Saber, ..}), ..}));
}
#[async_std::test]
async fn test_trade_multiple_individual() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_inv = vec![
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Saber,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Buster,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
];
let p2_inv = vec![
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Autogun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
];
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 2);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 2);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10001, 1)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210000, 1)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210001, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10000)
.individual(&p1_items.items[1], 0x10001)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 2,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let titems = TradeItemBuilder::default()
.individual(&p2_items.items[0], 0x210000)
.individual(&p2_items.items[1], 0x210001)
.build();
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 2,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 14);
assert!(matches!(ack[0], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 1,
item_id: 0x210000,
..
}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 1,
item_id: 0x210001,
..
}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 0,
item_id: 0x10000,
..
}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 0,
item_id: 0x10001,
..
}),
..
}))));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
item_id: 0x810004,
..
}),
..
}))));
assert!(matches!(ack[5], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_data: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
item_id: 0x810004,
..
}),
..
}))));
assert!(matches!(ack[6], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_data: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
item_id: 0x810003,
..
}),
..
}))));
assert!(matches!(ack[7], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_data: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], // saber
item_id: 0x810003,
..
}),
..
}))));
assert!(matches!(ack[8], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[9], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_data: [0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[10], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_data: [0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[11], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_data: [0, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], // handgun
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[12], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[13], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 2);
assert!(matches!(p1_items.items[0].with_individual(|i| i.clone()).unwrap(), item::ItemEntity{item: item::ItemDetail::Weapon(item::weapon::Weapon {weapon: item::weapon::WeaponType::Handgun, ..}), ..}));
assert!(matches!(p1_items.items[1].with_individual(|i| i.clone()).unwrap(), item::ItemEntity{item: item::ItemDetail::Weapon(item::weapon::Weapon {weapon: item::weapon::WeaponType::Autogun, ..}), ..}));
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 2);
assert!(matches!(p2_items.items[0].with_individual(|i| i.clone()).unwrap(), item::ItemEntity{item: item::ItemDetail::Weapon(item::weapon::Weapon {weapon: item::weapon::WeaponType::Saber, ..}), ..}));
assert!(matches!(p2_items.items[1].with_individual(|i| i.clone()).unwrap(), item::ItemEntity{item: item::ItemDetail::Weapon(item::weapon::Weapon {weapon: item::weapon::WeaponType::Buster, ..}), ..}));
}
#[async_std::test]
async fn test_trade_multiple_stacked() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack1 = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p1_stack2 = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Dimate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p2_stack1 = futures::future::join_all((0..3).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monofluid,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p2_stack2 = futures::future::join_all((0..3).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Difluid,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack1, p1_stack2])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack1, p2_stack2])).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 2);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 2);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 2)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10001, 2)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210000, 3)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210001, 3)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[0], 0x10000, 2)
.stacked(&p1_items.items[1], 0x10001, 2)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 2,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let titems = TradeItemBuilder::default()
.stacked(&p2_items.items[0], 0x210000, 3)
.stacked(&p2_items.items[1], 0x210001, 3)
.build();
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 2,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 14);
assert!(matches!(ack[0], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 1,
item_id: 0x210000,
..
}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 1,
item_id: 0x210001,
..
}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 0,
item_id: 0x10000,
..
}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {
client: 0,
item_id: 0x10001,
..
}),
..
}))));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_id: 0x810004,
..
}),
..
}))));
assert!(matches!(ack[5], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_id: 0x810004,
..
}),
..
}))));
assert!(matches!(ack[6], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_id: 0x810003,
..
}),
..
}))));
assert!(matches!(ack[7], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 1,
item_id: 0x810003,
..
}),
..
}))));
assert!(matches!(ack[8], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[9], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_id: 0x810002,
..
}),
..
}))));
assert!(matches!(ack[10], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[11], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {
client: 0,
item_id: 0x810001,
..
}),
..
}))));
assert!(matches!(ack[12], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[13], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 2);
assert_eq!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 3);
assert!(matches!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monofluid, ..}), ..}));
assert_eq!(p1_items.items[1].with_stacked(|i| i.clone()).unwrap().len(), 3);
assert!(matches!(p1_items.items[1].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Difluid, ..}), ..}));
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 2);
assert_eq!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 2);
assert!(matches!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monomate, ..}), ..}));
assert_eq!(p2_items.items[1].with_stacked(|i| i.clone()).unwrap().len(), 2);
assert!(matches!(p2_items.items[1].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Dimate, ..}), ..}));
}
#[async_std::test]
async fn test_trade_not_enough_inventory_space_individual() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_inv = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}
).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p2_inv = futures::future::join_all((0..30).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}
).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 2);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 30);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10000)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack,
vec![
(ClientId(1), SendShipPacket::CancelTrade(CancelTrade {})),
(ClientId(2), SendShipPacket::CancelTrade(CancelTrade {})),
]);
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 2);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 30);
}
#[async_std::test]
async fn test_trade_not_enough_inventory_space_stacked() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p2_inv = futures::future::join_all((0..30).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}
).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 30);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 2)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[0], 0x10000, 2)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack,
vec![
(ClientId(1), SendShipPacket::CancelTrade(CancelTrade {})),
(ClientId(2), SendShipPacket::CancelTrade(CancelTrade {})),
]);
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 30);
}
#[async_std::test]
async fn test_trade_stack_too_big() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack = futures::future::join_all((0..8).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p2_stack = futures::future::join_all((0..7).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(vec![p2_stack])).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
assert_eq!(p1_items.items[0].with_stacked(|i| i.len()).unwrap(), 8);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
assert_eq!(p2_items.items[0].with_stacked(|i| i.len()).unwrap(), 7);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 4)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[0], 0x10000, 4)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack,
vec![
(ClientId(1), SendShipPacket::CancelTrade(CancelTrade {})),
(ClientId(2), SendShipPacket::CancelTrade(CancelTrade {})),
]);
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
assert_eq!(p1_items.items[0].with_stacked(|i| i.len()).unwrap(), 8);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
assert_eq!(p2_items.items[0].with_stacked(|i| i.len()).unwrap(), 7);
}
#[async_std::test]
async fn test_trade_meseta() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
entity_gateway.set_character_meseta(&char1.id, Meseta(2323)).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0xFFFFFF01, 23)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.meseta(23)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 5);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {..}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap();
assert_eq!(c1_meseta, Meseta(2300));
let c2_meseta = entity_gateway.get_character_meseta(&char2.id).await.unwrap();
assert_eq!(c2_meseta, Meseta(23));
}
#[async_std::test]
async fn test_trade_too_much_meseta() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
entity_gateway.set_character_meseta(&char1.id, Meseta(4000)).await.unwrap();
entity_gateway.set_character_meseta(&char2.id, Meseta(999000)).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0xFFFFFF01, 2000)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.meseta(2000)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..))));
let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap();
assert_eq!(c1_meseta, Meseta(4000));
let c2_meseta = entity_gateway.get_character_meseta(&char2.id).await.unwrap();
assert_eq!(c2_meseta, Meseta(999000));
}
#[async_std::test]
async fn test_trade_invalid_amount_of_meseta() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
entity_gateway.set_character_meseta(&char1.id, Meseta(4000)).await.unwrap();
entity_gateway.set_character_meseta(&char2.id, Meseta(999000)).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0xFFFFFF01, 5000)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.meseta(5000)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..))));
let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap();
assert_eq!(c1_meseta, Meseta(4000));
let c2_meseta = entity_gateway.get_character_meseta(&char2.id).await.unwrap();
assert_eq!(c2_meseta, Meseta(999000));
}
#[async_std::test]
async fn test_trade_meseta_request_and_items_dont_match() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
entity_gateway.set_character_meseta(&char1.id, Meseta(4000)).await.unwrap();
entity_gateway.set_character_meseta(&char2.id, Meseta(999000)).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0xFFFFFF01, 50)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.meseta(23)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..))));
let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap();
assert_eq!(c1_meseta, Meseta(4000));
let c2_meseta = entity_gateway.get_character_meseta(&char2.id).await.unwrap();
assert_eq!(c2_meseta, Meseta(999000));
}
#[async_std::test]
async fn test_player_declined_trade() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
let ack = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::Cancel
})))).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..))));
}
#[async_std::test]
async fn test_back_out_of_trade_last_minute() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let mut p1_inv = Vec::new();
p1_inv.push(entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap());
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let ack = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::Cancel
})))).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..))));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
}
#[async_std::test]
async fn test_valid_trade_when_both_inventories_are_full() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_inv = futures::future::join_all((0..30).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Saber,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}
).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p2_inv = futures::future::join_all((0..30).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}
).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 30);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 30);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10001, 1)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210000, 1)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210001, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10000)
.individual(&p1_items.items[1], 0x10001)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 2,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let titems = TradeItemBuilder::default()
.individual(&p2_items.items[0], 0x210000)
.individual(&p2_items.items[1], 0x210001)
.build();
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 2,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 14);
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 30);
assert_eq!(p1_items.items.iter().filter(|i| matches!(i.individual().unwrap().item, item::ItemDetail::Weapon(item::weapon::Weapon { weapon: item::weapon::WeaponType::Saber, ..}, ..))).count(), 28);
assert_eq!(p1_items.items.iter().filter(|i| matches!(i.individual().unwrap().item, item::ItemDetail::Weapon(item::weapon::Weapon { weapon: item::weapon::WeaponType::Handgun, ..}, ..))).count(), 2);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 30);
assert_eq!(p2_items.items.iter().filter(|i| matches!(i.individual().unwrap().item, item::ItemDetail::Weapon(item::weapon::Weapon { weapon: item::weapon::WeaponType::Saber, ..}, ..))).count(), 2);
assert_eq!(p2_items.items.iter().filter(|i| matches!(i.individual().unwrap().item, item::ItemDetail::Weapon(item::weapon::Weapon { weapon: item::weapon::WeaponType::Handgun, ..}, ..))).count(), 28);
}
#[async_std::test]
async fn test_invalid_trade_when_both_inventories_are_full() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_inv = futures::future::join_all((0..30).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Saber,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}
).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p2_inv = futures::future::join_all((0..30).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}
).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(p2_inv)).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 30);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 30);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10001, 1)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10002, 1)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210000, 1)
})))).await.unwrap();
ship.handle(ClientId(2), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::AddItem(0x210001, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10000)
.individual(&p1_items.items[1], 0x10001)
.individual(&p1_items.items[1], 0x10002)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 3,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let titems = TradeItemBuilder::default()
.individual(&p2_items.items[0], 0x210000)
.individual(&p2_items.items[1], 0x210001)
.build();
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 2,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack,
vec![
(ClientId(1), SendShipPacket::CancelTrade(CancelTrade {})),
(ClientId(2), SendShipPacket::CancelTrade(CancelTrade {})),
]);
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 30);
assert_eq!(p1_items.items.iter().filter(|i| matches!(i.individual().unwrap().item, item::ItemDetail::Weapon(item::weapon::Weapon { weapon: item::weapon::WeaponType::Saber, ..}, ..))).count(), 30);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 30);
assert_eq!(p2_items.items.iter().filter(|i| matches!(i.individual().unwrap().item, item::ItemDetail::Weapon(item::weapon::Weapon { weapon: item::weapon::WeaponType::Handgun, ..}, ..))).count(), 30);
}
#[async_std::test]
async fn test_client_tries_to_start_two_trades() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let (_user2, _char3) = new_user_character(&mut entity_gateway, "a3", "a", 1).await;
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
log_in_char(&mut ship, ClientId(3), "a3", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
join_lobby(&mut ship, ClientId(3)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
join_room(&mut ship, ClientId(3), 0).await;
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
let ack = ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 0,
target: 0,
trade: TradeRequestCommand::Initialize(TradeRequestInitializeCommand::Initialize, 0)
})))).await.err().unwrap();
assert!(matches!(ack.downcast::<ShipError>().unwrap(), ShipError::TradeError(TradeError::ClientAlreadyInTrade)));
}
#[async_std::test]
async fn test_client_tries_trading_with_client_already_trading() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let (_user2, _char3) = new_user_character(&mut entity_gateway, "a3", "a", 1).await;
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
log_in_char(&mut ship, ClientId(3), "a3", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
join_lobby(&mut ship, ClientId(3)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
join_room(&mut ship, ClientId(3), 0).await;
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
let ack = ship.handle(ClientId(3), RecvShipPacket::DirectMessage(DirectMessage::new(0, GameMessage::TradeRequest(TradeRequest {
client: 2,
target: 0,
trade: TradeRequestCommand::Initialize(TradeRequestInitializeCommand::Initialize, 0)
})))).await.err().unwrap();
assert!(matches!(ack.downcast::<ShipError>().unwrap(), ShipError::TradeError(TradeError::OtherAlreadyInTrade)));
let ack = ship.handle(ClientId(3), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 2,
target: 0,
trade: TradeRequestCommand::Initialize(TradeRequestInitializeCommand::Initialize, 1)
})))).await.err().unwrap();
assert!(matches!(ack.downcast::<ShipError>().unwrap(), ShipError::TradeError(TradeError::OtherAlreadyInTrade)));
}
#[async_std::test]
async fn test_add_then_remove_individual_item() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let mut p1_inv = Vec::new();
for _ in 0..2 {
p1_inv.push(entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap());
}
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 2);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10001, 1)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::RemoveItem(0x10000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[1], 0x10001)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 5);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {..}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
}
#[async_std::test]
async fn test_add_then_remove_stacked_item() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack1 = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p1_stack2 = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monofluid,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack1, p1_stack2])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 2);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 2)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10001, 2)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::RemoveItem(0x10000, 2)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[1], 0x10001, 2)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 5);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {..}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
assert!(matches!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monomate, ..}), ..}));
assert_eq!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 2);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 1);
assert_eq!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 2);
assert!(matches!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monofluid, ..}), ..}));
}
#[async_std::test]
async fn test_add_then_remove_partial_stack() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack1 = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
let p1_stack2 = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monofluid,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack1, p1_stack2])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 2);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 2)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10001, 2)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::RemoveItem(0x10000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[0], 0x10000, 1)
.stacked(&p1_items.items[1], 0x10001, 2)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 2,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 8);
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
assert_eq!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 1);
assert!(matches!(p1_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monomate, ..}), ..}));
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 2);
assert_eq!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap().len(), 1);
assert_eq!(p2_items.items[1].with_stacked(|i| i.clone()).unwrap().len(), 2);
assert!(matches!(p2_items.items[0].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monomate, ..}), ..}));
assert!(matches!(p2_items.items[1].with_stacked(|i| i.clone()).unwrap()[0], item::ItemEntity{item: item::ItemDetail::Tool(item::tool::Tool {tool: item::tool::ToolType::Monofluid, ..}), ..}));
}
#[async_std::test]
async fn test_add_then_remove_meseta() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
entity_gateway.set_character_meseta(&char1.id, Meseta(2323)).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0xFFFFFF01, 23)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::RemoveItem(0xFFFFFF01, 5)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.meseta(18)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 5);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {..}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let c1_meseta = entity_gateway.get_character_meseta(&char1.id).await.unwrap();
assert_eq!(c1_meseta, Meseta(2305));
let c2_meseta = entity_gateway.get_character_meseta(&char2.id).await.unwrap();
assert_eq!(c2_meseta, Meseta(18));
}
#[async_std::test]
async fn test_items_to_trade_data_does_not_match() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let mut p1_inv = Vec::new();
p1_inv.push(entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap());
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let new_item = item::InventoryItemEntity::Individual(
ItemEntity {
id: p1_items.items[0].with_individual(|i| i.id).unwrap(),
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 2,
special: None,
attrs: [None, None, None],
tekked: true,
}
)});
let titems = TradeItemBuilder::default()
.individual(&new_item, 0x10000)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..))));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
}
#[async_std::test]
async fn test_items_to_trade_id_does_not_match() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let mut p1_inv = Vec::new();
p1_inv.push(entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap());
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10001)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..))));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
}
#[async_std::test]
async fn test_stack_is_same_amount_in_request_and_items_to_trade() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 2)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[0], 0x10000, 1)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..))));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
}
#[async_std::test]
async fn test_stack_is_same_amount_in_request_and_items_to_trade2() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_stack = futures::future::join_all((0..2).map(|_| {
let mut entity_gateway = entity_gateway.clone();
async move {
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Tool(
item::tool::Tool {
tool: item::tool::ToolType::Monomate,
}
)
}).await
}}))
.await
.into_iter()
.collect::<Result<Vec<ItemEntity>,_>>()
.unwrap();
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(vec![p1_stack])).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.stacked(&p1_items.items[0], 0x10000, 2)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..))));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
}
#[async_std::test]
async fn test_items_to_trade_count_less_than() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_inv = vec![
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Saber,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Brand,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Buster,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
];
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 3);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10001, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10000)
.individual(&p1_items.items[1], 0x10001)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..))));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 3);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
}
#[async_std::test]
async fn test_items_to_trade_count_greater_than() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
entity_gateway.set_character_meseta(&char1.id, Meseta(23)).await.unwrap();
let p1_inv = vec![
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Saber,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Brand,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Buster,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
];
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 3);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10001, 1)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0xFFFFFF01, 5)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10000)
.individual(&p1_items.items[1], 0x10001)
.meseta(5)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 4,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..))));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 3);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
}
#[async_std::test]
async fn test_items_to_trade_count_mismatch_with_meseta() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let p1_inv = vec![
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Saber,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Brand,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Buster,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap(),
];
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 3);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10001, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10000)
.individual(&p1_items.items[1], 0x10001)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 3,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::CancelTrade(..))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::CancelTrade(..))));
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 3);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
}
#[async_std::test]
async fn test_dropping_item_after_trade() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await;
let (_user2, char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await;
let mut p1_inv = Vec::new();
p1_inv.push(entity_gateway.create_item(
item::NewItemEntity {
item: item::ItemDetail::Weapon(
item::weapon::Weapon {
weapon: item::weapon::WeaponType::Handgun,
grind: 0,
special: None,
attrs: [None, None, None],
tekked: true,
}
),
}).await.unwrap());
entity_gateway.set_character_inventory(&char1.id, &item::InventoryEntity::new(p1_inv)).await.unwrap();
entity_gateway.set_character_inventory(&char2.id, &item::InventoryEntity::new(Vec::<item::InventoryItemEntity>::new())).await.unwrap();
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
log_in_char(&mut ship, ClientId(2), "a2", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
join_lobby(&mut ship, ClientId(2)).await;
create_room(&mut ship, ClientId(1), "room", "").await;
join_room(&mut ship, ClientId(2), 0).await;
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 1);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
initialize_trade(&mut ship, ClientId(1), ClientId(2)).await;
ship.handle(ClientId(1), RecvShipPacket::DirectMessage(DirectMessage::new(1, GameMessage::TradeRequest(TradeRequest {
client: 1,
target: 0,
trade: TradeRequestCommand::AddItem(0x10000, 1)
})))).await.unwrap();
confirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
finalconfirm_trade(&mut ship, ClientId(1), ClientId(2)).await;
let titems = TradeItemBuilder::default()
.individual(&p1_items.items[0], 0x10000)
.build();
let ack = ship.handle(ClientId(1), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 1,
unknown2: 0,
count: 1,
items: titems,
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::ItemsToTrade(ItemsToTrade {
trade_target: 0,
unknown2: 0,
count: 0,
items: Default::default(),
})).await.unwrap();
assert_eq!(ack.len(), 2);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::AcknowledgeTrade(AcknowledgeTrade {}))));
let ack = ship.handle(ClientId(1), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 0);
let ack = ship.handle(ClientId(2), RecvShipPacket::TradeConfirmed(TradeConfirmed {
})).await.unwrap();
assert_eq!(ack.len(), 5);
assert!(matches!(ack[0], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::PlayerNoLongerHasItem(PlayerNoLongerHasItem {..}),
..
}))));
assert!(matches!(ack[1], (ClientId(1), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[2], (ClientId(2), SendShipPacket::Message(Message {
msg: GameMessage::CreateItem(CreateItem {..}),
..
}))));
assert!(matches!(ack[3], (ClientId(2), SendShipPacket::TradeSuccessful {..})));
assert!(matches!(ack[4], (ClientId(1), SendShipPacket::TradeSuccessful {..})));
let _ack = ship.handle(ClientId(2), RecvShipPacket::Message(Message::new(GameMessage::PlayerDropItem(PlayerDropItem {
client: 0,
target: 0,
unknown1: 0,
map_area: 0,
item_id: 0x810001,
x: 0.0,
y: 0.0,
z: 0.0,
})))).await.unwrap();
let p1_items = entity_gateway.get_character_inventory(&char1.id).await.unwrap();
assert_eq!(p1_items.items.len(), 0);
let p2_items = entity_gateway.get_character_inventory(&char2.id).await.unwrap();
assert_eq!(p2_items.items.len(), 0);
}
|